diff --git a/.gradle/8.0/executionHistory/executionHistory.bin b/.gradle/8.0/executionHistory/executionHistory.bin index d3d6cae..fd72aef 100644 Binary files a/.gradle/8.0/executionHistory/executionHistory.bin and b/.gradle/8.0/executionHistory/executionHistory.bin differ diff --git a/.gradle/8.0/executionHistory/executionHistory.lock b/.gradle/8.0/executionHistory/executionHistory.lock index ba74460..b6eecc8 100644 Binary files a/.gradle/8.0/executionHistory/executionHistory.lock and b/.gradle/8.0/executionHistory/executionHistory.lock differ diff --git a/.gradle/8.0/fileHashes/fileHashes.bin b/.gradle/8.0/fileHashes/fileHashes.bin index 9c1b25f..e611bd7 100644 Binary files a/.gradle/8.0/fileHashes/fileHashes.bin and b/.gradle/8.0/fileHashes/fileHashes.bin differ diff --git a/.gradle/8.0/fileHashes/fileHashes.lock b/.gradle/8.0/fileHashes/fileHashes.lock index 0b49904..9c61704 100644 Binary files a/.gradle/8.0/fileHashes/fileHashes.lock and b/.gradle/8.0/fileHashes/fileHashes.lock differ diff --git a/.gradle/8.0/fileHashes/resourceHashesCache.bin b/.gradle/8.0/fileHashes/resourceHashesCache.bin index fa7dd54..173d71f 100644 Binary files a/.gradle/8.0/fileHashes/resourceHashesCache.bin and b/.gradle/8.0/fileHashes/resourceHashesCache.bin differ diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 879cbbd..2d161e5 100644 Binary files a/.gradle/buildOutputCleanup/buildOutputCleanup.lock and b/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ diff --git a/UnpackDebugJar.sh b/UnpackDebugJar.sh new file mode 100644 index 0000000..0b77e96 --- /dev/null +++ b/UnpackDebugJar.sh @@ -0,0 +1,2 @@ +rm lwjgl-rundir/eaglercraft.jar +cp ./build/libs/eaglercraft.jar ./lwjgl-rundir \ No newline at end of file diff --git a/build.gradle b/build.gradle index afa9345..a1aba14 100644 --- a/build.gradle +++ b/build.gradle @@ -36,6 +36,6 @@ distributions { } application { - mainClass = 'net.minecraft.client.main.Main' + mainClass = 'net.lax1dude.eaglercraft.MinecraftMain' applicationDefaultJvmArgs = ['-Djava.library.path=lwjgl-rundir'] } diff --git a/build/classes/java/main/Start.class b/build/classes/java/main/Start.class deleted file mode 100644 index 2ae02ef..0000000 Binary files a/build/classes/java/main/Start.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/client/ClientBrandRetriever.class b/build/classes/java/main/net/minecraft/client/ClientBrandRetriever.class deleted file mode 100644 index e6c0396..0000000 Binary files a/build/classes/java/main/net/minecraft/client/ClientBrandRetriever.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/client/main/Main.class b/build/classes/java/main/net/minecraft/client/main/Main.class deleted file mode 100644 index 0c47ba7..0000000 Binary files a/build/classes/java/main/net/minecraft/client/main/Main.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/server/MinecraftServer.class b/build/classes/java/main/net/minecraft/server/MinecraftServer.class deleted file mode 100644 index b248156..0000000 Binary files a/build/classes/java/main/net/minecraft/server/MinecraftServer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/AABBLocalPool.class b/build/classes/java/main/net/minecraft/src/AABBLocalPool.class deleted file mode 100644 index d1aa86f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/AABBLocalPool.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/AABBPool.class b/build/classes/java/main/net/minecraft/src/AABBPool.class deleted file mode 100644 index 8b4cc96..0000000 Binary files a/build/classes/java/main/net/minecraft/src/AABBPool.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/AbstractClientPlayer.class b/build/classes/java/main/net/minecraft/src/AbstractClientPlayer.class deleted file mode 100644 index 7dbebc5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/AbstractClientPlayer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/AbstractResourcePack.class b/build/classes/java/main/net/minecraft/src/AbstractResourcePack.class deleted file mode 100644 index 6614e25..0000000 Binary files a/build/classes/java/main/net/minecraft/src/AbstractResourcePack.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/AbstractTexture.class b/build/classes/java/main/net/minecraft/src/AbstractTexture.class deleted file mode 100644 index ad5288e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/AbstractTexture.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Achievement.class b/build/classes/java/main/net/minecraft/src/Achievement.class deleted file mode 100644 index e6ddbd5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Achievement.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/AchievementList.class b/build/classes/java/main/net/minecraft/src/AchievementList.class deleted file mode 100644 index 3926369..0000000 Binary files a/build/classes/java/main/net/minecraft/src/AchievementList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/AchievementMap.class b/build/classes/java/main/net/minecraft/src/AchievementMap.class deleted file mode 100644 index 36f0d6c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/AchievementMap.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ActiveRenderInfo.class b/build/classes/java/main/net/minecraft/src/ActiveRenderInfo.class deleted file mode 100644 index 4da485a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ActiveRenderInfo.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/AnimalChest.class b/build/classes/java/main/net/minecraft/src/AnimalChest.class deleted file mode 100644 index 26ea84a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/AnimalChest.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/AnimationFrame.class b/build/classes/java/main/net/minecraft/src/AnimationFrame.class deleted file mode 100644 index f2e64bf..0000000 Binary files a/build/classes/java/main/net/minecraft/src/AnimationFrame.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/AnimationMetadataSection.class b/build/classes/java/main/net/minecraft/src/AnimationMetadataSection.class deleted file mode 100644 index 709c949..0000000 Binary files a/build/classes/java/main/net/minecraft/src/AnimationMetadataSection.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/AnimationMetadataSectionSerializer.class b/build/classes/java/main/net/minecraft/src/AnimationMetadataSectionSerializer.class deleted file mode 100644 index 6e664ad..0000000 Binary files a/build/classes/java/main/net/minecraft/src/AnimationMetadataSectionSerializer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/AnvilChunkLoader.class b/build/classes/java/main/net/minecraft/src/AnvilChunkLoader.class deleted file mode 100644 index 7c80730..0000000 Binary files a/build/classes/java/main/net/minecraft/src/AnvilChunkLoader.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/AnvilChunkLoaderPending.class b/build/classes/java/main/net/minecraft/src/AnvilChunkLoaderPending.class deleted file mode 100644 index a707cc0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/AnvilChunkLoaderPending.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/AnvilConverterData.class b/build/classes/java/main/net/minecraft/src/AnvilConverterData.class deleted file mode 100644 index 0e4ef7b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/AnvilConverterData.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/AnvilConverterException.class b/build/classes/java/main/net/minecraft/src/AnvilConverterException.class deleted file mode 100644 index b5c04b5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/AnvilConverterException.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/AnvilSaveConverter.class b/build/classes/java/main/net/minecraft/src/AnvilSaveConverter.class deleted file mode 100644 index fd092f6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/AnvilSaveConverter.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/AnvilSaveConverterFileFilter.class b/build/classes/java/main/net/minecraft/src/AnvilSaveConverterFileFilter.class deleted file mode 100644 index 66a516a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/AnvilSaveConverterFileFilter.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/AnvilSaveHandler.class b/build/classes/java/main/net/minecraft/src/AnvilSaveHandler.class deleted file mode 100644 index 6ff6715..0000000 Binary files a/build/classes/java/main/net/minecraft/src/AnvilSaveHandler.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Attribute.class b/build/classes/java/main/net/minecraft/src/Attribute.class deleted file mode 100644 index 4446185..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Attribute.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/AttributeInstance.class b/build/classes/java/main/net/minecraft/src/AttributeInstance.class deleted file mode 100644 index 47a9b96..0000000 Binary files a/build/classes/java/main/net/minecraft/src/AttributeInstance.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/AttributeModifier.class b/build/classes/java/main/net/minecraft/src/AttributeModifier.class deleted file mode 100644 index cc79237..0000000 Binary files a/build/classes/java/main/net/minecraft/src/AttributeModifier.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/AxisAlignedBB.class b/build/classes/java/main/net/minecraft/src/AxisAlignedBB.class deleted file mode 100644 index ac7843c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/AxisAlignedBB.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Backup.class b/build/classes/java/main/net/minecraft/src/Backup.class deleted file mode 100644 index eccac6f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Backup.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BackupList.class b/build/classes/java/main/net/minecraft/src/BackupList.class deleted file mode 100644 index 9cff6fd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BackupList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BanEntry.class b/build/classes/java/main/net/minecraft/src/BanEntry.class deleted file mode 100644 index 9c9c4d7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BanEntry.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BanList.class b/build/classes/java/main/net/minecraft/src/BanList.class deleted file mode 100644 index 442e32b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BanList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BaseAttribute.class b/build/classes/java/main/net/minecraft/src/BaseAttribute.class deleted file mode 100644 index 2121521..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BaseAttribute.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BaseAttributeMap.class b/build/classes/java/main/net/minecraft/src/BaseAttributeMap.class deleted file mode 100644 index 327fb59..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BaseAttributeMap.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BaseMetadataSectionSerializer.class b/build/classes/java/main/net/minecraft/src/BaseMetadataSectionSerializer.class deleted file mode 100644 index 5695525..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BaseMetadataSectionSerializer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BehaviorDefaultDispenseItem.class b/build/classes/java/main/net/minecraft/src/BehaviorDefaultDispenseItem.class deleted file mode 100644 index 7a8d07d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BehaviorDefaultDispenseItem.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BehaviorDispenseArmor.class b/build/classes/java/main/net/minecraft/src/BehaviorDispenseArmor.class deleted file mode 100644 index 4695a07..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BehaviorDispenseArmor.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BehaviorDispenseItemProvider.class b/build/classes/java/main/net/minecraft/src/BehaviorDispenseItemProvider.class deleted file mode 100644 index b3ecd9e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BehaviorDispenseItemProvider.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BehaviorDispenseMinecart.class b/build/classes/java/main/net/minecraft/src/BehaviorDispenseMinecart.class deleted file mode 100644 index cc43090..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BehaviorDispenseMinecart.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BehaviorProjectileDispense.class b/build/classes/java/main/net/minecraft/src/BehaviorProjectileDispense.class deleted file mode 100644 index f127a94..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BehaviorProjectileDispense.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BiomeCache.class b/build/classes/java/main/net/minecraft/src/BiomeCache.class deleted file mode 100644 index 01ceb98..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BiomeCache.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BiomeCacheBlock.class b/build/classes/java/main/net/minecraft/src/BiomeCacheBlock.class deleted file mode 100644 index b8d398f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BiomeCacheBlock.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BiomeDecorator.class b/build/classes/java/main/net/minecraft/src/BiomeDecorator.class deleted file mode 100644 index ecc775d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BiomeDecorator.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BiomeEndDecorator.class b/build/classes/java/main/net/minecraft/src/BiomeEndDecorator.class deleted file mode 100644 index e08807b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BiomeEndDecorator.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BiomeGenBase.class b/build/classes/java/main/net/minecraft/src/BiomeGenBase.class deleted file mode 100644 index 271b781..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BiomeGenBase.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BiomeGenBeach.class b/build/classes/java/main/net/minecraft/src/BiomeGenBeach.class deleted file mode 100644 index ae8342b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BiomeGenBeach.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BiomeGenDesert.class b/build/classes/java/main/net/minecraft/src/BiomeGenDesert.class deleted file mode 100644 index d8d85a1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BiomeGenDesert.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BiomeGenEnd.class b/build/classes/java/main/net/minecraft/src/BiomeGenEnd.class deleted file mode 100644 index a04523d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BiomeGenEnd.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BiomeGenForest.class b/build/classes/java/main/net/minecraft/src/BiomeGenForest.class deleted file mode 100644 index 3a66d71..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BiomeGenForest.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BiomeGenHell.class b/build/classes/java/main/net/minecraft/src/BiomeGenHell.class deleted file mode 100644 index 1b3bdac..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BiomeGenHell.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BiomeGenHills.class b/build/classes/java/main/net/minecraft/src/BiomeGenHills.class deleted file mode 100644 index c097d89..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BiomeGenHills.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BiomeGenJungle.class b/build/classes/java/main/net/minecraft/src/BiomeGenJungle.class deleted file mode 100644 index a9b6be0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BiomeGenJungle.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BiomeGenMushroomIsland.class b/build/classes/java/main/net/minecraft/src/BiomeGenMushroomIsland.class deleted file mode 100644 index 8b1ffd6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BiomeGenMushroomIsland.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BiomeGenOcean.class b/build/classes/java/main/net/minecraft/src/BiomeGenOcean.class deleted file mode 100644 index 8ff73ab..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BiomeGenOcean.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BiomeGenPlains.class b/build/classes/java/main/net/minecraft/src/BiomeGenPlains.class deleted file mode 100644 index 313c60d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BiomeGenPlains.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BiomeGenRiver.class b/build/classes/java/main/net/minecraft/src/BiomeGenRiver.class deleted file mode 100644 index 7e1f605..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BiomeGenRiver.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BiomeGenSnow.class b/build/classes/java/main/net/minecraft/src/BiomeGenSnow.class deleted file mode 100644 index 467a643..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BiomeGenSnow.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BiomeGenSwamp.class b/build/classes/java/main/net/minecraft/src/BiomeGenSwamp.class deleted file mode 100644 index e34411e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BiomeGenSwamp.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BiomeGenTaiga.class b/build/classes/java/main/net/minecraft/src/BiomeGenTaiga.class deleted file mode 100644 index 1563983..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BiomeGenTaiga.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Block.class b/build/classes/java/main/net/minecraft/src/Block.class deleted file mode 100644 index 78ea0ce..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Block.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockAnvil.class b/build/classes/java/main/net/minecraft/src/BlockAnvil.class deleted file mode 100644 index 5d86ac5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockAnvil.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockBasePressurePlate.class b/build/classes/java/main/net/minecraft/src/BlockBasePressurePlate.class deleted file mode 100644 index 90c7a2e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockBasePressurePlate.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockBaseRailLogic.class b/build/classes/java/main/net/minecraft/src/BlockBaseRailLogic.class deleted file mode 100644 index ddd2f9c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockBaseRailLogic.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockBeacon.class b/build/classes/java/main/net/minecraft/src/BlockBeacon.class deleted file mode 100644 index c6a28e5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockBeacon.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockBed.class b/build/classes/java/main/net/minecraft/src/BlockBed.class deleted file mode 100644 index e36d725..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockBed.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockBookshelf.class b/build/classes/java/main/net/minecraft/src/BlockBookshelf.class deleted file mode 100644 index b4f8444..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockBookshelf.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockBreakable.class b/build/classes/java/main/net/minecraft/src/BlockBreakable.class deleted file mode 100644 index f386692..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockBreakable.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockBrewingStand.class b/build/classes/java/main/net/minecraft/src/BlockBrewingStand.class deleted file mode 100644 index f43ecd0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockBrewingStand.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockButton.class b/build/classes/java/main/net/minecraft/src/BlockButton.class deleted file mode 100644 index 2820c23..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockButton.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockButtonStone.class b/build/classes/java/main/net/minecraft/src/BlockButtonStone.class deleted file mode 100644 index 86366fb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockButtonStone.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockButtonWood.class b/build/classes/java/main/net/minecraft/src/BlockButtonWood.class deleted file mode 100644 index f956c45..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockButtonWood.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockCactus.class b/build/classes/java/main/net/minecraft/src/BlockCactus.class deleted file mode 100644 index d866c93..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockCactus.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockCake.class b/build/classes/java/main/net/minecraft/src/BlockCake.class deleted file mode 100644 index ad1a0d1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockCake.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockCarpet.class b/build/classes/java/main/net/minecraft/src/BlockCarpet.class deleted file mode 100644 index 7fbe571..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockCarpet.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockCarrot.class b/build/classes/java/main/net/minecraft/src/BlockCarrot.class deleted file mode 100644 index 0b7b028..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockCarrot.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockCauldron.class b/build/classes/java/main/net/minecraft/src/BlockCauldron.class deleted file mode 100644 index faf6a8a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockCauldron.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockChest.class b/build/classes/java/main/net/minecraft/src/BlockChest.class deleted file mode 100644 index 35701c4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockChest.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockClay.class b/build/classes/java/main/net/minecraft/src/BlockClay.class deleted file mode 100644 index 86394a5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockClay.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockCocoa.class b/build/classes/java/main/net/minecraft/src/BlockCocoa.class deleted file mode 100644 index fece6c6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockCocoa.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockColored.class b/build/classes/java/main/net/minecraft/src/BlockColored.class deleted file mode 100644 index f57c6be..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockColored.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockCommandBlock.class b/build/classes/java/main/net/minecraft/src/BlockCommandBlock.class deleted file mode 100644 index a08a9a7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockCommandBlock.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockComparator.class b/build/classes/java/main/net/minecraft/src/BlockComparator.class deleted file mode 100644 index c416d3c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockComparator.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockContainer.class b/build/classes/java/main/net/minecraft/src/BlockContainer.class deleted file mode 100644 index fed5f00..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockContainer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockCrops.class b/build/classes/java/main/net/minecraft/src/BlockCrops.class deleted file mode 100644 index a2fa298..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockCrops.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockDaylightDetector.class b/build/classes/java/main/net/minecraft/src/BlockDaylightDetector.class deleted file mode 100644 index 9b0c3b3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockDaylightDetector.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockDeadBush.class b/build/classes/java/main/net/minecraft/src/BlockDeadBush.class deleted file mode 100644 index 8a7a067..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockDeadBush.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockDetectorRail.class b/build/classes/java/main/net/minecraft/src/BlockDetectorRail.class deleted file mode 100644 index a9cc617..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockDetectorRail.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockDirectional.class b/build/classes/java/main/net/minecraft/src/BlockDirectional.class deleted file mode 100644 index d2ba1ca..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockDirectional.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockDirt.class b/build/classes/java/main/net/minecraft/src/BlockDirt.class deleted file mode 100644 index 06480b8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockDirt.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockDispenser.class b/build/classes/java/main/net/minecraft/src/BlockDispenser.class deleted file mode 100644 index e9c4581..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockDispenser.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockDoor.class b/build/classes/java/main/net/minecraft/src/BlockDoor.class deleted file mode 100644 index 9b0c7ce..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockDoor.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockDragonEgg.class b/build/classes/java/main/net/minecraft/src/BlockDragonEgg.class deleted file mode 100644 index b0a530b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockDragonEgg.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockDropper.class b/build/classes/java/main/net/minecraft/src/BlockDropper.class deleted file mode 100644 index 9f9f443..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockDropper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockEnchantmentTable.class b/build/classes/java/main/net/minecraft/src/BlockEnchantmentTable.class deleted file mode 100644 index 51eb413..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockEnchantmentTable.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockEndPortal.class b/build/classes/java/main/net/minecraft/src/BlockEndPortal.class deleted file mode 100644 index 7d67777..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockEndPortal.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockEndPortalFrame.class b/build/classes/java/main/net/minecraft/src/BlockEndPortalFrame.class deleted file mode 100644 index 92c3d55..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockEndPortalFrame.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockEnderChest.class b/build/classes/java/main/net/minecraft/src/BlockEnderChest.class deleted file mode 100644 index 40c2e7a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockEnderChest.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockEventData.class b/build/classes/java/main/net/minecraft/src/BlockEventData.class deleted file mode 100644 index 9a6ce91..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockEventData.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockFarmland.class b/build/classes/java/main/net/minecraft/src/BlockFarmland.class deleted file mode 100644 index 1f8349e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockFarmland.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockFence.class b/build/classes/java/main/net/minecraft/src/BlockFence.class deleted file mode 100644 index c58f93a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockFence.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockFenceGate.class b/build/classes/java/main/net/minecraft/src/BlockFenceGate.class deleted file mode 100644 index 43296f1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockFenceGate.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockFire.class b/build/classes/java/main/net/minecraft/src/BlockFire.class deleted file mode 100644 index 1100781..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockFire.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockFlower.class b/build/classes/java/main/net/minecraft/src/BlockFlower.class deleted file mode 100644 index 5ee60ef..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockFlower.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockFlowerPot.class b/build/classes/java/main/net/minecraft/src/BlockFlowerPot.class deleted file mode 100644 index 8837fb7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockFlowerPot.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockFlowing.class b/build/classes/java/main/net/minecraft/src/BlockFlowing.class deleted file mode 100644 index 4491ba4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockFlowing.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockFluid.class b/build/classes/java/main/net/minecraft/src/BlockFluid.class deleted file mode 100644 index 73be772..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockFluid.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockFurnace.class b/build/classes/java/main/net/minecraft/src/BlockFurnace.class deleted file mode 100644 index 797b3c9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockFurnace.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockGlass.class b/build/classes/java/main/net/minecraft/src/BlockGlass.class deleted file mode 100644 index 0ca005d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockGlass.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockGlowStone.class b/build/classes/java/main/net/minecraft/src/BlockGlowStone.class deleted file mode 100644 index 52a6719..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockGlowStone.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockGrass.class b/build/classes/java/main/net/minecraft/src/BlockGrass.class deleted file mode 100644 index 880845e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockGrass.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockGravel.class b/build/classes/java/main/net/minecraft/src/BlockGravel.class deleted file mode 100644 index 695b5b5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockGravel.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockHalfSlab.class b/build/classes/java/main/net/minecraft/src/BlockHalfSlab.class deleted file mode 100644 index d0b1495..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockHalfSlab.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockHay.class b/build/classes/java/main/net/minecraft/src/BlockHay.class deleted file mode 100644 index 8897cb5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockHay.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockHopper.class b/build/classes/java/main/net/minecraft/src/BlockHopper.class deleted file mode 100644 index 1ea1060..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockHopper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockIce.class b/build/classes/java/main/net/minecraft/src/BlockIce.class deleted file mode 100644 index 4fc4c07..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockIce.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockJukeBox.class b/build/classes/java/main/net/minecraft/src/BlockJukeBox.class deleted file mode 100644 index 8e97472..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockJukeBox.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockLadder.class b/build/classes/java/main/net/minecraft/src/BlockLadder.class deleted file mode 100644 index c674e3e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockLadder.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockLeaves.class b/build/classes/java/main/net/minecraft/src/BlockLeaves.class deleted file mode 100644 index 4282998..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockLeaves.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockLeavesBase.class b/build/classes/java/main/net/minecraft/src/BlockLeavesBase.class deleted file mode 100644 index 4c70d2e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockLeavesBase.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockLever.class b/build/classes/java/main/net/minecraft/src/BlockLever.class deleted file mode 100644 index 1d9a8ca..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockLever.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockLilyPad.class b/build/classes/java/main/net/minecraft/src/BlockLilyPad.class deleted file mode 100644 index 34c096c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockLilyPad.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockLockedChest.class b/build/classes/java/main/net/minecraft/src/BlockLockedChest.class deleted file mode 100644 index 6d31d52..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockLockedChest.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockLog.class b/build/classes/java/main/net/minecraft/src/BlockLog.class deleted file mode 100644 index ee50d08..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockLog.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockMelon.class b/build/classes/java/main/net/minecraft/src/BlockMelon.class deleted file mode 100644 index 397942d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockMelon.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockMobSpawner.class b/build/classes/java/main/net/minecraft/src/BlockMobSpawner.class deleted file mode 100644 index 5bdecd6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockMobSpawner.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockMushroom.class b/build/classes/java/main/net/minecraft/src/BlockMushroom.class deleted file mode 100644 index 901bd53..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockMushroom.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockMushroomCap.class b/build/classes/java/main/net/minecraft/src/BlockMushroomCap.class deleted file mode 100644 index 6348871..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockMushroomCap.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockMycelium.class b/build/classes/java/main/net/minecraft/src/BlockMycelium.class deleted file mode 100644 index b51b190..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockMycelium.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockNetherStalk.class b/build/classes/java/main/net/minecraft/src/BlockNetherStalk.class deleted file mode 100644 index 9ca9b25..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockNetherStalk.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockNetherrack.class b/build/classes/java/main/net/minecraft/src/BlockNetherrack.class deleted file mode 100644 index 0b1bd7b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockNetherrack.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockNote.class b/build/classes/java/main/net/minecraft/src/BlockNote.class deleted file mode 100644 index bcbcb9c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockNote.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockObsidian.class b/build/classes/java/main/net/minecraft/src/BlockObsidian.class deleted file mode 100644 index cef503a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockObsidian.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockOre.class b/build/classes/java/main/net/minecraft/src/BlockOre.class deleted file mode 100644 index d387ae7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockOre.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockOreStorage.class b/build/classes/java/main/net/minecraft/src/BlockOreStorage.class deleted file mode 100644 index 8118092..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockOreStorage.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockPane.class b/build/classes/java/main/net/minecraft/src/BlockPane.class deleted file mode 100644 index 8d71220..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockPane.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockPistonBase.class b/build/classes/java/main/net/minecraft/src/BlockPistonBase.class deleted file mode 100644 index 1abe870..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockPistonBase.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockPistonExtension.class b/build/classes/java/main/net/minecraft/src/BlockPistonExtension.class deleted file mode 100644 index 88521cc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockPistonExtension.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockPistonMoving.class b/build/classes/java/main/net/minecraft/src/BlockPistonMoving.class deleted file mode 100644 index 04f2247..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockPistonMoving.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockPortal.class b/build/classes/java/main/net/minecraft/src/BlockPortal.class deleted file mode 100644 index 6ab8266..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockPortal.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockPotato.class b/build/classes/java/main/net/minecraft/src/BlockPotato.class deleted file mode 100644 index 5ac790c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockPotato.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockPoweredOre.class b/build/classes/java/main/net/minecraft/src/BlockPoweredOre.class deleted file mode 100644 index 2c40931..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockPoweredOre.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockPressurePlate.class b/build/classes/java/main/net/minecraft/src/BlockPressurePlate.class deleted file mode 100644 index 784ba7b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockPressurePlate.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockPressurePlateWeighted.class b/build/classes/java/main/net/minecraft/src/BlockPressurePlateWeighted.class deleted file mode 100644 index d79a92b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockPressurePlateWeighted.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockPumpkin.class b/build/classes/java/main/net/minecraft/src/BlockPumpkin.class deleted file mode 100644 index c74f4e0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockPumpkin.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockQuartz.class b/build/classes/java/main/net/minecraft/src/BlockQuartz.class deleted file mode 100644 index 353fde0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockQuartz.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockRail.class b/build/classes/java/main/net/minecraft/src/BlockRail.class deleted file mode 100644 index 0f9eab0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockRail.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockRailBase.class b/build/classes/java/main/net/minecraft/src/BlockRailBase.class deleted file mode 100644 index 578de3a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockRailBase.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockRailPowered.class b/build/classes/java/main/net/minecraft/src/BlockRailPowered.class deleted file mode 100644 index 142b186..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockRailPowered.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockRedstoneLight.class b/build/classes/java/main/net/minecraft/src/BlockRedstoneLight.class deleted file mode 100644 index c2e6d86..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockRedstoneLight.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockRedstoneLogic.class b/build/classes/java/main/net/minecraft/src/BlockRedstoneLogic.class deleted file mode 100644 index d9fc9a4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockRedstoneLogic.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockRedstoneOre.class b/build/classes/java/main/net/minecraft/src/BlockRedstoneOre.class deleted file mode 100644 index f178aba..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockRedstoneOre.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockRedstoneRepeater.class b/build/classes/java/main/net/minecraft/src/BlockRedstoneRepeater.class deleted file mode 100644 index e0e1657..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockRedstoneRepeater.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockRedstoneTorch.class b/build/classes/java/main/net/minecraft/src/BlockRedstoneTorch.class deleted file mode 100644 index 7902bca..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockRedstoneTorch.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockRedstoneWire.class b/build/classes/java/main/net/minecraft/src/BlockRedstoneWire.class deleted file mode 100644 index 667d62f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockRedstoneWire.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockReed.class b/build/classes/java/main/net/minecraft/src/BlockReed.class deleted file mode 100644 index 5e281a6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockReed.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockRotatedPillar.class b/build/classes/java/main/net/minecraft/src/BlockRotatedPillar.class deleted file mode 100644 index 4224a33..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockRotatedPillar.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockSand.class b/build/classes/java/main/net/minecraft/src/BlockSand.class deleted file mode 100644 index b75c6d5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockSand.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockSandStone.class b/build/classes/java/main/net/minecraft/src/BlockSandStone.class deleted file mode 100644 index 9e0236a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockSandStone.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockSapling.class b/build/classes/java/main/net/minecraft/src/BlockSapling.class deleted file mode 100644 index 89d9fc1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockSapling.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockSign.class b/build/classes/java/main/net/minecraft/src/BlockSign.class deleted file mode 100644 index 24ef3db..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockSign.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockSilverfish.class b/build/classes/java/main/net/minecraft/src/BlockSilverfish.class deleted file mode 100644 index 7c99b30..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockSilverfish.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockSkull.class b/build/classes/java/main/net/minecraft/src/BlockSkull.class deleted file mode 100644 index a2e2561..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockSkull.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockSnow.class b/build/classes/java/main/net/minecraft/src/BlockSnow.class deleted file mode 100644 index 9f57445..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockSnow.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockSnowBlock.class b/build/classes/java/main/net/minecraft/src/BlockSnowBlock.class deleted file mode 100644 index ef53809..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockSnowBlock.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockSoulSand.class b/build/classes/java/main/net/minecraft/src/BlockSoulSand.class deleted file mode 100644 index 293b6a8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockSoulSand.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockSourceImpl.class b/build/classes/java/main/net/minecraft/src/BlockSourceImpl.class deleted file mode 100644 index 49e7891..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockSourceImpl.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockSponge.class b/build/classes/java/main/net/minecraft/src/BlockSponge.class deleted file mode 100644 index 956592b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockSponge.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockStairs.class b/build/classes/java/main/net/minecraft/src/BlockStairs.class deleted file mode 100644 index e24a4a2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockStairs.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockStationary.class b/build/classes/java/main/net/minecraft/src/BlockStationary.class deleted file mode 100644 index 2ec163d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockStationary.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockStem.class b/build/classes/java/main/net/minecraft/src/BlockStem.class deleted file mode 100644 index 9eee3d8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockStem.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockStep.class b/build/classes/java/main/net/minecraft/src/BlockStep.class deleted file mode 100644 index 44c6630..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockStep.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockStone.class b/build/classes/java/main/net/minecraft/src/BlockStone.class deleted file mode 100644 index def1fdf..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockStone.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockStoneBrick.class b/build/classes/java/main/net/minecraft/src/BlockStoneBrick.class deleted file mode 100644 index ff2202d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockStoneBrick.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockTNT.class b/build/classes/java/main/net/minecraft/src/BlockTNT.class deleted file mode 100644 index 42e85da..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockTNT.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockTallGrass.class b/build/classes/java/main/net/minecraft/src/BlockTallGrass.class deleted file mode 100644 index 5ba18ce..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockTallGrass.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockTorch.class b/build/classes/java/main/net/minecraft/src/BlockTorch.class deleted file mode 100644 index 0f713f6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockTorch.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockTrapDoor.class b/build/classes/java/main/net/minecraft/src/BlockTrapDoor.class deleted file mode 100644 index 604b677..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockTrapDoor.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockTripWire.class b/build/classes/java/main/net/minecraft/src/BlockTripWire.class deleted file mode 100644 index f14eeff..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockTripWire.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockTripWireSource.class b/build/classes/java/main/net/minecraft/src/BlockTripWireSource.class deleted file mode 100644 index 3ff274b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockTripWireSource.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockVine.class b/build/classes/java/main/net/minecraft/src/BlockVine.class deleted file mode 100644 index 62da0c3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockVine.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockWall.class b/build/classes/java/main/net/minecraft/src/BlockWall.class deleted file mode 100644 index b9b498b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockWall.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockWeb.class b/build/classes/java/main/net/minecraft/src/BlockWeb.class deleted file mode 100644 index b5a9aa8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockWeb.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockWood.class b/build/classes/java/main/net/minecraft/src/BlockWood.class deleted file mode 100644 index a7fbb4e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockWood.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockWoodSlab.class b/build/classes/java/main/net/minecraft/src/BlockWoodSlab.class deleted file mode 100644 index de6a21c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockWoodSlab.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BlockWorkbench.class b/build/classes/java/main/net/minecraft/src/BlockWorkbench.class deleted file mode 100644 index 300ed62..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BlockWorkbench.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/BossStatus.class b/build/classes/java/main/net/minecraft/src/BossStatus.class deleted file mode 100644 index e4b3c7f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/BossStatus.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableBlockDataValue.class b/build/classes/java/main/net/minecraft/src/CallableBlockDataValue.class deleted file mode 100644 index 2aaa86c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableBlockDataValue.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableBlockLocation.class b/build/classes/java/main/net/minecraft/src/CallableBlockLocation.class deleted file mode 100644 index 6401c0a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableBlockLocation.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableBlockType.class b/build/classes/java/main/net/minecraft/src/CallableBlockType.class deleted file mode 100644 index 61e5fa2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableBlockType.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableChunkPosHash.class b/build/classes/java/main/net/minecraft/src/CallableChunkPosHash.class deleted file mode 100644 index 3f031bf..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableChunkPosHash.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableClientMemoryStats.class b/build/classes/java/main/net/minecraft/src/CallableClientMemoryStats.class deleted file mode 100644 index 72a17cc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableClientMemoryStats.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableClientProfiler.class b/build/classes/java/main/net/minecraft/src/CallableClientProfiler.class deleted file mode 100644 index 39c3a2b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableClientProfiler.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableConnectionName.class b/build/classes/java/main/net/minecraft/src/CallableConnectionName.class deleted file mode 100644 index b08302b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableConnectionName.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableCrashMemoryReport.class b/build/classes/java/main/net/minecraft/src/CallableCrashMemoryReport.class deleted file mode 100644 index 8e21832..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableCrashMemoryReport.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableEntityName.class b/build/classes/java/main/net/minecraft/src/CallableEntityName.class deleted file mode 100644 index 633ce49..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableEntityName.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableEntityTracker.class b/build/classes/java/main/net/minecraft/src/CallableEntityTracker.class deleted file mode 100644 index 1367079..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableEntityTracker.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableEntityType.class b/build/classes/java/main/net/minecraft/src/CallableEntityType.class deleted file mode 100644 index d1ac513..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableEntityType.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableGLInfo.class b/build/classes/java/main/net/minecraft/src/CallableGLInfo.class deleted file mode 100644 index fb51b25..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableGLInfo.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableIntCache.class b/build/classes/java/main/net/minecraft/src/CallableIntCache.class deleted file mode 100644 index fefc653..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableIntCache.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableIsFeatureChunk.class b/build/classes/java/main/net/minecraft/src/CallableIsFeatureChunk.class deleted file mode 100644 index aba02be..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableIsFeatureChunk.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableIsModded.class b/build/classes/java/main/net/minecraft/src/CallableIsModded.class deleted file mode 100644 index d63fda2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableIsModded.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableIsServerModded.class b/build/classes/java/main/net/minecraft/src/CallableIsServerModded.class deleted file mode 100644 index 60967a8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableIsServerModded.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableItemName.class b/build/classes/java/main/net/minecraft/src/CallableItemName.class deleted file mode 100644 index fe0f753..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableItemName.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableJVMFlags.class b/build/classes/java/main/net/minecraft/src/CallableJVMFlags.class deleted file mode 100644 index 8254c4d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableJVMFlags.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableJavaInfo.class b/build/classes/java/main/net/minecraft/src/CallableJavaInfo.class deleted file mode 100644 index 8190f23..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableJavaInfo.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableJavaInfo2.class b/build/classes/java/main/net/minecraft/src/CallableJavaInfo2.class deleted file mode 100644 index 2062d59..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableJavaInfo2.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableLWJGLVersion.class b/build/classes/java/main/net/minecraft/src/CallableLWJGLVersion.class deleted file mode 100644 index 3ebe70a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableLWJGLVersion.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableLaunchedVersion.class b/build/classes/java/main/net/minecraft/src/CallableLaunchedVersion.class deleted file mode 100644 index f05ca40..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableLaunchedVersion.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableLevelDimension.class b/build/classes/java/main/net/minecraft/src/CallableLevelDimension.class deleted file mode 100644 index c1df9b2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableLevelDimension.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableLevelGamemode.class b/build/classes/java/main/net/minecraft/src/CallableLevelGamemode.class deleted file mode 100644 index 4b49f36..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableLevelGamemode.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableLevelGenerator.class b/build/classes/java/main/net/minecraft/src/CallableLevelGenerator.class deleted file mode 100644 index 2158432..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableLevelGenerator.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableLevelGeneratorOptions.class b/build/classes/java/main/net/minecraft/src/CallableLevelGeneratorOptions.class deleted file mode 100644 index 15c4b0a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableLevelGeneratorOptions.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableLevelSeed.class b/build/classes/java/main/net/minecraft/src/CallableLevelSeed.class deleted file mode 100644 index 2c6c60f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableLevelSeed.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableLevelSpawnLocation.class b/build/classes/java/main/net/minecraft/src/CallableLevelSpawnLocation.class deleted file mode 100644 index 4f8213d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableLevelSpawnLocation.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableLevelStorageVersion.class b/build/classes/java/main/net/minecraft/src/CallableLevelStorageVersion.class deleted file mode 100644 index 6b2575a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableLevelStorageVersion.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableLevelTime.class b/build/classes/java/main/net/minecraft/src/CallableLevelTime.class deleted file mode 100644 index f67a397..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableLevelTime.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableLevelWeather.class b/build/classes/java/main/net/minecraft/src/CallableLevelWeather.class deleted file mode 100644 index 3441b7c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableLevelWeather.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableLvl1.class b/build/classes/java/main/net/minecraft/src/CallableLvl1.class deleted file mode 100644 index 00d0098..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableLvl1.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableLvl2.class b/build/classes/java/main/net/minecraft/src/CallableLvl2.class deleted file mode 100644 index f62f22c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableLvl2.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableLvl3.class b/build/classes/java/main/net/minecraft/src/CallableLvl3.class deleted file mode 100644 index 195a3fd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableLvl3.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableMPL1.class b/build/classes/java/main/net/minecraft/src/CallableMPL1.class deleted file mode 100644 index 29bd30e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableMPL1.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableMPL2.class b/build/classes/java/main/net/minecraft/src/CallableMPL2.class deleted file mode 100644 index a0bdc00..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableMPL2.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableMemoryInfo.class b/build/classes/java/main/net/minecraft/src/CallableMemoryInfo.class deleted file mode 100644 index 3cd64e2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableMemoryInfo.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableMinecraftVersion.class b/build/classes/java/main/net/minecraft/src/CallableMinecraftVersion.class deleted file mode 100644 index 7550e83..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableMinecraftVersion.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableModded.class b/build/classes/java/main/net/minecraft/src/CallableModded.class deleted file mode 100644 index 225d5f6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableModded.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableMouseLocation.class b/build/classes/java/main/net/minecraft/src/CallableMouseLocation.class deleted file mode 100644 index 40a97fc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableMouseLocation.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableOSInfo.class b/build/classes/java/main/net/minecraft/src/CallableOSInfo.class deleted file mode 100644 index 528c59d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableOSInfo.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallablePacketClass.class b/build/classes/java/main/net/minecraft/src/CallablePacketClass.class deleted file mode 100644 index d4772c1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallablePacketClass.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallablePacketID.class b/build/classes/java/main/net/minecraft/src/CallablePacketID.class deleted file mode 100644 index d8d4bf2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallablePacketID.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableParticlePositionInfo.class b/build/classes/java/main/net/minecraft/src/CallableParticlePositionInfo.class deleted file mode 100644 index 7fbff29..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableParticlePositionInfo.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableParticleScreenName.class b/build/classes/java/main/net/minecraft/src/CallableParticleScreenName.class deleted file mode 100644 index 74f10ce..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableParticleScreenName.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableScreenName.class b/build/classes/java/main/net/minecraft/src/CallableScreenName.class deleted file mode 100644 index 7dd85f8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableScreenName.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableScreenSize.class b/build/classes/java/main/net/minecraft/src/CallableScreenSize.class deleted file mode 100644 index 81318a0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableScreenSize.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableServerMemoryStats.class b/build/classes/java/main/net/minecraft/src/CallableServerMemoryStats.class deleted file mode 100644 index 4813a58..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableServerMemoryStats.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableServerProfiler.class b/build/classes/java/main/net/minecraft/src/CallableServerProfiler.class deleted file mode 100644 index 21389f9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableServerProfiler.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableServerType.class b/build/classes/java/main/net/minecraft/src/CallableServerType.class deleted file mode 100644 index 08fa885..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableServerType.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableStructureType.class b/build/classes/java/main/net/minecraft/src/CallableStructureType.class deleted file mode 100644 index 78fdebf..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableStructureType.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableSuspiciousClasses.class b/build/classes/java/main/net/minecraft/src/CallableSuspiciousClasses.class deleted file mode 100644 index c278935..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableSuspiciousClasses.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableTagCompound1.class b/build/classes/java/main/net/minecraft/src/CallableTagCompound1.class deleted file mode 100644 index 1e9577c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableTagCompound1.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableTagCompound2.class b/build/classes/java/main/net/minecraft/src/CallableTagCompound2.class deleted file mode 100644 index f0f9131..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableTagCompound2.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableTexturePack.class b/build/classes/java/main/net/minecraft/src/CallableTexturePack.class deleted file mode 100644 index 26e8fab..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableTexturePack.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableTileEntityData.class b/build/classes/java/main/net/minecraft/src/CallableTileEntityData.class deleted file mode 100644 index e523206..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableTileEntityData.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableTileEntityID.class b/build/classes/java/main/net/minecraft/src/CallableTileEntityID.class deleted file mode 100644 index fcfae55..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableTileEntityID.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableTileEntityName.class b/build/classes/java/main/net/minecraft/src/CallableTileEntityName.class deleted file mode 100644 index f7b5da3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableTileEntityName.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableType.class b/build/classes/java/main/net/minecraft/src/CallableType.class deleted file mode 100644 index 622b514..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableType.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableType2.class b/build/classes/java/main/net/minecraft/src/CallableType2.class deleted file mode 100644 index e1c5e4f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableType2.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableType3.class b/build/classes/java/main/net/minecraft/src/CallableType3.class deleted file mode 100644 index 4096e5a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableType3.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CallableUpdatingScreenName.class b/build/classes/java/main/net/minecraft/src/CallableUpdatingScreenName.class deleted file mode 100644 index d3bf20f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CallableUpdatingScreenName.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ChatAllowedCharacters.class b/build/classes/java/main/net/minecraft/src/ChatAllowedCharacters.class deleted file mode 100644 index 1c0cf77..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ChatAllowedCharacters.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ChatClickData.class b/build/classes/java/main/net/minecraft/src/ChatClickData.class deleted file mode 100644 index 3859678..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ChatClickData.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ChatLine.class b/build/classes/java/main/net/minecraft/src/ChatLine.class deleted file mode 100644 index 3f24b9f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ChatLine.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ChatMessageComponent.class b/build/classes/java/main/net/minecraft/src/ChatMessageComponent.class deleted file mode 100644 index 60ce9e7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ChatMessageComponent.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ChestItemRenderHelper.class b/build/classes/java/main/net/minecraft/src/ChestItemRenderHelper.class deleted file mode 100644 index 1a8312c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ChestItemRenderHelper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Chunk.class b/build/classes/java/main/net/minecraft/src/Chunk.class deleted file mode 100644 index 0c4c084..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Chunk.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ChunkCache.class b/build/classes/java/main/net/minecraft/src/ChunkCache.class deleted file mode 100644 index f21ab16..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ChunkCache.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ChunkCoordIntPair.class b/build/classes/java/main/net/minecraft/src/ChunkCoordIntPair.class deleted file mode 100644 index bd34771..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ChunkCoordIntPair.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ChunkCoordinates.class b/build/classes/java/main/net/minecraft/src/ChunkCoordinates.class deleted file mode 100644 index 3439c95..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ChunkCoordinates.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ChunkLoader.class b/build/classes/java/main/net/minecraft/src/ChunkLoader.class deleted file mode 100644 index 3258c0d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ChunkLoader.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ChunkPosition.class b/build/classes/java/main/net/minecraft/src/ChunkPosition.class deleted file mode 100644 index 052811f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ChunkPosition.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ChunkProviderClient.class b/build/classes/java/main/net/minecraft/src/ChunkProviderClient.class deleted file mode 100644 index 99675dc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ChunkProviderClient.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ChunkProviderEnd.class b/build/classes/java/main/net/minecraft/src/ChunkProviderEnd.class deleted file mode 100644 index 5298cbe..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ChunkProviderEnd.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ChunkProviderFlat.class b/build/classes/java/main/net/minecraft/src/ChunkProviderFlat.class deleted file mode 100644 index d7713df..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ChunkProviderFlat.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ChunkProviderGenerate.class b/build/classes/java/main/net/minecraft/src/ChunkProviderGenerate.class deleted file mode 100644 index 433d048..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ChunkProviderGenerate.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ChunkProviderHell.class b/build/classes/java/main/net/minecraft/src/ChunkProviderHell.class deleted file mode 100644 index 8758dbe..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ChunkProviderHell.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ChunkProviderServer.class b/build/classes/java/main/net/minecraft/src/ChunkProviderServer.class deleted file mode 100644 index 7adb9dd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ChunkProviderServer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ClippingHelper.class b/build/classes/java/main/net/minecraft/src/ClippingHelper.class deleted file mode 100644 index 65a0964..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ClippingHelper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ClippingHelperImpl.class b/build/classes/java/main/net/minecraft/src/ClippingHelperImpl.class deleted file mode 100644 index 7713a55..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ClippingHelperImpl.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ColorizerFoliage.class b/build/classes/java/main/net/minecraft/src/ColorizerFoliage.class deleted file mode 100644 index 0e56e85..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ColorizerFoliage.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ColorizerGrass.class b/build/classes/java/main/net/minecraft/src/ColorizerGrass.class deleted file mode 100644 index 252ba20..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ColorizerGrass.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CombatEntry.class b/build/classes/java/main/net/minecraft/src/CombatEntry.class deleted file mode 100644 index f0cdab1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CombatEntry.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CombatTracker.class b/build/classes/java/main/net/minecraft/src/CombatTracker.class deleted file mode 100644 index b77c870..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CombatTracker.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandBase.class b/build/classes/java/main/net/minecraft/src/CommandBase.class deleted file mode 100644 index f733b4e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandBase.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandClearInventory.class b/build/classes/java/main/net/minecraft/src/CommandClearInventory.class deleted file mode 100644 index cb2ab3d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandClearInventory.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandDebug.class b/build/classes/java/main/net/minecraft/src/CommandDebug.class deleted file mode 100644 index 724324f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandDebug.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandDefaultGameMode.class b/build/classes/java/main/net/minecraft/src/CommandDefaultGameMode.class deleted file mode 100644 index 951e5d7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandDefaultGameMode.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandDifficulty.class b/build/classes/java/main/net/minecraft/src/CommandDifficulty.class deleted file mode 100644 index 0b56f22..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandDifficulty.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandEffect.class b/build/classes/java/main/net/minecraft/src/CommandEffect.class deleted file mode 100644 index 7b1db63..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandEffect.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandEnchant.class b/build/classes/java/main/net/minecraft/src/CommandEnchant.class deleted file mode 100644 index d360142..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandEnchant.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandException.class b/build/classes/java/main/net/minecraft/src/CommandException.class deleted file mode 100644 index 9741f7e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandException.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandGameMode.class b/build/classes/java/main/net/minecraft/src/CommandGameMode.class deleted file mode 100644 index 044530e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandGameMode.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandGameRule.class b/build/classes/java/main/net/minecraft/src/CommandGameRule.class deleted file mode 100644 index d4143b1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandGameRule.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandGive.class b/build/classes/java/main/net/minecraft/src/CommandGive.class deleted file mode 100644 index b782bd6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandGive.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandHandler.class b/build/classes/java/main/net/minecraft/src/CommandHandler.class deleted file mode 100644 index 010b423..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandHandler.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandHelp.class b/build/classes/java/main/net/minecraft/src/CommandHelp.class deleted file mode 100644 index e0477b1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandHelp.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandKill.class b/build/classes/java/main/net/minecraft/src/CommandKill.class deleted file mode 100644 index e4b71ff..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandKill.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandNotFoundException.class b/build/classes/java/main/net/minecraft/src/CommandNotFoundException.class deleted file mode 100644 index f170716..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandNotFoundException.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandPlaySound.class b/build/classes/java/main/net/minecraft/src/CommandPlaySound.class deleted file mode 100644 index ee7a0b5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandPlaySound.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandServerBan.class b/build/classes/java/main/net/minecraft/src/CommandServerBan.class deleted file mode 100644 index d6c8481..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandServerBan.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandServerBanIp.class b/build/classes/java/main/net/minecraft/src/CommandServerBanIp.class deleted file mode 100644 index 5491831..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandServerBanIp.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandServerBanlist.class b/build/classes/java/main/net/minecraft/src/CommandServerBanlist.class deleted file mode 100644 index 05fb9ef..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandServerBanlist.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandServerDeop.class b/build/classes/java/main/net/minecraft/src/CommandServerDeop.class deleted file mode 100644 index 17965f9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandServerDeop.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandServerEmote.class b/build/classes/java/main/net/minecraft/src/CommandServerEmote.class deleted file mode 100644 index 130c47c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandServerEmote.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandServerKick.class b/build/classes/java/main/net/minecraft/src/CommandServerKick.class deleted file mode 100644 index bba0335..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandServerKick.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandServerList.class b/build/classes/java/main/net/minecraft/src/CommandServerList.class deleted file mode 100644 index 06a1945..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandServerList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandServerMessage.class b/build/classes/java/main/net/minecraft/src/CommandServerMessage.class deleted file mode 100644 index 4e3b8fd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandServerMessage.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandServerOp.class b/build/classes/java/main/net/minecraft/src/CommandServerOp.class deleted file mode 100644 index d678a2e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandServerOp.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandServerPardon.class b/build/classes/java/main/net/minecraft/src/CommandServerPardon.class deleted file mode 100644 index df7a4e1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandServerPardon.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandServerPardonIp.class b/build/classes/java/main/net/minecraft/src/CommandServerPardonIp.class deleted file mode 100644 index ab315ab..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandServerPardonIp.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandServerPublishLocal.class b/build/classes/java/main/net/minecraft/src/CommandServerPublishLocal.class deleted file mode 100644 index 88fa489..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandServerPublishLocal.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandServerSaveAll.class b/build/classes/java/main/net/minecraft/src/CommandServerSaveAll.class deleted file mode 100644 index 204a61c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandServerSaveAll.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandServerSaveOff.class b/build/classes/java/main/net/minecraft/src/CommandServerSaveOff.class deleted file mode 100644 index 0a211e4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandServerSaveOff.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandServerSaveOn.class b/build/classes/java/main/net/minecraft/src/CommandServerSaveOn.class deleted file mode 100644 index fe20c80..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandServerSaveOn.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandServerSay.class b/build/classes/java/main/net/minecraft/src/CommandServerSay.class deleted file mode 100644 index 4f98228..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandServerSay.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandServerStop.class b/build/classes/java/main/net/minecraft/src/CommandServerStop.class deleted file mode 100644 index 054acb2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandServerStop.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandServerTp.class b/build/classes/java/main/net/minecraft/src/CommandServerTp.class deleted file mode 100644 index 716326d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandServerTp.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandServerWhitelist.class b/build/classes/java/main/net/minecraft/src/CommandServerWhitelist.class deleted file mode 100644 index 26240eb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandServerWhitelist.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandSetPlayerTimeout.class b/build/classes/java/main/net/minecraft/src/CommandSetPlayerTimeout.class deleted file mode 100644 index ca7706a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandSetPlayerTimeout.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandSetSpawnpoint.class b/build/classes/java/main/net/minecraft/src/CommandSetSpawnpoint.class deleted file mode 100644 index f461bf5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandSetSpawnpoint.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandShowSeed.class b/build/classes/java/main/net/minecraft/src/CommandShowSeed.class deleted file mode 100644 index 8bd2280..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandShowSeed.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandSpreadPlayers.class b/build/classes/java/main/net/minecraft/src/CommandSpreadPlayers.class deleted file mode 100644 index b7cede1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandSpreadPlayers.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandSpreadPlayersPosition.class b/build/classes/java/main/net/minecraft/src/CommandSpreadPlayersPosition.class deleted file mode 100644 index 011e679..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandSpreadPlayersPosition.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandTime.class b/build/classes/java/main/net/minecraft/src/CommandTime.class deleted file mode 100644 index 0f7f156..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandTime.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandToggleDownfall.class b/build/classes/java/main/net/minecraft/src/CommandToggleDownfall.class deleted file mode 100644 index 5f11795..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandToggleDownfall.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandWeather.class b/build/classes/java/main/net/minecraft/src/CommandWeather.class deleted file mode 100644 index ab9e538..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandWeather.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CommandXP.class b/build/classes/java/main/net/minecraft/src/CommandXP.class deleted file mode 100644 index f9dd574..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CommandXP.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComparatorClassSorter.class b/build/classes/java/main/net/minecraft/src/ComparatorClassSorter.class deleted file mode 100644 index c48b214..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComparatorClassSorter.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentMineshaftCorridor.class b/build/classes/java/main/net/minecraft/src/ComponentMineshaftCorridor.class deleted file mode 100644 index a5b9c78..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentMineshaftCorridor.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentMineshaftCross.class b/build/classes/java/main/net/minecraft/src/ComponentMineshaftCross.class deleted file mode 100644 index 905bc4f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentMineshaftCross.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentMineshaftRoom.class b/build/classes/java/main/net/minecraft/src/ComponentMineshaftRoom.class deleted file mode 100644 index 95f4efd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentMineshaftRoom.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentMineshaftStairs.class b/build/classes/java/main/net/minecraft/src/ComponentMineshaftStairs.class deleted file mode 100644 index 61cc044..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentMineshaftStairs.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCorridor.class b/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCorridor.class deleted file mode 100644 index 4ea157c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCorridor.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCorridor2.class b/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCorridor2.class deleted file mode 100644 index 19c0101..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCorridor2.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCorridor3.class b/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCorridor3.class deleted file mode 100644 index 4cb94ce..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCorridor3.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCorridor4.class b/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCorridor4.class deleted file mode 100644 index 69f5977..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCorridor4.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCorridor5.class b/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCorridor5.class deleted file mode 100644 index df54d3d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCorridor5.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCrossing.class b/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCrossing.class deleted file mode 100644 index 1484fd8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCrossing.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCrossing2.class b/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCrossing2.class deleted file mode 100644 index b27dfd1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCrossing2.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCrossing3.class b/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCrossing3.class deleted file mode 100644 index 9aeaabf..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeCrossing3.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeEnd.class b/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeEnd.class deleted file mode 100644 index 6dcdc5b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeEnd.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeEntrance.class b/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeEntrance.class deleted file mode 100644 index 511ea58..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeEntrance.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeNetherStalkRoom.class b/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeNetherStalkRoom.class deleted file mode 100644 index a2cee41..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeNetherStalkRoom.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgePiece.class b/build/classes/java/main/net/minecraft/src/ComponentNetherBridgePiece.class deleted file mode 100644 index 8a248a9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgePiece.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeStairs.class b/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeStairs.class deleted file mode 100644 index 4867c62..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeStairs.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeStartPiece.class b/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeStartPiece.class deleted file mode 100644 index c775272..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeStartPiece.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeStraight.class b/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeStraight.class deleted file mode 100644 index 4ac5370..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeStraight.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeThrone.class b/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeThrone.class deleted file mode 100644 index fbb43e2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentNetherBridgeThrone.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentScatteredFeature.class b/build/classes/java/main/net/minecraft/src/ComponentScatteredFeature.class deleted file mode 100644 index 10f47b2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentScatteredFeature.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentScatteredFeatureDesertPyramid.class b/build/classes/java/main/net/minecraft/src/ComponentScatteredFeatureDesertPyramid.class deleted file mode 100644 index 8c49ab9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentScatteredFeatureDesertPyramid.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentScatteredFeatureJunglePyramid.class b/build/classes/java/main/net/minecraft/src/ComponentScatteredFeatureJunglePyramid.class deleted file mode 100644 index d6788b4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentScatteredFeatureJunglePyramid.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentScatteredFeaturePieces.class b/build/classes/java/main/net/minecraft/src/ComponentScatteredFeaturePieces.class deleted file mode 100644 index 58563b2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentScatteredFeaturePieces.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentScatteredFeaturePieces2.class b/build/classes/java/main/net/minecraft/src/ComponentScatteredFeaturePieces2.class deleted file mode 100644 index 7e4bef9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentScatteredFeaturePieces2.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentScatteredFeatureSwampHut.class b/build/classes/java/main/net/minecraft/src/ComponentScatteredFeatureSwampHut.class deleted file mode 100644 index 65579a4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentScatteredFeatureSwampHut.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentStronghold.class b/build/classes/java/main/net/minecraft/src/ComponentStronghold.class deleted file mode 100644 index 8499483..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentStronghold.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentStrongholdChestCorridor.class b/build/classes/java/main/net/minecraft/src/ComponentStrongholdChestCorridor.class deleted file mode 100644 index b1fea18..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentStrongholdChestCorridor.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentStrongholdCorridor.class b/build/classes/java/main/net/minecraft/src/ComponentStrongholdCorridor.class deleted file mode 100644 index 02c5547..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentStrongholdCorridor.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentStrongholdCrossing.class b/build/classes/java/main/net/minecraft/src/ComponentStrongholdCrossing.class deleted file mode 100644 index 6706122..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentStrongholdCrossing.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentStrongholdLeftTurn.class b/build/classes/java/main/net/minecraft/src/ComponentStrongholdLeftTurn.class deleted file mode 100644 index 7ca9cab..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentStrongholdLeftTurn.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentStrongholdLibrary.class b/build/classes/java/main/net/minecraft/src/ComponentStrongholdLibrary.class deleted file mode 100644 index 22540f6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentStrongholdLibrary.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentStrongholdPortalRoom.class b/build/classes/java/main/net/minecraft/src/ComponentStrongholdPortalRoom.class deleted file mode 100644 index 4786b32..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentStrongholdPortalRoom.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentStrongholdPrison.class b/build/classes/java/main/net/minecraft/src/ComponentStrongholdPrison.class deleted file mode 100644 index ee7d6ae..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentStrongholdPrison.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentStrongholdRightTurn.class b/build/classes/java/main/net/minecraft/src/ComponentStrongholdRightTurn.class deleted file mode 100644 index db2e3ff..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentStrongholdRightTurn.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentStrongholdRoomCrossing.class b/build/classes/java/main/net/minecraft/src/ComponentStrongholdRoomCrossing.class deleted file mode 100644 index 788691f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentStrongholdRoomCrossing.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentStrongholdStairs.class b/build/classes/java/main/net/minecraft/src/ComponentStrongholdStairs.class deleted file mode 100644 index e5274fb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentStrongholdStairs.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentStrongholdStairs2.class b/build/classes/java/main/net/minecraft/src/ComponentStrongholdStairs2.class deleted file mode 100644 index 11e7c86..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentStrongholdStairs2.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentStrongholdStairsStraight.class b/build/classes/java/main/net/minecraft/src/ComponentStrongholdStairsStraight.class deleted file mode 100644 index 92507eb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentStrongholdStairsStraight.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentStrongholdStraight.class b/build/classes/java/main/net/minecraft/src/ComponentStrongholdStraight.class deleted file mode 100644 index 6b124d7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentStrongholdStraight.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentVillage.class b/build/classes/java/main/net/minecraft/src/ComponentVillage.class deleted file mode 100644 index 299912d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentVillage.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentVillageChurch.class b/build/classes/java/main/net/minecraft/src/ComponentVillageChurch.class deleted file mode 100644 index fa282cf..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentVillageChurch.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentVillageField.class b/build/classes/java/main/net/minecraft/src/ComponentVillageField.class deleted file mode 100644 index c77791d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentVillageField.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentVillageField2.class b/build/classes/java/main/net/minecraft/src/ComponentVillageField2.class deleted file mode 100644 index caaa536..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentVillageField2.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentVillageHall.class b/build/classes/java/main/net/minecraft/src/ComponentVillageHall.class deleted file mode 100644 index 4418671..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentVillageHall.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentVillageHouse1.class b/build/classes/java/main/net/minecraft/src/ComponentVillageHouse1.class deleted file mode 100644 index 0d816fd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentVillageHouse1.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentVillageHouse2.class b/build/classes/java/main/net/minecraft/src/ComponentVillageHouse2.class deleted file mode 100644 index e30812f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentVillageHouse2.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentVillageHouse3.class b/build/classes/java/main/net/minecraft/src/ComponentVillageHouse3.class deleted file mode 100644 index b4460ea..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentVillageHouse3.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentVillageHouse4_Garden.class b/build/classes/java/main/net/minecraft/src/ComponentVillageHouse4_Garden.class deleted file mode 100644 index 98c7136..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentVillageHouse4_Garden.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentVillagePathGen.class b/build/classes/java/main/net/minecraft/src/ComponentVillagePathGen.class deleted file mode 100644 index d6e512e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentVillagePathGen.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentVillageRoadPiece.class b/build/classes/java/main/net/minecraft/src/ComponentVillageRoadPiece.class deleted file mode 100644 index ca38c2d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentVillageRoadPiece.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentVillageStartPiece.class b/build/classes/java/main/net/minecraft/src/ComponentVillageStartPiece.class deleted file mode 100644 index d43a7d5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentVillageStartPiece.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentVillageTorch.class b/build/classes/java/main/net/minecraft/src/ComponentVillageTorch.class deleted file mode 100644 index c88999e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentVillageTorch.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentVillageWell.class b/build/classes/java/main/net/minecraft/src/ComponentVillageWell.class deleted file mode 100644 index 65833b6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentVillageWell.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ComponentVillageWoodHut.class b/build/classes/java/main/net/minecraft/src/ComponentVillageWoodHut.class deleted file mode 100644 index 6aaff02..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ComponentVillageWoodHut.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CompressedStreamTools.class b/build/classes/java/main/net/minecraft/src/CompressedStreamTools.class deleted file mode 100644 index b7c9df4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CompressedStreamTools.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Container.class b/build/classes/java/main/net/minecraft/src/Container.class deleted file mode 100644 index 77f1fe9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Container.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ContainerBeacon.class b/build/classes/java/main/net/minecraft/src/ContainerBeacon.class deleted file mode 100644 index 51a840b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ContainerBeacon.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ContainerBrewingStand.class b/build/classes/java/main/net/minecraft/src/ContainerBrewingStand.class deleted file mode 100644 index 2fce76b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ContainerBrewingStand.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ContainerChest.class b/build/classes/java/main/net/minecraft/src/ContainerChest.class deleted file mode 100644 index d4d8539..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ContainerChest.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ContainerCreative.class b/build/classes/java/main/net/minecraft/src/ContainerCreative.class deleted file mode 100644 index 2eedbfe..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ContainerCreative.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ContainerDispenser.class b/build/classes/java/main/net/minecraft/src/ContainerDispenser.class deleted file mode 100644 index 9a00f0d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ContainerDispenser.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ContainerEnchantment.class b/build/classes/java/main/net/minecraft/src/ContainerEnchantment.class deleted file mode 100644 index fe5a0a0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ContainerEnchantment.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ContainerFurnace.class b/build/classes/java/main/net/minecraft/src/ContainerFurnace.class deleted file mode 100644 index f457514..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ContainerFurnace.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ContainerHopper.class b/build/classes/java/main/net/minecraft/src/ContainerHopper.class deleted file mode 100644 index 47251b3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ContainerHopper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ContainerHorseInventory.class b/build/classes/java/main/net/minecraft/src/ContainerHorseInventory.class deleted file mode 100644 index 4bd0926..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ContainerHorseInventory.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ContainerHorseInventorySlotArmor.class b/build/classes/java/main/net/minecraft/src/ContainerHorseInventorySlotArmor.class deleted file mode 100644 index 37d0d69..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ContainerHorseInventorySlotArmor.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ContainerHorseInventorySlotSaddle.class b/build/classes/java/main/net/minecraft/src/ContainerHorseInventorySlotSaddle.class deleted file mode 100644 index 060d60b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ContainerHorseInventorySlotSaddle.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ContainerMerchant.class b/build/classes/java/main/net/minecraft/src/ContainerMerchant.class deleted file mode 100644 index f97fffa..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ContainerMerchant.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ContainerPlayer.class b/build/classes/java/main/net/minecraft/src/ContainerPlayer.class deleted file mode 100644 index 4c4b8ad..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ContainerPlayer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ContainerRepair.class b/build/classes/java/main/net/minecraft/src/ContainerRepair.class deleted file mode 100644 index 50cb59c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ContainerRepair.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ContainerRepairINNER1.class b/build/classes/java/main/net/minecraft/src/ContainerRepairINNER1.class deleted file mode 100644 index b5c0220..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ContainerRepairINNER1.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ContainerRepairINNER2.class b/build/classes/java/main/net/minecraft/src/ContainerRepairINNER2.class deleted file mode 100644 index a68667c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ContainerRepairINNER2.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ContainerSheep.class b/build/classes/java/main/net/minecraft/src/ContainerSheep.class deleted file mode 100644 index 04bbc73..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ContainerSheep.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ContainerWorkbench.class b/build/classes/java/main/net/minecraft/src/ContainerWorkbench.class deleted file mode 100644 index 13fbf28..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ContainerWorkbench.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ConvertingProgressUpdate.class b/build/classes/java/main/net/minecraft/src/ConvertingProgressUpdate.class deleted file mode 100644 index b938bc1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ConvertingProgressUpdate.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CraftingManager.class b/build/classes/java/main/net/minecraft/src/CraftingManager.class deleted file mode 100644 index 98a597f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CraftingManager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CrashReport.class b/build/classes/java/main/net/minecraft/src/CrashReport.class deleted file mode 100644 index 554ba9a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CrashReport.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CrashReportCategory.class b/build/classes/java/main/net/minecraft/src/CrashReportCategory.class deleted file mode 100644 index 3d4457f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CrashReportCategory.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CrashReportCategoryEntry.class b/build/classes/java/main/net/minecraft/src/CrashReportCategoryEntry.class deleted file mode 100644 index 0948059..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CrashReportCategoryEntry.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CreativeCrafting.class b/build/classes/java/main/net/minecraft/src/CreativeCrafting.class deleted file mode 100644 index e096b49..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CreativeCrafting.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CreativeTabBlock.class b/build/classes/java/main/net/minecraft/src/CreativeTabBlock.class deleted file mode 100644 index 69fa083..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CreativeTabBlock.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CreativeTabBrewing.class b/build/classes/java/main/net/minecraft/src/CreativeTabBrewing.class deleted file mode 100644 index 2431081..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CreativeTabBrewing.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CreativeTabCombat.class b/build/classes/java/main/net/minecraft/src/CreativeTabCombat.class deleted file mode 100644 index 7eee5ab..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CreativeTabCombat.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CreativeTabDeco.class b/build/classes/java/main/net/minecraft/src/CreativeTabDeco.class deleted file mode 100644 index 86ab0bc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CreativeTabDeco.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CreativeTabFood.class b/build/classes/java/main/net/minecraft/src/CreativeTabFood.class deleted file mode 100644 index ac8a0a0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CreativeTabFood.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CreativeTabInventory.class b/build/classes/java/main/net/minecraft/src/CreativeTabInventory.class deleted file mode 100644 index a21d4a2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CreativeTabInventory.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CreativeTabMaterial.class b/build/classes/java/main/net/minecraft/src/CreativeTabMaterial.class deleted file mode 100644 index 28ab26b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CreativeTabMaterial.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CreativeTabMisc.class b/build/classes/java/main/net/minecraft/src/CreativeTabMisc.class deleted file mode 100644 index 38731a9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CreativeTabMisc.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CreativeTabRedstone.class b/build/classes/java/main/net/minecraft/src/CreativeTabRedstone.class deleted file mode 100644 index 46940b1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CreativeTabRedstone.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CreativeTabSearch.class b/build/classes/java/main/net/minecraft/src/CreativeTabSearch.class deleted file mode 100644 index 75c566c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CreativeTabSearch.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CreativeTabTools.class b/build/classes/java/main/net/minecraft/src/CreativeTabTools.class deleted file mode 100644 index f1a8cec..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CreativeTabTools.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CreativeTabTransport.class b/build/classes/java/main/net/minecraft/src/CreativeTabTransport.class deleted file mode 100644 index 2ca112c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CreativeTabTransport.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CreativeTabs.class b/build/classes/java/main/net/minecraft/src/CreativeTabs.class deleted file mode 100644 index 918aa84..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CreativeTabs.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/CryptManager.class b/build/classes/java/main/net/minecraft/src/CryptManager.class deleted file mode 100644 index cb881c3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/CryptManager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DamageSource.class b/build/classes/java/main/net/minecraft/src/DamageSource.class deleted file mode 100644 index cec5561..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DamageSource.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DataWatcher.class b/build/classes/java/main/net/minecraft/src/DataWatcher.class deleted file mode 100644 index 3f30e1e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DataWatcher.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DedicatedPlayerList.class b/build/classes/java/main/net/minecraft/src/DedicatedPlayerList.class deleted file mode 100644 index 9fdbeb7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DedicatedPlayerList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DedicatedServer.class b/build/classes/java/main/net/minecraft/src/DedicatedServer.class deleted file mode 100644 index cdf4a5f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DedicatedServer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DedicatedServerCommandThread.class b/build/classes/java/main/net/minecraft/src/DedicatedServerCommandThread.class deleted file mode 100644 index c73b5aa..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DedicatedServerCommandThread.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DedicatedServerListenThread.class b/build/classes/java/main/net/minecraft/src/DedicatedServerListenThread.class deleted file mode 100644 index 699d8ba..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DedicatedServerListenThread.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DedicatedServerSleepThread.class b/build/classes/java/main/net/minecraft/src/DedicatedServerSleepThread.class deleted file mode 100644 index 3780072..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DedicatedServerSleepThread.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DefaultResourcePack.class b/build/classes/java/main/net/minecraft/src/DefaultResourcePack.class deleted file mode 100644 index 6f0d40b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DefaultResourcePack.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DemoWorldManager.class b/build/classes/java/main/net/minecraft/src/DemoWorldManager.class deleted file mode 100644 index 2cedf6f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DemoWorldManager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DemoWorldServer.class b/build/classes/java/main/net/minecraft/src/DemoWorldServer.class deleted file mode 100644 index 87142c2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DemoWorldServer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DerivedWorldInfo.class b/build/classes/java/main/net/minecraft/src/DerivedWorldInfo.class deleted file mode 100644 index 364670a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DerivedWorldInfo.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DestroyBlockProgress.class b/build/classes/java/main/net/minecraft/src/DestroyBlockProgress.class deleted file mode 100644 index 150b82f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DestroyBlockProgress.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Direction.class b/build/classes/java/main/net/minecraft/src/Direction.class deleted file mode 100644 index 9461d16..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Direction.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DispenserBehaviorArrow.class b/build/classes/java/main/net/minecraft/src/DispenserBehaviorArrow.class deleted file mode 100644 index 8831436..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DispenserBehaviorArrow.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DispenserBehaviorBoat.class b/build/classes/java/main/net/minecraft/src/DispenserBehaviorBoat.class deleted file mode 100644 index caf104c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DispenserBehaviorBoat.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DispenserBehaviorDye.class b/build/classes/java/main/net/minecraft/src/DispenserBehaviorDye.class deleted file mode 100644 index d5d364b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DispenserBehaviorDye.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DispenserBehaviorEgg.class b/build/classes/java/main/net/minecraft/src/DispenserBehaviorEgg.class deleted file mode 100644 index d8a0f5a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DispenserBehaviorEgg.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DispenserBehaviorEmptyBucket.class b/build/classes/java/main/net/minecraft/src/DispenserBehaviorEmptyBucket.class deleted file mode 100644 index 64b8834..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DispenserBehaviorEmptyBucket.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DispenserBehaviorExperience.class b/build/classes/java/main/net/minecraft/src/DispenserBehaviorExperience.class deleted file mode 100644 index 3bf3b37..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DispenserBehaviorExperience.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DispenserBehaviorFilledBucket.class b/build/classes/java/main/net/minecraft/src/DispenserBehaviorFilledBucket.class deleted file mode 100644 index ded76c1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DispenserBehaviorFilledBucket.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DispenserBehaviorFire.class b/build/classes/java/main/net/minecraft/src/DispenserBehaviorFire.class deleted file mode 100644 index 3442f61..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DispenserBehaviorFire.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DispenserBehaviorFireball.class b/build/classes/java/main/net/minecraft/src/DispenserBehaviorFireball.class deleted file mode 100644 index 0fd5504..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DispenserBehaviorFireball.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DispenserBehaviorFireworks.class b/build/classes/java/main/net/minecraft/src/DispenserBehaviorFireworks.class deleted file mode 100644 index b29c6da..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DispenserBehaviorFireworks.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DispenserBehaviorMobEgg.class b/build/classes/java/main/net/minecraft/src/DispenserBehaviorMobEgg.class deleted file mode 100644 index 150e373..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DispenserBehaviorMobEgg.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DispenserBehaviorPotion.class b/build/classes/java/main/net/minecraft/src/DispenserBehaviorPotion.class deleted file mode 100644 index f32e071..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DispenserBehaviorPotion.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DispenserBehaviorPotionProjectile.class b/build/classes/java/main/net/minecraft/src/DispenserBehaviorPotionProjectile.class deleted file mode 100644 index 07e229f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DispenserBehaviorPotionProjectile.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DispenserBehaviorSnowball.class b/build/classes/java/main/net/minecraft/src/DispenserBehaviorSnowball.class deleted file mode 100644 index 74de551..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DispenserBehaviorSnowball.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DispenserBehaviorTNT.class b/build/classes/java/main/net/minecraft/src/DispenserBehaviorTNT.class deleted file mode 100644 index 2b23bf3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DispenserBehaviorTNT.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DispenserBehaviors.class b/build/classes/java/main/net/minecraft/src/DispenserBehaviors.class deleted file mode 100644 index dee20e3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DispenserBehaviors.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/DynamicTexture.class b/build/classes/java/main/net/minecraft/src/DynamicTexture.class deleted file mode 100644 index 1a49f1d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/DynamicTexture.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EffectRenderer.class b/build/classes/java/main/net/minecraft/src/EffectRenderer.class deleted file mode 100644 index e3db161..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EffectRenderer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Empty3.class b/build/classes/java/main/net/minecraft/src/Empty3.class deleted file mode 100644 index e1a2c51..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Empty3.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EmptyChunk.class b/build/classes/java/main/net/minecraft/src/EmptyChunk.class deleted file mode 100644 index b88a9f1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EmptyChunk.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Enchantment.class b/build/classes/java/main/net/minecraft/src/Enchantment.class deleted file mode 100644 index fb9d545..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Enchantment.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnchantmentArrowDamage.class b/build/classes/java/main/net/minecraft/src/EnchantmentArrowDamage.class deleted file mode 100644 index 44d2ba5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnchantmentArrowDamage.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnchantmentArrowFire.class b/build/classes/java/main/net/minecraft/src/EnchantmentArrowFire.class deleted file mode 100644 index 18d5cb7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnchantmentArrowFire.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnchantmentArrowInfinite.class b/build/classes/java/main/net/minecraft/src/EnchantmentArrowInfinite.class deleted file mode 100644 index 298694d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnchantmentArrowInfinite.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnchantmentArrowKnockback.class b/build/classes/java/main/net/minecraft/src/EnchantmentArrowKnockback.class deleted file mode 100644 index 5ad5ecc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnchantmentArrowKnockback.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnchantmentDamage.class b/build/classes/java/main/net/minecraft/src/EnchantmentDamage.class deleted file mode 100644 index e28a5a9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnchantmentDamage.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnchantmentData.class b/build/classes/java/main/net/minecraft/src/EnchantmentData.class deleted file mode 100644 index fd63840..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnchantmentData.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnchantmentDigging.class b/build/classes/java/main/net/minecraft/src/EnchantmentDigging.class deleted file mode 100644 index 598bf64..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnchantmentDigging.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnchantmentDurability.class b/build/classes/java/main/net/minecraft/src/EnchantmentDurability.class deleted file mode 100644 index 49a66c1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnchantmentDurability.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnchantmentFireAspect.class b/build/classes/java/main/net/minecraft/src/EnchantmentFireAspect.class deleted file mode 100644 index 1593194..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnchantmentFireAspect.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnchantmentHelper.class b/build/classes/java/main/net/minecraft/src/EnchantmentHelper.class deleted file mode 100644 index 2789f95..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnchantmentHelper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnchantmentKnockback.class b/build/classes/java/main/net/minecraft/src/EnchantmentKnockback.class deleted file mode 100644 index 1955cdf..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnchantmentKnockback.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnchantmentLootBonus.class b/build/classes/java/main/net/minecraft/src/EnchantmentLootBonus.class deleted file mode 100644 index f932870..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnchantmentLootBonus.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnchantmentModifierDamage.class b/build/classes/java/main/net/minecraft/src/EnchantmentModifierDamage.class deleted file mode 100644 index 3af6ae0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnchantmentModifierDamage.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnchantmentModifierLiving.class b/build/classes/java/main/net/minecraft/src/EnchantmentModifierLiving.class deleted file mode 100644 index 40cbaf7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnchantmentModifierLiving.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnchantmentNameParts.class b/build/classes/java/main/net/minecraft/src/EnchantmentNameParts.class deleted file mode 100644 index e4f0b35..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnchantmentNameParts.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnchantmentOxygen.class b/build/classes/java/main/net/minecraft/src/EnchantmentOxygen.class deleted file mode 100644 index ef6b30e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnchantmentOxygen.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnchantmentProtection.class b/build/classes/java/main/net/minecraft/src/EnchantmentProtection.class deleted file mode 100644 index 819b0b6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnchantmentProtection.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnchantmentThorns.class b/build/classes/java/main/net/minecraft/src/EnchantmentThorns.class deleted file mode 100644 index 2a83bdd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnchantmentThorns.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnchantmentUntouching.class b/build/classes/java/main/net/minecraft/src/EnchantmentUntouching.class deleted file mode 100644 index ae39949..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnchantmentUntouching.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnchantmentWaterWorker.class b/build/classes/java/main/net/minecraft/src/EnchantmentWaterWorker.class deleted file mode 100644 index 99ec849..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnchantmentWaterWorker.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Entity.class b/build/classes/java/main/net/minecraft/src/Entity.class deleted file mode 100644 index 3c7e193..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Entity.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIArrowAttack.class b/build/classes/java/main/net/minecraft/src/EntityAIArrowAttack.class deleted file mode 100644 index ce5f705..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIArrowAttack.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIAttackOnCollide.class b/build/classes/java/main/net/minecraft/src/EntityAIAttackOnCollide.class deleted file mode 100644 index 1eb5e02..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIAttackOnCollide.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIAvoidEntity.class b/build/classes/java/main/net/minecraft/src/EntityAIAvoidEntity.class deleted file mode 100644 index c443b83..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIAvoidEntity.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIAvoidEntitySelector.class b/build/classes/java/main/net/minecraft/src/EntityAIAvoidEntitySelector.class deleted file mode 100644 index 7350b5c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIAvoidEntitySelector.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIBase.class b/build/classes/java/main/net/minecraft/src/EntityAIBase.class deleted file mode 100644 index ab4b49c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIBase.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIBeg.class b/build/classes/java/main/net/minecraft/src/EntityAIBeg.class deleted file mode 100644 index ac3bb68..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIBeg.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIBreakDoor.class b/build/classes/java/main/net/minecraft/src/EntityAIBreakDoor.class deleted file mode 100644 index 8f87e80..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIBreakDoor.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIControlledByPlayer.class b/build/classes/java/main/net/minecraft/src/EntityAIControlledByPlayer.class deleted file mode 100644 index e24471a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIControlledByPlayer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAICreeperSwell.class b/build/classes/java/main/net/minecraft/src/EntityAICreeperSwell.class deleted file mode 100644 index da60799..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAICreeperSwell.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIDefendVillage.class b/build/classes/java/main/net/minecraft/src/EntityAIDefendVillage.class deleted file mode 100644 index e140861..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIDefendVillage.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIDoorInteract.class b/build/classes/java/main/net/minecraft/src/EntityAIDoorInteract.class deleted file mode 100644 index 4b65b04..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIDoorInteract.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIEatGrass.class b/build/classes/java/main/net/minecraft/src/EntityAIEatGrass.class deleted file mode 100644 index d9122ff..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIEatGrass.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIFleeSun.class b/build/classes/java/main/net/minecraft/src/EntityAIFleeSun.class deleted file mode 100644 index 4d09fc7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIFleeSun.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIFollowGolem.class b/build/classes/java/main/net/minecraft/src/EntityAIFollowGolem.class deleted file mode 100644 index e32c4d6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIFollowGolem.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIFollowOwner.class b/build/classes/java/main/net/minecraft/src/EntityAIFollowOwner.class deleted file mode 100644 index a51cbaa..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIFollowOwner.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIFollowParent.class b/build/classes/java/main/net/minecraft/src/EntityAIFollowParent.class deleted file mode 100644 index a627ca3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIFollowParent.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIHurtByTarget.class b/build/classes/java/main/net/minecraft/src/EntityAIHurtByTarget.class deleted file mode 100644 index abb59a0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIHurtByTarget.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAILeapAtTarget.class b/build/classes/java/main/net/minecraft/src/EntityAILeapAtTarget.class deleted file mode 100644 index 46e207f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAILeapAtTarget.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAILookAtTradePlayer.class b/build/classes/java/main/net/minecraft/src/EntityAILookAtTradePlayer.class deleted file mode 100644 index e5196a3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAILookAtTradePlayer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAILookAtVillager.class b/build/classes/java/main/net/minecraft/src/EntityAILookAtVillager.class deleted file mode 100644 index 663d31d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAILookAtVillager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAILookIdle.class b/build/classes/java/main/net/minecraft/src/EntityAILookIdle.class deleted file mode 100644 index 8fef983..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAILookIdle.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIMate.class b/build/classes/java/main/net/minecraft/src/EntityAIMate.class deleted file mode 100644 index 4f6d1d7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIMate.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIMoveIndoors.class b/build/classes/java/main/net/minecraft/src/EntityAIMoveIndoors.class deleted file mode 100644 index a305fc7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIMoveIndoors.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIMoveThroughVillage.class b/build/classes/java/main/net/minecraft/src/EntityAIMoveThroughVillage.class deleted file mode 100644 index 63049e0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIMoveThroughVillage.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIMoveTowardsRestriction.class b/build/classes/java/main/net/minecraft/src/EntityAIMoveTowardsRestriction.class deleted file mode 100644 index 3e286a0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIMoveTowardsRestriction.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIMoveTowardsTarget.class b/build/classes/java/main/net/minecraft/src/EntityAIMoveTowardsTarget.class deleted file mode 100644 index 1a84540..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIMoveTowardsTarget.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAINearestAttackableTarget.class b/build/classes/java/main/net/minecraft/src/EntityAINearestAttackableTarget.class deleted file mode 100644 index a773c90..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAINearestAttackableTarget.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAINearestAttackableTargetSelector.class b/build/classes/java/main/net/minecraft/src/EntityAINearestAttackableTargetSelector.class deleted file mode 100644 index 198404f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAINearestAttackableTargetSelector.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAINearestAttackableTargetSorter.class b/build/classes/java/main/net/minecraft/src/EntityAINearestAttackableTargetSorter.class deleted file mode 100644 index a9f24e9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAINearestAttackableTargetSorter.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIOcelotAttack.class b/build/classes/java/main/net/minecraft/src/EntityAIOcelotAttack.class deleted file mode 100644 index 0fd88cc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIOcelotAttack.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIOcelotSit.class b/build/classes/java/main/net/minecraft/src/EntityAIOcelotSit.class deleted file mode 100644 index 31ba821..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIOcelotSit.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIOpenDoor.class b/build/classes/java/main/net/minecraft/src/EntityAIOpenDoor.class deleted file mode 100644 index 965cf2b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIOpenDoor.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIOwnerHurtByTarget.class b/build/classes/java/main/net/minecraft/src/EntityAIOwnerHurtByTarget.class deleted file mode 100644 index 6d0a512..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIOwnerHurtByTarget.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIOwnerHurtTarget.class b/build/classes/java/main/net/minecraft/src/EntityAIOwnerHurtTarget.class deleted file mode 100644 index 4b05b3c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIOwnerHurtTarget.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIPanic.class b/build/classes/java/main/net/minecraft/src/EntityAIPanic.class deleted file mode 100644 index 320bf83..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIPanic.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIPlay.class b/build/classes/java/main/net/minecraft/src/EntityAIPlay.class deleted file mode 100644 index 56282e9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIPlay.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIRestrictOpenDoor.class b/build/classes/java/main/net/minecraft/src/EntityAIRestrictOpenDoor.class deleted file mode 100644 index 115d958..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIRestrictOpenDoor.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIRestrictSun.class b/build/classes/java/main/net/minecraft/src/EntityAIRestrictSun.class deleted file mode 100644 index e748e1b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIRestrictSun.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIRunAroundLikeCrazy.class b/build/classes/java/main/net/minecraft/src/EntityAIRunAroundLikeCrazy.class deleted file mode 100644 index 8a378bc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIRunAroundLikeCrazy.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAISit.class b/build/classes/java/main/net/minecraft/src/EntityAISit.class deleted file mode 100644 index ea9dc39..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAISit.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAISwimming.class b/build/classes/java/main/net/minecraft/src/EntityAISwimming.class deleted file mode 100644 index 16b1ec6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAISwimming.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAITarget.class b/build/classes/java/main/net/minecraft/src/EntityAITarget.class deleted file mode 100644 index f1ed731..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAITarget.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAITargetNonTamed.class b/build/classes/java/main/net/minecraft/src/EntityAITargetNonTamed.class deleted file mode 100644 index 27fd8a6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAITargetNonTamed.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAITaskEntry.class b/build/classes/java/main/net/minecraft/src/EntityAITaskEntry.class deleted file mode 100644 index 1d8e390..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAITaskEntry.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAITasks.class b/build/classes/java/main/net/minecraft/src/EntityAITasks.class deleted file mode 100644 index 815f298..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAITasks.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAITempt.class b/build/classes/java/main/net/minecraft/src/EntityAITempt.class deleted file mode 100644 index 73dbec4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAITempt.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAITradePlayer.class b/build/classes/java/main/net/minecraft/src/EntityAITradePlayer.class deleted file mode 100644 index d9658ab..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAITradePlayer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIVillagerMate.class b/build/classes/java/main/net/minecraft/src/EntityAIVillagerMate.class deleted file mode 100644 index 9eaec81..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIVillagerMate.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIWander.class b/build/classes/java/main/net/minecraft/src/EntityAIWander.class deleted file mode 100644 index 38ea66a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIWander.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIWatchClosest.class b/build/classes/java/main/net/minecraft/src/EntityAIWatchClosest.class deleted file mode 100644 index 3c649d0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIWatchClosest.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAIWatchClosest2.class b/build/classes/java/main/net/minecraft/src/EntityAIWatchClosest2.class deleted file mode 100644 index 41dbfb4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAIWatchClosest2.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAgeable.class b/build/classes/java/main/net/minecraft/src/EntityAgeable.class deleted file mode 100644 index 06ad751..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAgeable.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAmbientCreature.class b/build/classes/java/main/net/minecraft/src/EntityAmbientCreature.class deleted file mode 100644 index 3d39228..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAmbientCreature.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAnimal.class b/build/classes/java/main/net/minecraft/src/EntityAnimal.class deleted file mode 100644 index a314ec0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAnimal.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityArrow.class b/build/classes/java/main/net/minecraft/src/EntityArrow.class deleted file mode 100644 index 7fca975..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityArrow.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityAuraFX.class b/build/classes/java/main/net/minecraft/src/EntityAuraFX.class deleted file mode 100644 index 37628ef..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityAuraFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityBat.class b/build/classes/java/main/net/minecraft/src/EntityBat.class deleted file mode 100644 index 781627b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityBat.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityBlaze.class b/build/classes/java/main/net/minecraft/src/EntityBlaze.class deleted file mode 100644 index 7c84be6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityBlaze.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityBoat.class b/build/classes/java/main/net/minecraft/src/EntityBoat.class deleted file mode 100644 index aef1ff7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityBoat.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityBodyHelper.class b/build/classes/java/main/net/minecraft/src/EntityBodyHelper.class deleted file mode 100644 index 30a076c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityBodyHelper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityBreakingFX.class b/build/classes/java/main/net/minecraft/src/EntityBreakingFX.class deleted file mode 100644 index 81c0fd7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityBreakingFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityBubbleFX.class b/build/classes/java/main/net/minecraft/src/EntityBubbleFX.class deleted file mode 100644 index ba5bb99..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityBubbleFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityCaveSpider.class b/build/classes/java/main/net/minecraft/src/EntityCaveSpider.class deleted file mode 100644 index 1b1a6fe..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityCaveSpider.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityChicken.class b/build/classes/java/main/net/minecraft/src/EntityChicken.class deleted file mode 100644 index af7569c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityChicken.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityClientPlayerMP.class b/build/classes/java/main/net/minecraft/src/EntityClientPlayerMP.class deleted file mode 100644 index f71da8e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityClientPlayerMP.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityCloudFX.class b/build/classes/java/main/net/minecraft/src/EntityCloudFX.class deleted file mode 100644 index 5dadb4e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityCloudFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityCow.class b/build/classes/java/main/net/minecraft/src/EntityCow.class deleted file mode 100644 index acb3dca..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityCow.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityCreature.class b/build/classes/java/main/net/minecraft/src/EntityCreature.class deleted file mode 100644 index 3b6df23..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityCreature.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityCreeper.class b/build/classes/java/main/net/minecraft/src/EntityCreeper.class deleted file mode 100644 index c500665..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityCreeper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityCrit2FX.class b/build/classes/java/main/net/minecraft/src/EntityCrit2FX.class deleted file mode 100644 index 793b9bd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityCrit2FX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityCritFX.class b/build/classes/java/main/net/minecraft/src/EntityCritFX.class deleted file mode 100644 index 0bd2914..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityCritFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityDamageSource.class b/build/classes/java/main/net/minecraft/src/EntityDamageSource.class deleted file mode 100644 index eb525b8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityDamageSource.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityDamageSourceIndirect.class b/build/classes/java/main/net/minecraft/src/EntityDamageSourceIndirect.class deleted file mode 100644 index 0d51fa2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityDamageSourceIndirect.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityDiggingFX.class b/build/classes/java/main/net/minecraft/src/EntityDiggingFX.class deleted file mode 100644 index 18a8bf1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityDiggingFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityDragon.class b/build/classes/java/main/net/minecraft/src/EntityDragon.class deleted file mode 100644 index 55bf360..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityDragon.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityDragonPart.class b/build/classes/java/main/net/minecraft/src/EntityDragonPart.class deleted file mode 100644 index 648b461..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityDragonPart.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityDropParticleFX.class b/build/classes/java/main/net/minecraft/src/EntityDropParticleFX.class deleted file mode 100644 index 36457b1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityDropParticleFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityEgg.class b/build/classes/java/main/net/minecraft/src/EntityEgg.class deleted file mode 100644 index 7abbbdd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityEgg.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityEggInfo.class b/build/classes/java/main/net/minecraft/src/EntityEggInfo.class deleted file mode 100644 index 5e1b1e1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityEggInfo.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityEnchantmentTableParticleFX.class b/build/classes/java/main/net/minecraft/src/EntityEnchantmentTableParticleFX.class deleted file mode 100644 index 33a194a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityEnchantmentTableParticleFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityEnderCrystal.class b/build/classes/java/main/net/minecraft/src/EntityEnderCrystal.class deleted file mode 100644 index 9926979..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityEnderCrystal.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityEnderEye.class b/build/classes/java/main/net/minecraft/src/EntityEnderEye.class deleted file mode 100644 index 9baf58d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityEnderEye.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityEnderPearl.class b/build/classes/java/main/net/minecraft/src/EntityEnderPearl.class deleted file mode 100644 index c122aa4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityEnderPearl.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityEnderman.class b/build/classes/java/main/net/minecraft/src/EntityEnderman.class deleted file mode 100644 index 81d99aa..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityEnderman.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityExpBottle.class b/build/classes/java/main/net/minecraft/src/EntityExpBottle.class deleted file mode 100644 index 91f807c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityExpBottle.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityExplodeFX.class b/build/classes/java/main/net/minecraft/src/EntityExplodeFX.class deleted file mode 100644 index 55ea846..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityExplodeFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityFX.class b/build/classes/java/main/net/minecraft/src/EntityFX.class deleted file mode 100644 index 0ebbf68..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityFallingSand.class b/build/classes/java/main/net/minecraft/src/EntityFallingSand.class deleted file mode 100644 index afe425b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityFallingSand.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityFireball.class b/build/classes/java/main/net/minecraft/src/EntityFireball.class deleted file mode 100644 index 3ad0d4a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityFireball.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityFireworkOverlayFX.class b/build/classes/java/main/net/minecraft/src/EntityFireworkOverlayFX.class deleted file mode 100644 index 56e35da..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityFireworkOverlayFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityFireworkRocket.class b/build/classes/java/main/net/minecraft/src/EntityFireworkRocket.class deleted file mode 100644 index 908f99b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityFireworkRocket.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityFireworkSparkFX.class b/build/classes/java/main/net/minecraft/src/EntityFireworkSparkFX.class deleted file mode 100644 index ec6fc51..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityFireworkSparkFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityFireworkStarterFX.class b/build/classes/java/main/net/minecraft/src/EntityFireworkStarterFX.class deleted file mode 100644 index 25af673..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityFireworkStarterFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityFishHook.class b/build/classes/java/main/net/minecraft/src/EntityFishHook.class deleted file mode 100644 index 0cd576a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityFishHook.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityFlameFX.class b/build/classes/java/main/net/minecraft/src/EntityFlameFX.class deleted file mode 100644 index 6ca21f6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityFlameFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityFlying.class b/build/classes/java/main/net/minecraft/src/EntityFlying.class deleted file mode 100644 index 964029c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityFlying.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityFootStepFX.class b/build/classes/java/main/net/minecraft/src/EntityFootStepFX.class deleted file mode 100644 index 25b1013..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityFootStepFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityGhast.class b/build/classes/java/main/net/minecraft/src/EntityGhast.class deleted file mode 100644 index a3f3a4b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityGhast.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityGiantZombie.class b/build/classes/java/main/net/minecraft/src/EntityGiantZombie.class deleted file mode 100644 index 12410bd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityGiantZombie.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityGolem.class b/build/classes/java/main/net/minecraft/src/EntityGolem.class deleted file mode 100644 index 26d3a00..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityGolem.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityHanging.class b/build/classes/java/main/net/minecraft/src/EntityHanging.class deleted file mode 100644 index 23b6f84..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityHanging.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityHeartFX.class b/build/classes/java/main/net/minecraft/src/EntityHeartFX.class deleted file mode 100644 index 4890790..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityHeartFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityHorse.class b/build/classes/java/main/net/minecraft/src/EntityHorse.class deleted file mode 100644 index f76eafc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityHorse.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityHorseBredSelector.class b/build/classes/java/main/net/minecraft/src/EntityHorseBredSelector.class deleted file mode 100644 index 277d28e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityHorseBredSelector.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityHorseGroupData.class b/build/classes/java/main/net/minecraft/src/EntityHorseGroupData.class deleted file mode 100644 index b271dbd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityHorseGroupData.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityHugeExplodeFX.class b/build/classes/java/main/net/minecraft/src/EntityHugeExplodeFX.class deleted file mode 100644 index 99ccbcc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityHugeExplodeFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityIronGolem.class b/build/classes/java/main/net/minecraft/src/EntityIronGolem.class deleted file mode 100644 index 480deea..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityIronGolem.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityItem.class b/build/classes/java/main/net/minecraft/src/EntityItem.class deleted file mode 100644 index 37225ea..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityItem.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityItemFrame.class b/build/classes/java/main/net/minecraft/src/EntityItemFrame.class deleted file mode 100644 index 8981d5d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityItemFrame.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityJumpHelper.class b/build/classes/java/main/net/minecraft/src/EntityJumpHelper.class deleted file mode 100644 index 610f091..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityJumpHelper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityLargeExplodeFX.class b/build/classes/java/main/net/minecraft/src/EntityLargeExplodeFX.class deleted file mode 100644 index 9ab66c6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityLargeExplodeFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityLargeFireball.class b/build/classes/java/main/net/minecraft/src/EntityLargeFireball.class deleted file mode 100644 index 4e64f9c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityLargeFireball.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityLavaFX.class b/build/classes/java/main/net/minecraft/src/EntityLavaFX.class deleted file mode 100644 index fb335ab..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityLavaFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityLeashKnot.class b/build/classes/java/main/net/minecraft/src/EntityLeashKnot.class deleted file mode 100644 index 8eca2bf..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityLeashKnot.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityLightningBolt.class b/build/classes/java/main/net/minecraft/src/EntityLightningBolt.class deleted file mode 100644 index 1cc97a7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityLightningBolt.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityList.class b/build/classes/java/main/net/minecraft/src/EntityList.class deleted file mode 100644 index 1a66012..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityLiving.class b/build/classes/java/main/net/minecraft/src/EntityLiving.class deleted file mode 100644 index 1e13887..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityLiving.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityLivingBase.class b/build/classes/java/main/net/minecraft/src/EntityLivingBase.class deleted file mode 100644 index 67a4edb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityLivingBase.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityLivingData.class b/build/classes/java/main/net/minecraft/src/EntityLivingData.class deleted file mode 100644 index c8e2c2c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityLivingData.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityLookHelper.class b/build/classes/java/main/net/minecraft/src/EntityLookHelper.class deleted file mode 100644 index f4fdd1a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityLookHelper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityMagmaCube.class b/build/classes/java/main/net/minecraft/src/EntityMagmaCube.class deleted file mode 100644 index 43d195a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityMagmaCube.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityMinecart.class b/build/classes/java/main/net/minecraft/src/EntityMinecart.class deleted file mode 100644 index bba3968..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityMinecart.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityMinecartChest.class b/build/classes/java/main/net/minecraft/src/EntityMinecartChest.class deleted file mode 100644 index e0d0dec..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityMinecartChest.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityMinecartContainer.class b/build/classes/java/main/net/minecraft/src/EntityMinecartContainer.class deleted file mode 100644 index f8aa6ed..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityMinecartContainer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityMinecartEmpty.class b/build/classes/java/main/net/minecraft/src/EntityMinecartEmpty.class deleted file mode 100644 index 40bd921..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityMinecartEmpty.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityMinecartFurnace.class b/build/classes/java/main/net/minecraft/src/EntityMinecartFurnace.class deleted file mode 100644 index fb48a50..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityMinecartFurnace.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityMinecartHopper.class b/build/classes/java/main/net/minecraft/src/EntityMinecartHopper.class deleted file mode 100644 index 7d649de..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityMinecartHopper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityMinecartMobSpawner.class b/build/classes/java/main/net/minecraft/src/EntityMinecartMobSpawner.class deleted file mode 100644 index b4508c7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityMinecartMobSpawner.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityMinecartMobSpawnerLogic.class b/build/classes/java/main/net/minecraft/src/EntityMinecartMobSpawnerLogic.class deleted file mode 100644 index e080386..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityMinecartMobSpawnerLogic.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityMinecartTNT.class b/build/classes/java/main/net/minecraft/src/EntityMinecartTNT.class deleted file mode 100644 index 320d2c8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityMinecartTNT.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityMob.class b/build/classes/java/main/net/minecraft/src/EntityMob.class deleted file mode 100644 index f8958f4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityMob.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityMooshroom.class b/build/classes/java/main/net/minecraft/src/EntityMooshroom.class deleted file mode 100644 index 17e9c45..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityMooshroom.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityMoveHelper.class b/build/classes/java/main/net/minecraft/src/EntityMoveHelper.class deleted file mode 100644 index ff22b5a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityMoveHelper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityNoteFX.class b/build/classes/java/main/net/minecraft/src/EntityNoteFX.class deleted file mode 100644 index 7b0852f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityNoteFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityOcelot.class b/build/classes/java/main/net/minecraft/src/EntityOcelot.class deleted file mode 100644 index 3125274..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityOcelot.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityOtherPlayerMP.class b/build/classes/java/main/net/minecraft/src/EntityOtherPlayerMP.class deleted file mode 100644 index 3362de4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityOtherPlayerMP.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityOwnable.class b/build/classes/java/main/net/minecraft/src/EntityOwnable.class deleted file mode 100644 index d317aa1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityOwnable.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityPainting.class b/build/classes/java/main/net/minecraft/src/EntityPainting.class deleted file mode 100644 index 22c4353..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityPainting.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityPickupFX.class b/build/classes/java/main/net/minecraft/src/EntityPickupFX.class deleted file mode 100644 index 1ebe750..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityPickupFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityPig.class b/build/classes/java/main/net/minecraft/src/EntityPig.class deleted file mode 100644 index 91c201f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityPig.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityPigZombie.class b/build/classes/java/main/net/minecraft/src/EntityPigZombie.class deleted file mode 100644 index 69d164e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityPigZombie.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityPlayer.class b/build/classes/java/main/net/minecraft/src/EntityPlayer.class deleted file mode 100644 index fb2e2fc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityPlayer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityPlayerMP.class b/build/classes/java/main/net/minecraft/src/EntityPlayerMP.class deleted file mode 100644 index d5acd4b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityPlayerMP.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityPlayerSP.class b/build/classes/java/main/net/minecraft/src/EntityPlayerSP.class deleted file mode 100644 index 637f09b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityPlayerSP.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityPortalFX.class b/build/classes/java/main/net/minecraft/src/EntityPortalFX.class deleted file mode 100644 index 02687cd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityPortalFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityPotion.class b/build/classes/java/main/net/minecraft/src/EntityPotion.class deleted file mode 100644 index 79c5e50..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityPotion.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityRainFX.class b/build/classes/java/main/net/minecraft/src/EntityRainFX.class deleted file mode 100644 index cfe318a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityRainFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityReddustFX.class b/build/classes/java/main/net/minecraft/src/EntityReddustFX.class deleted file mode 100644 index ebebfd4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityReddustFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityRenderer.class b/build/classes/java/main/net/minecraft/src/EntityRenderer.class deleted file mode 100644 index 63fc23f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityRenderer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntitySelectorAlive.class b/build/classes/java/main/net/minecraft/src/EntitySelectorAlive.class deleted file mode 100644 index 7a4ae99..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntitySelectorAlive.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntitySelectorArmoredMob.class b/build/classes/java/main/net/minecraft/src/EntitySelectorArmoredMob.class deleted file mode 100644 index 7bb6ba8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntitySelectorArmoredMob.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntitySelectorInventory.class b/build/classes/java/main/net/minecraft/src/EntitySelectorInventory.class deleted file mode 100644 index 985062e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntitySelectorInventory.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntitySenses.class b/build/classes/java/main/net/minecraft/src/EntitySenses.class deleted file mode 100644 index 70dfb22..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntitySenses.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntitySheep.class b/build/classes/java/main/net/minecraft/src/EntitySheep.class deleted file mode 100644 index 8157a55..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntitySheep.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntitySilverfish.class b/build/classes/java/main/net/minecraft/src/EntitySilverfish.class deleted file mode 100644 index 9940af5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntitySilverfish.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntitySkeleton.class b/build/classes/java/main/net/minecraft/src/EntitySkeleton.class deleted file mode 100644 index c7414fa..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntitySkeleton.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntitySlime.class b/build/classes/java/main/net/minecraft/src/EntitySlime.class deleted file mode 100644 index 2cf51b5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntitySlime.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntitySmallFireball.class b/build/classes/java/main/net/minecraft/src/EntitySmallFireball.class deleted file mode 100644 index d4d576d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntitySmallFireball.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntitySmokeFX.class b/build/classes/java/main/net/minecraft/src/EntitySmokeFX.class deleted file mode 100644 index 7d70a02..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntitySmokeFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntitySnowShovelFX.class b/build/classes/java/main/net/minecraft/src/EntitySnowShovelFX.class deleted file mode 100644 index 077bb45..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntitySnowShovelFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntitySnowball.class b/build/classes/java/main/net/minecraft/src/EntitySnowball.class deleted file mode 100644 index 5b87e62..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntitySnowball.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntitySnowman.class b/build/classes/java/main/net/minecraft/src/EntitySnowman.class deleted file mode 100644 index f4ccb30..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntitySnowman.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntitySorter.class b/build/classes/java/main/net/minecraft/src/EntitySorter.class deleted file mode 100644 index 8d663be..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntitySorter.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntitySpellParticleFX.class b/build/classes/java/main/net/minecraft/src/EntitySpellParticleFX.class deleted file mode 100644 index 3d73b29..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntitySpellParticleFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntitySpider.class b/build/classes/java/main/net/minecraft/src/EntitySpider.class deleted file mode 100644 index e1ad61c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntitySpider.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntitySplashFX.class b/build/classes/java/main/net/minecraft/src/EntitySplashFX.class deleted file mode 100644 index 5529163..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntitySplashFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntitySquid.class b/build/classes/java/main/net/minecraft/src/EntitySquid.class deleted file mode 100644 index 91df6b2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntitySquid.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntitySuspendFX.class b/build/classes/java/main/net/minecraft/src/EntitySuspendFX.class deleted file mode 100644 index 9741317..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntitySuspendFX.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityTNTPrimed.class b/build/classes/java/main/net/minecraft/src/EntityTNTPrimed.class deleted file mode 100644 index 488cd24..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityTNTPrimed.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityTameable.class b/build/classes/java/main/net/minecraft/src/EntityTameable.class deleted file mode 100644 index 0d5eb70..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityTameable.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityThrowable.class b/build/classes/java/main/net/minecraft/src/EntityThrowable.class deleted file mode 100644 index 5ae57fd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityThrowable.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityTracker.class b/build/classes/java/main/net/minecraft/src/EntityTracker.class deleted file mode 100644 index 63095b9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityTracker.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityTrackerEntry.class b/build/classes/java/main/net/minecraft/src/EntityTrackerEntry.class deleted file mode 100644 index 06ea6ac..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityTrackerEntry.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityVillager.class b/build/classes/java/main/net/minecraft/src/EntityVillager.class deleted file mode 100644 index 0a4aef4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityVillager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityWaterMob.class b/build/classes/java/main/net/minecraft/src/EntityWaterMob.class deleted file mode 100644 index 9390c1a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityWaterMob.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityWeatherEffect.class b/build/classes/java/main/net/minecraft/src/EntityWeatherEffect.class deleted file mode 100644 index 72a8e59..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityWeatherEffect.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityWitch.class b/build/classes/java/main/net/minecraft/src/EntityWitch.class deleted file mode 100644 index ee31bb1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityWitch.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityWither.class b/build/classes/java/main/net/minecraft/src/EntityWither.class deleted file mode 100644 index 196c6a6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityWither.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityWitherAttackFilter.class b/build/classes/java/main/net/minecraft/src/EntityWitherAttackFilter.class deleted file mode 100644 index 623e109..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityWitherAttackFilter.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityWitherSkull.class b/build/classes/java/main/net/minecraft/src/EntityWitherSkull.class deleted file mode 100644 index 6ee5248..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityWitherSkull.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityWolf.class b/build/classes/java/main/net/minecraft/src/EntityWolf.class deleted file mode 100644 index 4bde093..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityWolf.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityXPOrb.class b/build/classes/java/main/net/minecraft/src/EntityXPOrb.class deleted file mode 100644 index 1dd2778..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityXPOrb.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityZombie.class b/build/classes/java/main/net/minecraft/src/EntityZombie.class deleted file mode 100644 index 43016a5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityZombie.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityZombieGroupData.class b/build/classes/java/main/net/minecraft/src/EntityZombieGroupData.class deleted file mode 100644 index b916fb4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityZombieGroupData.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EntityZombieINNER1.class b/build/classes/java/main/net/minecraft/src/EntityZombieINNER1.class deleted file mode 100644 index b3cdd68..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EntityZombieINNER1.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumAction.class b/build/classes/java/main/net/minecraft/src/EnumAction.class deleted file mode 100644 index b9064ba..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumAction.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumArmorMaterial.class b/build/classes/java/main/net/minecraft/src/EnumArmorMaterial.class deleted file mode 100644 index 081f2bd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumArmorMaterial.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumArt.class b/build/classes/java/main/net/minecraft/src/EnumArt.class deleted file mode 100644 index a6f60e9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumArt.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumChatFormatting.class b/build/classes/java/main/net/minecraft/src/EnumChatFormatting.class deleted file mode 100644 index 5c8848b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumChatFormatting.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumCreatureAttribute.class b/build/classes/java/main/net/minecraft/src/EnumCreatureAttribute.class deleted file mode 100644 index 7b63780..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumCreatureAttribute.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumCreatureType.class b/build/classes/java/main/net/minecraft/src/EnumCreatureType.class deleted file mode 100644 index 167df8a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumCreatureType.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumDoor.class b/build/classes/java/main/net/minecraft/src/EnumDoor.class deleted file mode 100644 index fe64398..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumDoor.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumDoorHelper.class b/build/classes/java/main/net/minecraft/src/EnumDoorHelper.class deleted file mode 100644 index 3cb503a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumDoorHelper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumEnchantmentType.class b/build/classes/java/main/net/minecraft/src/EnumEnchantmentType.class deleted file mode 100644 index 650aa3f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumEnchantmentType.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumEntitySize.class b/build/classes/java/main/net/minecraft/src/EnumEntitySize.class deleted file mode 100644 index 1ca43c4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumEntitySize.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumEntitySizeHelper.class b/build/classes/java/main/net/minecraft/src/EnumEntitySizeHelper.class deleted file mode 100644 index 354215e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumEntitySizeHelper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumFacing.class b/build/classes/java/main/net/minecraft/src/EnumFacing.class deleted file mode 100644 index 8a2df9b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumFacing.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumGameType.class b/build/classes/java/main/net/minecraft/src/EnumGameType.class deleted file mode 100644 index f3e06e1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumGameType.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumMobType.class b/build/classes/java/main/net/minecraft/src/EnumMobType.class deleted file mode 100644 index 93c6e0d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumMobType.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumMovingObjectType.class b/build/classes/java/main/net/minecraft/src/EnumMovingObjectType.class deleted file mode 100644 index 48c3c4f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumMovingObjectType.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumOS.class b/build/classes/java/main/net/minecraft/src/EnumOS.class deleted file mode 100644 index 6e71958..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumOS.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumOptions.class b/build/classes/java/main/net/minecraft/src/EnumOptions.class deleted file mode 100644 index c9f2c7c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumOptions.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumOptionsHelper.class b/build/classes/java/main/net/minecraft/src/EnumOptionsHelper.class deleted file mode 100644 index f81ec9a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumOptionsHelper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumRarity.class b/build/classes/java/main/net/minecraft/src/EnumRarity.class deleted file mode 100644 index f42c507..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumRarity.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumSkyBlock.class b/build/classes/java/main/net/minecraft/src/EnumSkyBlock.class deleted file mode 100644 index 6e3df9e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumSkyBlock.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumStatus.class b/build/classes/java/main/net/minecraft/src/EnumStatus.class deleted file mode 100644 index 6b0c0f8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumStatus.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/EnumToolMaterial.class b/build/classes/java/main/net/minecraft/src/EnumToolMaterial.class deleted file mode 100644 index 2939c97..0000000 Binary files a/build/classes/java/main/net/minecraft/src/EnumToolMaterial.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ExceptionMcoHttp.class b/build/classes/java/main/net/minecraft/src/ExceptionMcoHttp.class deleted file mode 100644 index 2c607e7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ExceptionMcoHttp.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ExceptionMcoService.class b/build/classes/java/main/net/minecraft/src/ExceptionMcoService.class deleted file mode 100644 index 8b145d4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ExceptionMcoService.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ExceptionRetryCall.class b/build/classes/java/main/net/minecraft/src/ExceptionRetryCall.class deleted file mode 100644 index bbe5573..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ExceptionRetryCall.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Explosion.class b/build/classes/java/main/net/minecraft/src/Explosion.class deleted file mode 100644 index 08a32aa..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Explosion.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ExtendedBlockStorage.class b/build/classes/java/main/net/minecraft/src/ExtendedBlockStorage.class deleted file mode 100644 index f441c7d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ExtendedBlockStorage.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Facing.class b/build/classes/java/main/net/minecraft/src/Facing.class deleted file mode 100644 index 39a83ec..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Facing.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/FallbackResourceManager.class b/build/classes/java/main/net/minecraft/src/FallbackResourceManager.class deleted file mode 100644 index 4dd92c5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/FallbackResourceManager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/FileResourcePack.class b/build/classes/java/main/net/minecraft/src/FileResourcePack.class deleted file mode 100644 index a6113b6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/FileResourcePack.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/FilterIMob.class b/build/classes/java/main/net/minecraft/src/FilterIMob.class deleted file mode 100644 index 602bec2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/FilterIMob.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/FlatGeneratorInfo.class b/build/classes/java/main/net/minecraft/src/FlatGeneratorInfo.class deleted file mode 100644 index 7d47f1c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/FlatGeneratorInfo.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/FlatLayerInfo.class b/build/classes/java/main/net/minecraft/src/FlatLayerInfo.class deleted file mode 100644 index b1a5286..0000000 Binary files a/build/classes/java/main/net/minecraft/src/FlatLayerInfo.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/FolderResourcePack.class b/build/classes/java/main/net/minecraft/src/FolderResourcePack.class deleted file mode 100644 index 2de61f8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/FolderResourcePack.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/FoliageColorReloadListener.class b/build/classes/java/main/net/minecraft/src/FoliageColorReloadListener.class deleted file mode 100644 index 3adeb7e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/FoliageColorReloadListener.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/FontMetadataSection.class b/build/classes/java/main/net/minecraft/src/FontMetadataSection.class deleted file mode 100644 index e65686e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/FontMetadataSection.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/FontMetadataSectionSerializer.class b/build/classes/java/main/net/minecraft/src/FontMetadataSectionSerializer.class deleted file mode 100644 index 913c913..0000000 Binary files a/build/classes/java/main/net/minecraft/src/FontMetadataSectionSerializer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/FontRenderer.class b/build/classes/java/main/net/minecraft/src/FontRenderer.class deleted file mode 100644 index b81ac08..0000000 Binary files a/build/classes/java/main/net/minecraft/src/FontRenderer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/FoodStats.class b/build/classes/java/main/net/minecraft/src/FoodStats.class deleted file mode 100644 index 45cd581..0000000 Binary files a/build/classes/java/main/net/minecraft/src/FoodStats.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Frustrum.class b/build/classes/java/main/net/minecraft/src/Frustrum.class deleted file mode 100644 index a5f8e22..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Frustrum.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/FurnaceRecipes.class b/build/classes/java/main/net/minecraft/src/FurnaceRecipes.class deleted file mode 100644 index 4f12594..0000000 Binary files a/build/classes/java/main/net/minecraft/src/FurnaceRecipes.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GLAllocation.class b/build/classes/java/main/net/minecraft/src/GLAllocation.class deleted file mode 100644 index 1bcc57e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GLAllocation.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GameRuleValue.class b/build/classes/java/main/net/minecraft/src/GameRuleValue.class deleted file mode 100644 index c0e3cdb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GameRuleValue.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GameRules.class b/build/classes/java/main/net/minecraft/src/GameRules.class deleted file mode 100644 index 8fb5046..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GameRules.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GameSettings.class b/build/classes/java/main/net/minecraft/src/GameSettings.class deleted file mode 100644 index 842ed73..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GameSettings.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GenLayer.class b/build/classes/java/main/net/minecraft/src/GenLayer.class deleted file mode 100644 index 8dc9056..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GenLayer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GenLayerAddIsland.class b/build/classes/java/main/net/minecraft/src/GenLayerAddIsland.class deleted file mode 100644 index 3983caa..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GenLayerAddIsland.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GenLayerAddMushroomIsland.class b/build/classes/java/main/net/minecraft/src/GenLayerAddMushroomIsland.class deleted file mode 100644 index e5ba403..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GenLayerAddMushroomIsland.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GenLayerAddSnow.class b/build/classes/java/main/net/minecraft/src/GenLayerAddSnow.class deleted file mode 100644 index fccd46c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GenLayerAddSnow.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GenLayerBiome.class b/build/classes/java/main/net/minecraft/src/GenLayerBiome.class deleted file mode 100644 index 43305fb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GenLayerBiome.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GenLayerFuzzyZoom.class b/build/classes/java/main/net/minecraft/src/GenLayerFuzzyZoom.class deleted file mode 100644 index ed55851..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GenLayerFuzzyZoom.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GenLayerHills.class b/build/classes/java/main/net/minecraft/src/GenLayerHills.class deleted file mode 100644 index 7ba7a6c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GenLayerHills.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GenLayerIsland.class b/build/classes/java/main/net/minecraft/src/GenLayerIsland.class deleted file mode 100644 index 2e5bac2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GenLayerIsland.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GenLayerRiver.class b/build/classes/java/main/net/minecraft/src/GenLayerRiver.class deleted file mode 100644 index 2393562..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GenLayerRiver.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GenLayerRiverInit.class b/build/classes/java/main/net/minecraft/src/GenLayerRiverInit.class deleted file mode 100644 index 4d32d28..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GenLayerRiverInit.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GenLayerRiverMix.class b/build/classes/java/main/net/minecraft/src/GenLayerRiverMix.class deleted file mode 100644 index 3dd5ce7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GenLayerRiverMix.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GenLayerShore.class b/build/classes/java/main/net/minecraft/src/GenLayerShore.class deleted file mode 100644 index d9955b3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GenLayerShore.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GenLayerSmooth.class b/build/classes/java/main/net/minecraft/src/GenLayerSmooth.class deleted file mode 100644 index 11e8a3a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GenLayerSmooth.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GenLayerSwampRivers.class b/build/classes/java/main/net/minecraft/src/GenLayerSwampRivers.class deleted file mode 100644 index 29378d0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GenLayerSwampRivers.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GenLayerVoronoiZoom.class b/build/classes/java/main/net/minecraft/src/GenLayerVoronoiZoom.class deleted file mode 100644 index fe71114..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GenLayerVoronoiZoom.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GenLayerZoom.class b/build/classes/java/main/net/minecraft/src/GenLayerZoom.class deleted file mode 100644 index 29ba2b2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GenLayerZoom.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GrassColorReloadListener.class b/build/classes/java/main/net/minecraft/src/GrassColorReloadListener.class deleted file mode 100644 index c05e696..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GrassColorReloadListener.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Gui.class b/build/classes/java/main/net/minecraft/src/Gui.class deleted file mode 100644 index 3f44988..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Gui.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiAchievement.class b/build/classes/java/main/net/minecraft/src/GuiAchievement.class deleted file mode 100644 index 0eed976..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiAchievement.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiAchievements.class b/build/classes/java/main/net/minecraft/src/GuiAchievements.class deleted file mode 100644 index 1a7b4be..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiAchievements.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiBeacon.class b/build/classes/java/main/net/minecraft/src/GuiBeacon.class deleted file mode 100644 index a8c4788..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiBeacon.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiBeaconButton.class b/build/classes/java/main/net/minecraft/src/GuiBeaconButton.class deleted file mode 100644 index a7f202a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiBeaconButton.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiBeaconButtonCancel.class b/build/classes/java/main/net/minecraft/src/GuiBeaconButtonCancel.class deleted file mode 100644 index 1b1e8ad..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiBeaconButtonCancel.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiBeaconButtonConfirm.class b/build/classes/java/main/net/minecraft/src/GuiBeaconButtonConfirm.class deleted file mode 100644 index d42ba74..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiBeaconButtonConfirm.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiBeaconButtonPower.class b/build/classes/java/main/net/minecraft/src/GuiBeaconButtonPower.class deleted file mode 100644 index c49c4af..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiBeaconButtonPower.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiBrewingStand.class b/build/classes/java/main/net/minecraft/src/GuiBrewingStand.class deleted file mode 100644 index 0d9c90b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiBrewingStand.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiButton.class b/build/classes/java/main/net/minecraft/src/GuiButton.class deleted file mode 100644 index 83bfb7f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiButton.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiButtonLanguage.class b/build/classes/java/main/net/minecraft/src/GuiButtonLanguage.class deleted file mode 100644 index de877d6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiButtonLanguage.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiButtonLink.class b/build/classes/java/main/net/minecraft/src/GuiButtonLink.class deleted file mode 100644 index 767d7f9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiButtonLink.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiButtonMerchant.class b/build/classes/java/main/net/minecraft/src/GuiButtonMerchant.class deleted file mode 100644 index 16c15bc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiButtonMerchant.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiButtonNextPage.class b/build/classes/java/main/net/minecraft/src/GuiButtonNextPage.class deleted file mode 100644 index 60af923..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiButtonNextPage.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiChat.class b/build/classes/java/main/net/minecraft/src/GuiChat.class deleted file mode 100644 index 1bad810..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiChat.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiChest.class b/build/classes/java/main/net/minecraft/src/GuiChest.class deleted file mode 100644 index f84144d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiChest.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiCommandBlock.class b/build/classes/java/main/net/minecraft/src/GuiCommandBlock.class deleted file mode 100644 index 9d5c88b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiCommandBlock.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiConfirmOpenLink.class b/build/classes/java/main/net/minecraft/src/GuiConfirmOpenLink.class deleted file mode 100644 index bd3ae10..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiConfirmOpenLink.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiConnecting.class b/build/classes/java/main/net/minecraft/src/GuiConnecting.class deleted file mode 100644 index 205acc7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiConnecting.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiContainer.class b/build/classes/java/main/net/minecraft/src/GuiContainer.class deleted file mode 100644 index a97c2fa..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiContainer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiContainerCreative.class b/build/classes/java/main/net/minecraft/src/GuiContainerCreative.class deleted file mode 100644 index 9c46656..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiContainerCreative.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiControls.class b/build/classes/java/main/net/minecraft/src/GuiControls.class deleted file mode 100644 index 25ea0aa..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiControls.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiCrafting.class b/build/classes/java/main/net/minecraft/src/GuiCrafting.class deleted file mode 100644 index 1bf8c0e4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiCrafting.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiCreateFlatWorld.class b/build/classes/java/main/net/minecraft/src/GuiCreateFlatWorld.class deleted file mode 100644 index 4790901..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiCreateFlatWorld.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiCreateFlatWorldListSlot.class b/build/classes/java/main/net/minecraft/src/GuiCreateFlatWorldListSlot.class deleted file mode 100644 index de9ebd0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiCreateFlatWorldListSlot.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiCreateWorld.class b/build/classes/java/main/net/minecraft/src/GuiCreateWorld.class deleted file mode 100644 index 5494ce9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiCreateWorld.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiDisconnected.class b/build/classes/java/main/net/minecraft/src/GuiDisconnected.class deleted file mode 100644 index 4b6d792..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiDisconnected.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiDispenser.class b/build/classes/java/main/net/minecraft/src/GuiDispenser.class deleted file mode 100644 index 27b4017..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiDispenser.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiDownloadTerrain.class b/build/classes/java/main/net/minecraft/src/GuiDownloadTerrain.class deleted file mode 100644 index ee49dcd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiDownloadTerrain.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiEditSign.class b/build/classes/java/main/net/minecraft/src/GuiEditSign.class deleted file mode 100644 index a0185b1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiEditSign.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiEnchantment.class b/build/classes/java/main/net/minecraft/src/GuiEnchantment.class deleted file mode 100644 index f15e4df..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiEnchantment.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiErrorScreen.class b/build/classes/java/main/net/minecraft/src/GuiErrorScreen.class deleted file mode 100644 index 400b957..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiErrorScreen.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiFlatPresets.class b/build/classes/java/main/net/minecraft/src/GuiFlatPresets.class deleted file mode 100644 index eb84016..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiFlatPresets.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiFlatPresetsItem.class b/build/classes/java/main/net/minecraft/src/GuiFlatPresetsItem.class deleted file mode 100644 index 9947955..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiFlatPresetsItem.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiFlatPresetsListSlot.class b/build/classes/java/main/net/minecraft/src/GuiFlatPresetsListSlot.class deleted file mode 100644 index cc336c3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiFlatPresetsListSlot.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiFurnace.class b/build/classes/java/main/net/minecraft/src/GuiFurnace.class deleted file mode 100644 index 0e50b7d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiFurnace.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiGameOver.class b/build/classes/java/main/net/minecraft/src/GuiGameOver.class deleted file mode 100644 index a896634..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiGameOver.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiHopper.class b/build/classes/java/main/net/minecraft/src/GuiHopper.class deleted file mode 100644 index a6743cb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiHopper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiIngame.class b/build/classes/java/main/net/minecraft/src/GuiIngame.class deleted file mode 100644 index 1bc2e10..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiIngame.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiIngameMenu.class b/build/classes/java/main/net/minecraft/src/GuiIngameMenu.class deleted file mode 100644 index ffdd692..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiIngameMenu.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiInventory.class b/build/classes/java/main/net/minecraft/src/GuiInventory.class deleted file mode 100644 index 56dc80d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiInventory.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiLanguage.class b/build/classes/java/main/net/minecraft/src/GuiLanguage.class deleted file mode 100644 index cd9b1e1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiLanguage.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiMainMenu.class b/build/classes/java/main/net/minecraft/src/GuiMainMenu.class deleted file mode 100644 index 38d5b6c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiMainMenu.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiMemoryErrorScreen.class b/build/classes/java/main/net/minecraft/src/GuiMemoryErrorScreen.class deleted file mode 100644 index 535443d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiMemoryErrorScreen.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiMerchant.class b/build/classes/java/main/net/minecraft/src/GuiMerchant.class deleted file mode 100644 index d9f9995..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiMerchant.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiMultiplayer.class b/build/classes/java/main/net/minecraft/src/GuiMultiplayer.class deleted file mode 100644 index febb6de..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiMultiplayer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiNewChat.class b/build/classes/java/main/net/minecraft/src/GuiNewChat.class deleted file mode 100644 index 427f04f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiNewChat.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiOptions.class b/build/classes/java/main/net/minecraft/src/GuiOptions.class deleted file mode 100644 index fcfe016..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiOptions.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiPlayerInfo.class b/build/classes/java/main/net/minecraft/src/GuiPlayerInfo.class deleted file mode 100644 index d719575..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiPlayerInfo.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiRenameWorld.class b/build/classes/java/main/net/minecraft/src/GuiRenameWorld.class deleted file mode 100644 index c00303d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiRenameWorld.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiRepair.class b/build/classes/java/main/net/minecraft/src/GuiRepair.class deleted file mode 100644 index 735d990..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiRepair.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreen.class b/build/classes/java/main/net/minecraft/src/GuiScreen.class deleted file mode 100644 index f9c9405..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreen.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenAddServer.class b/build/classes/java/main/net/minecraft/src/GuiScreenAddServer.class deleted file mode 100644 index dce3bc1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenAddServer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenBackup.class b/build/classes/java/main/net/minecraft/src/GuiScreenBackup.class deleted file mode 100644 index efa6018..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenBackup.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenBackupDownloadThread.class b/build/classes/java/main/net/minecraft/src/GuiScreenBackupDownloadThread.class deleted file mode 100644 index 4c62f93..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenBackupDownloadThread.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenBackupRestoreTask.class b/build/classes/java/main/net/minecraft/src/GuiScreenBackupRestoreTask.class deleted file mode 100644 index 89f9c55..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenBackupRestoreTask.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenBackupSelectionList.class b/build/classes/java/main/net/minecraft/src/GuiScreenBackupSelectionList.class deleted file mode 100644 index 1c8e4f3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenBackupSelectionList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenBook.class b/build/classes/java/main/net/minecraft/src/GuiScreenBook.class deleted file mode 100644 index 3f0528f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenBook.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenClientOutdated.class b/build/classes/java/main/net/minecraft/src/GuiScreenClientOutdated.class deleted file mode 100644 index 27b2d7b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenClientOutdated.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenConfigureWorld.class b/build/classes/java/main/net/minecraft/src/GuiScreenConfigureWorld.class deleted file mode 100644 index b9deb8f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenConfigureWorld.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenConfirmation.class b/build/classes/java/main/net/minecraft/src/GuiScreenConfirmation.class deleted file mode 100644 index 18668c6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenConfirmation.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenConfirmationType.class b/build/classes/java/main/net/minecraft/src/GuiScreenConfirmationType.class deleted file mode 100644 index 27904eb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenConfirmationType.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenCreateOnlineWorld.class b/build/classes/java/main/net/minecraft/src/GuiScreenCreateOnlineWorld.class deleted file mode 100644 index bfec2ab..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenCreateOnlineWorld.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenDemo.class b/build/classes/java/main/net/minecraft/src/GuiScreenDemo.class deleted file mode 100644 index 795b305..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenDemo.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenDisconnectedOnline.class b/build/classes/java/main/net/minecraft/src/GuiScreenDisconnectedOnline.class deleted file mode 100644 index 6edbdce..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenDisconnectedOnline.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenEditOnlineWorld.class b/build/classes/java/main/net/minecraft/src/GuiScreenEditOnlineWorld.class deleted file mode 100644 index 16584fa..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenEditOnlineWorld.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenHorseInventory.class b/build/classes/java/main/net/minecraft/src/GuiScreenHorseInventory.class deleted file mode 100644 index 7896bae..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenHorseInventory.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenInvite.class b/build/classes/java/main/net/minecraft/src/GuiScreenInvite.class deleted file mode 100644 index a21e7b1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenInvite.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenLongRunningTask.class b/build/classes/java/main/net/minecraft/src/GuiScreenLongRunningTask.class deleted file mode 100644 index 85d5395..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenLongRunningTask.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenMcoWorldTemplate.class b/build/classes/java/main/net/minecraft/src/GuiScreenMcoWorldTemplate.class deleted file mode 100644 index 8c788d8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenMcoWorldTemplate.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenMcoWorldTemplateDownloadThread.class b/build/classes/java/main/net/minecraft/src/GuiScreenMcoWorldTemplateDownloadThread.class deleted file mode 100644 index 6b88b20..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenMcoWorldTemplateDownloadThread.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenMcoWorldTemplateSelectionList.class b/build/classes/java/main/net/minecraft/src/GuiScreenMcoWorldTemplateSelectionList.class deleted file mode 100644 index 9f389e4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenMcoWorldTemplateSelectionList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenOnlineServers.class b/build/classes/java/main/net/minecraft/src/GuiScreenOnlineServers.class deleted file mode 100644 index 6d61b28..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenOnlineServers.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenOnlineServersSubscreen.class b/build/classes/java/main/net/minecraft/src/GuiScreenOnlineServersSubscreen.class deleted file mode 100644 index 172e949..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenOnlineServersSubscreen.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenPendingInvitation.class b/build/classes/java/main/net/minecraft/src/GuiScreenPendingInvitation.class deleted file mode 100644 index 4f2b312..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenPendingInvitation.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenPendingInvitationINNER1.class b/build/classes/java/main/net/minecraft/src/GuiScreenPendingInvitationINNER1.class deleted file mode 100644 index 83871c7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenPendingInvitationINNER1.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenPendingInvitationINNER2.class b/build/classes/java/main/net/minecraft/src/GuiScreenPendingInvitationINNER2.class deleted file mode 100644 index 48117e5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenPendingInvitationINNER2.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenPendingInvitationINNER3.class b/build/classes/java/main/net/minecraft/src/GuiScreenPendingInvitationINNER3.class deleted file mode 100644 index 25a4144..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenPendingInvitationINNER3.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenPendingInvitationList.class b/build/classes/java/main/net/minecraft/src/GuiScreenPendingInvitationList.class deleted file mode 100644 index 47db8de..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenPendingInvitationList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenResetWorld.class b/build/classes/java/main/net/minecraft/src/GuiScreenResetWorld.class deleted file mode 100644 index f3cbb7e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenResetWorld.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenSelectLocation.class b/build/classes/java/main/net/minecraft/src/GuiScreenSelectLocation.class deleted file mode 100644 index 03c4d70..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenSelectLocation.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenServerList.class b/build/classes/java/main/net/minecraft/src/GuiScreenServerList.class deleted file mode 100644 index dd40f14..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenServerList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenSubscription.class b/build/classes/java/main/net/minecraft/src/GuiScreenSubscription.class deleted file mode 100644 index e21e6fc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenSubscription.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenTemporaryResourcePackSelect.class b/build/classes/java/main/net/minecraft/src/GuiScreenTemporaryResourcePackSelect.class deleted file mode 100644 index 534dc62..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenTemporaryResourcePackSelect.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiScreenTemporaryResourcePackSelectSelectionList.class b/build/classes/java/main/net/minecraft/src/GuiScreenTemporaryResourcePackSelectSelectionList.class deleted file mode 100644 index 74cefcf..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiScreenTemporaryResourcePackSelectSelectionList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiSelectWorld.class b/build/classes/java/main/net/minecraft/src/GuiSelectWorld.class deleted file mode 100644 index b26926b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiSelectWorld.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiShareToLan.class b/build/classes/java/main/net/minecraft/src/GuiShareToLan.class deleted file mode 100644 index b5ddb9c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiShareToLan.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiSleepMP.class b/build/classes/java/main/net/minecraft/src/GuiSleepMP.class deleted file mode 100644 index 8144d09..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiSleepMP.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiSlider.class b/build/classes/java/main/net/minecraft/src/GuiSlider.class deleted file mode 100644 index d3f8dc3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiSlider.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiSlot.class b/build/classes/java/main/net/minecraft/src/GuiSlot.class deleted file mode 100644 index ee87af0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiSlot.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiSlotLanguage.class b/build/classes/java/main/net/minecraft/src/GuiSlotLanguage.class deleted file mode 100644 index 494f737..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiSlotLanguage.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiSlotOnlineServerList.class b/build/classes/java/main/net/minecraft/src/GuiSlotOnlineServerList.class deleted file mode 100644 index aea2d71..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiSlotOnlineServerList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiSlotServer.class b/build/classes/java/main/net/minecraft/src/GuiSlotServer.class deleted file mode 100644 index 76d4694..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiSlotServer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiSlotStats.class b/build/classes/java/main/net/minecraft/src/GuiSlotStats.class deleted file mode 100644 index dcbedcd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiSlotStats.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiSlotStatsBlock.class b/build/classes/java/main/net/minecraft/src/GuiSlotStatsBlock.class deleted file mode 100644 index 438c1a3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiSlotStatsBlock.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiSlotStatsGeneral.class b/build/classes/java/main/net/minecraft/src/GuiSlotStatsGeneral.class deleted file mode 100644 index 6d53a9b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiSlotStatsGeneral.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiSlotStatsItem.class b/build/classes/java/main/net/minecraft/src/GuiSlotStatsItem.class deleted file mode 100644 index cdf7b49..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiSlotStatsItem.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiSmallButton.class b/build/classes/java/main/net/minecraft/src/GuiSmallButton.class deleted file mode 100644 index b80cfe4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiSmallButton.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiSnooper.class b/build/classes/java/main/net/minecraft/src/GuiSnooper.class deleted file mode 100644 index 978164f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiSnooper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiSnooperList.class b/build/classes/java/main/net/minecraft/src/GuiSnooperList.class deleted file mode 100644 index 3084f9e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiSnooperList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiStats.class b/build/classes/java/main/net/minecraft/src/GuiStats.class deleted file mode 100644 index fafaf4d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiStats.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiTextField.class b/build/classes/java/main/net/minecraft/src/GuiTextField.class deleted file mode 100644 index 4f3ae53..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiTextField.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiVideoSettings.class b/build/classes/java/main/net/minecraft/src/GuiVideoSettings.class deleted file mode 100644 index fbfa469..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiVideoSettings.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiWinGame.class b/build/classes/java/main/net/minecraft/src/GuiWinGame.class deleted file mode 100644 index 8d37729..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiWinGame.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiWorldSlot.class b/build/classes/java/main/net/minecraft/src/GuiWorldSlot.class deleted file mode 100644 index 91c2180..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiWorldSlot.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/GuiYesNo.class b/build/classes/java/main/net/minecraft/src/GuiYesNo.class deleted file mode 100644 index 3855e2c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/GuiYesNo.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Hopper.class b/build/classes/java/main/net/minecraft/src/Hopper.class deleted file mode 100644 index 5db182c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Hopper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/HttpUtil.class b/build/classes/java/main/net/minecraft/src/HttpUtil.class deleted file mode 100644 index 36edaec..0000000 Binary files a/build/classes/java/main/net/minecraft/src/HttpUtil.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/I18n.class b/build/classes/java/main/net/minecraft/src/I18n.class deleted file mode 100644 index 8a7110c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/I18n.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IAdminCommand.class b/build/classes/java/main/net/minecraft/src/IAdminCommand.class deleted file mode 100644 index 8008d65..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IAdminCommand.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IAnimals.class b/build/classes/java/main/net/minecraft/src/IAnimals.class deleted file mode 100644 index 7cbc2cb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IAnimals.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IBehaviorDispenseItem.class b/build/classes/java/main/net/minecraft/src/IBehaviorDispenseItem.class deleted file mode 100644 index d271872..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IBehaviorDispenseItem.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IBlockAccess.class b/build/classes/java/main/net/minecraft/src/IBlockAccess.class deleted file mode 100644 index 79dae44..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IBlockAccess.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IBlockSource.class b/build/classes/java/main/net/minecraft/src/IBlockSource.class deleted file mode 100644 index 79c4084..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IBlockSource.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IBossDisplayData.class b/build/classes/java/main/net/minecraft/src/IBossDisplayData.class deleted file mode 100644 index 61b3774..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IBossDisplayData.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ICamera.class b/build/classes/java/main/net/minecraft/src/ICamera.class deleted file mode 100644 index 4629949..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ICamera.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IChunkLoader.class b/build/classes/java/main/net/minecraft/src/IChunkLoader.class deleted file mode 100644 index 9aee9be..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IChunkLoader.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IChunkProvider.class b/build/classes/java/main/net/minecraft/src/IChunkProvider.class deleted file mode 100644 index 0a5f2e9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IChunkProvider.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ICommand.class b/build/classes/java/main/net/minecraft/src/ICommand.class deleted file mode 100644 index 04fdb90..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ICommand.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ICommandManager.class b/build/classes/java/main/net/minecraft/src/ICommandManager.class deleted file mode 100644 index d448bf9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ICommandManager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ICommandSender.class b/build/classes/java/main/net/minecraft/src/ICommandSender.class deleted file mode 100644 index 021f17a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ICommandSender.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ICrafting.class b/build/classes/java/main/net/minecraft/src/ICrafting.class deleted file mode 100644 index 2878d55..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ICrafting.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IEnchantmentModifier.class b/build/classes/java/main/net/minecraft/src/IEnchantmentModifier.class deleted file mode 100644 index 7c001e0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IEnchantmentModifier.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IEntityMultiPart.class b/build/classes/java/main/net/minecraft/src/IEntityMultiPart.class deleted file mode 100644 index c6d0aad..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IEntityMultiPart.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IEntitySelector.class b/build/classes/java/main/net/minecraft/src/IEntitySelector.class deleted file mode 100644 index 5e7cd8e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IEntitySelector.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IImageBuffer.class b/build/classes/java/main/net/minecraft/src/IImageBuffer.class deleted file mode 100644 index 785b964..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IImageBuffer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IInvBasic.class b/build/classes/java/main/net/minecraft/src/IInvBasic.class deleted file mode 100644 index 6441177..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IInvBasic.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IInventory.class b/build/classes/java/main/net/minecraft/src/IInventory.class deleted file mode 100644 index 64aad48..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IInventory.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ILocatableSource.class b/build/classes/java/main/net/minecraft/src/ILocatableSource.class deleted file mode 100644 index eb9a7c0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ILocatableSource.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ILocation.class b/build/classes/java/main/net/minecraft/src/ILocation.class deleted file mode 100644 index 0576a74..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ILocation.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ILogAgent.class b/build/classes/java/main/net/minecraft/src/ILogAgent.class deleted file mode 100644 index 18f7ed2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ILogAgent.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IMerchant.class b/build/classes/java/main/net/minecraft/src/IMerchant.class deleted file mode 100644 index e54ed2f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IMerchant.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IMob.class b/build/classes/java/main/net/minecraft/src/IMob.class deleted file mode 100644 index f23f07f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IMob.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/INetworkManager.class b/build/classes/java/main/net/minecraft/src/INetworkManager.class deleted file mode 100644 index 47b3034..0000000 Binary files a/build/classes/java/main/net/minecraft/src/INetworkManager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/INpc.class b/build/classes/java/main/net/minecraft/src/INpc.class deleted file mode 100644 index 9271c2e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/INpc.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IPlayerFileData.class b/build/classes/java/main/net/minecraft/src/IPlayerFileData.class deleted file mode 100644 index f94fa06..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IPlayerFileData.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IPlayerUsage.class b/build/classes/java/main/net/minecraft/src/IPlayerUsage.class deleted file mode 100644 index ba7063d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IPlayerUsage.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IPosition.class b/build/classes/java/main/net/minecraft/src/IPosition.class deleted file mode 100644 index e216206..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IPosition.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IProgressUpdate.class b/build/classes/java/main/net/minecraft/src/IProgressUpdate.class deleted file mode 100644 index e6451cf..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IProgressUpdate.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IProjectile.class b/build/classes/java/main/net/minecraft/src/IProjectile.class deleted file mode 100644 index a2c72a4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IProjectile.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IRangedAttackMob.class b/build/classes/java/main/net/minecraft/src/IRangedAttackMob.class deleted file mode 100644 index 08920c2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IRangedAttackMob.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IRecipe.class b/build/classes/java/main/net/minecraft/src/IRecipe.class deleted file mode 100644 index fd7247d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IRecipe.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IRegistry.class b/build/classes/java/main/net/minecraft/src/IRegistry.class deleted file mode 100644 index 2e916a1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IRegistry.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ISaveFormat.class b/build/classes/java/main/net/minecraft/src/ISaveFormat.class deleted file mode 100644 index 700f9d3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ISaveFormat.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ISaveHandler.class b/build/classes/java/main/net/minecraft/src/ISaveHandler.class deleted file mode 100644 index fdccc2e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ISaveHandler.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IServer.class b/build/classes/java/main/net/minecraft/src/IServer.class deleted file mode 100644 index a44d439..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IServer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ISidedInventory.class b/build/classes/java/main/net/minecraft/src/ISidedInventory.class deleted file mode 100644 index 56e0bf1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ISidedInventory.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IStatStringFormat.class b/build/classes/java/main/net/minecraft/src/IStatStringFormat.class deleted file mode 100644 index 92be0d1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IStatStringFormat.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IStatType.class b/build/classes/java/main/net/minecraft/src/IStatType.class deleted file mode 100644 index 40164aa..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IStatType.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IThreadedFileIO.class b/build/classes/java/main/net/minecraft/src/IThreadedFileIO.class deleted file mode 100644 index 4707dd1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IThreadedFileIO.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ITileEntityProvider.class b/build/classes/java/main/net/minecraft/src/ITileEntityProvider.class deleted file mode 100644 index bd30c90..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ITileEntityProvider.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IUpdatePlayerListBox.class b/build/classes/java/main/net/minecraft/src/IUpdatePlayerListBox.class deleted file mode 100644 index c3f05c5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IUpdatePlayerListBox.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IWorldAccess.class b/build/classes/java/main/net/minecraft/src/IWorldAccess.class deleted file mode 100644 index 92f238f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IWorldAccess.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Icon.class b/build/classes/java/main/net/minecraft/src/Icon.class deleted file mode 100644 index 24a0b09..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Icon.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IconFlipped.class b/build/classes/java/main/net/minecraft/src/IconFlipped.class deleted file mode 100644 index 61ed20c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IconFlipped.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IconRegister.class b/build/classes/java/main/net/minecraft/src/IconRegister.class deleted file mode 100644 index 43f3947..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IconRegister.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ImageBufferDownload.class b/build/classes/java/main/net/minecraft/src/ImageBufferDownload.class deleted file mode 100644 index 7290d05..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ImageBufferDownload.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IntCache.class b/build/classes/java/main/net/minecraft/src/IntCache.class deleted file mode 100644 index 3ee6401..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IntCache.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IntHashMap.class b/build/classes/java/main/net/minecraft/src/IntHashMap.class deleted file mode 100644 index e8c924e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IntHashMap.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IntHashMapEntry.class b/build/classes/java/main/net/minecraft/src/IntHashMapEntry.class deleted file mode 100644 index 808b567..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IntHashMapEntry.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IntegratedPlayerList.class b/build/classes/java/main/net/minecraft/src/IntegratedPlayerList.class deleted file mode 100644 index 6ce5f58..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IntegratedPlayerList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IntegratedServer.class b/build/classes/java/main/net/minecraft/src/IntegratedServer.class deleted file mode 100644 index 463913c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IntegratedServer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/IntegratedServerListenThread.class b/build/classes/java/main/net/minecraft/src/IntegratedServerListenThread.class deleted file mode 100644 index e6c7096..0000000 Binary files a/build/classes/java/main/net/minecraft/src/IntegratedServerListenThread.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/InventoryBasic.class b/build/classes/java/main/net/minecraft/src/InventoryBasic.class deleted file mode 100644 index 31c0a47..0000000 Binary files a/build/classes/java/main/net/minecraft/src/InventoryBasic.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/InventoryCraftResult.class b/build/classes/java/main/net/minecraft/src/InventoryCraftResult.class deleted file mode 100644 index c5721fb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/InventoryCraftResult.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/InventoryCrafting.class b/build/classes/java/main/net/minecraft/src/InventoryCrafting.class deleted file mode 100644 index eee8c43..0000000 Binary files a/build/classes/java/main/net/minecraft/src/InventoryCrafting.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/InventoryEffectRenderer.class b/build/classes/java/main/net/minecraft/src/InventoryEffectRenderer.class deleted file mode 100644 index 4ddf0fa..0000000 Binary files a/build/classes/java/main/net/minecraft/src/InventoryEffectRenderer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/InventoryEnderChest.class b/build/classes/java/main/net/minecraft/src/InventoryEnderChest.class deleted file mode 100644 index d72eb15..0000000 Binary files a/build/classes/java/main/net/minecraft/src/InventoryEnderChest.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/InventoryLargeChest.class b/build/classes/java/main/net/minecraft/src/InventoryLargeChest.class deleted file mode 100644 index 759eeb5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/InventoryLargeChest.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/InventoryMerchant.class b/build/classes/java/main/net/minecraft/src/InventoryMerchant.class deleted file mode 100644 index e9d9661..0000000 Binary files a/build/classes/java/main/net/minecraft/src/InventoryMerchant.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/InventoryPlayer.class b/build/classes/java/main/net/minecraft/src/InventoryPlayer.class deleted file mode 100644 index a20086b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/InventoryPlayer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Item.class b/build/classes/java/main/net/minecraft/src/Item.class deleted file mode 100644 index d33117e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Item.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemAnvilBlock.class b/build/classes/java/main/net/minecraft/src/ItemAnvilBlock.class deleted file mode 100644 index 8d383cf..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemAnvilBlock.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemAppleGold.class b/build/classes/java/main/net/minecraft/src/ItemAppleGold.class deleted file mode 100644 index a0fc6af..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemAppleGold.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemArmor.class b/build/classes/java/main/net/minecraft/src/ItemArmor.class deleted file mode 100644 index 31b34cb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemArmor.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemAxe.class b/build/classes/java/main/net/minecraft/src/ItemAxe.class deleted file mode 100644 index 71abf85..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemAxe.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemBed.class b/build/classes/java/main/net/minecraft/src/ItemBed.class deleted file mode 100644 index 63481c8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemBed.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemBlock.class b/build/classes/java/main/net/minecraft/src/ItemBlock.class deleted file mode 100644 index 8ab88c6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemBlock.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemBlockWithMetadata.class b/build/classes/java/main/net/minecraft/src/ItemBlockWithMetadata.class deleted file mode 100644 index cf75651..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemBlockWithMetadata.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemBoat.class b/build/classes/java/main/net/minecraft/src/ItemBoat.class deleted file mode 100644 index 1d0757f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemBoat.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemBook.class b/build/classes/java/main/net/minecraft/src/ItemBook.class deleted file mode 100644 index e91859b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemBook.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemBow.class b/build/classes/java/main/net/minecraft/src/ItemBow.class deleted file mode 100644 index 7c5b720..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemBow.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemBucket.class b/build/classes/java/main/net/minecraft/src/ItemBucket.class deleted file mode 100644 index f97082f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemBucket.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemBucketMilk.class b/build/classes/java/main/net/minecraft/src/ItemBucketMilk.class deleted file mode 100644 index 61b22e0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemBucketMilk.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemCarrotOnAStick.class b/build/classes/java/main/net/minecraft/src/ItemCarrotOnAStick.class deleted file mode 100644 index c3bccf3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemCarrotOnAStick.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemCloth.class b/build/classes/java/main/net/minecraft/src/ItemCloth.class deleted file mode 100644 index f4da7ee..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemCloth.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemCoal.class b/build/classes/java/main/net/minecraft/src/ItemCoal.class deleted file mode 100644 index 2af48e2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemCoal.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemColored.class b/build/classes/java/main/net/minecraft/src/ItemColored.class deleted file mode 100644 index f9aa085..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemColored.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemDoor.class b/build/classes/java/main/net/minecraft/src/ItemDoor.class deleted file mode 100644 index e07fe01..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemDoor.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemDye.class b/build/classes/java/main/net/minecraft/src/ItemDye.class deleted file mode 100644 index 1ddda4e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemDye.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemEditableBook.class b/build/classes/java/main/net/minecraft/src/ItemEditableBook.class deleted file mode 100644 index c5f1024..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemEditableBook.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemEgg.class b/build/classes/java/main/net/minecraft/src/ItemEgg.class deleted file mode 100644 index e1b6fe8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemEgg.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemEmptyMap.class b/build/classes/java/main/net/minecraft/src/ItemEmptyMap.class deleted file mode 100644 index 2bee504..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemEmptyMap.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemEnchantedBook.class b/build/classes/java/main/net/minecraft/src/ItemEnchantedBook.class deleted file mode 100644 index fa03a50..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemEnchantedBook.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemEnderEye.class b/build/classes/java/main/net/minecraft/src/ItemEnderEye.class deleted file mode 100644 index 09daa1e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemEnderEye.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemEnderPearl.class b/build/classes/java/main/net/minecraft/src/ItemEnderPearl.class deleted file mode 100644 index ab6a73b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemEnderPearl.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemExpBottle.class b/build/classes/java/main/net/minecraft/src/ItemExpBottle.class deleted file mode 100644 index 4f649bb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemExpBottle.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemFireball.class b/build/classes/java/main/net/minecraft/src/ItemFireball.class deleted file mode 100644 index 90f70ec..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemFireball.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemFirework.class b/build/classes/java/main/net/minecraft/src/ItemFirework.class deleted file mode 100644 index 9f99d5e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemFirework.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemFireworkCharge.class b/build/classes/java/main/net/minecraft/src/ItemFireworkCharge.class deleted file mode 100644 index 0696eaf..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemFireworkCharge.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemFishingRod.class b/build/classes/java/main/net/minecraft/src/ItemFishingRod.class deleted file mode 100644 index bce932c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemFishingRod.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemFlintAndSteel.class b/build/classes/java/main/net/minecraft/src/ItemFlintAndSteel.class deleted file mode 100644 index d6e951a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemFlintAndSteel.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemFood.class b/build/classes/java/main/net/minecraft/src/ItemFood.class deleted file mode 100644 index f38cb7c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemFood.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemGlassBottle.class b/build/classes/java/main/net/minecraft/src/ItemGlassBottle.class deleted file mode 100644 index 219ae7c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemGlassBottle.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemHangingEntity.class b/build/classes/java/main/net/minecraft/src/ItemHangingEntity.class deleted file mode 100644 index 1c0d453..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemHangingEntity.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemHoe.class b/build/classes/java/main/net/minecraft/src/ItemHoe.class deleted file mode 100644 index a1b6dc8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemHoe.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemInWorldManager.class b/build/classes/java/main/net/minecraft/src/ItemInWorldManager.class deleted file mode 100644 index 7f16dd7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemInWorldManager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemLeash.class b/build/classes/java/main/net/minecraft/src/ItemLeash.class deleted file mode 100644 index 5158605..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemLeash.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemLeaves.class b/build/classes/java/main/net/minecraft/src/ItemLeaves.class deleted file mode 100644 index ce4535d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemLeaves.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemLilyPad.class b/build/classes/java/main/net/minecraft/src/ItemLilyPad.class deleted file mode 100644 index 86f5229..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemLilyPad.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemMap.class b/build/classes/java/main/net/minecraft/src/ItemMap.class deleted file mode 100644 index 891e7bd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemMap.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemMapBase.class b/build/classes/java/main/net/minecraft/src/ItemMapBase.class deleted file mode 100644 index df14c99..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemMapBase.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemMinecart.class b/build/classes/java/main/net/minecraft/src/ItemMinecart.class deleted file mode 100644 index 188c89e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemMinecart.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemMonsterPlacer.class b/build/classes/java/main/net/minecraft/src/ItemMonsterPlacer.class deleted file mode 100644 index a788c8f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemMonsterPlacer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemMultiTextureTile.class b/build/classes/java/main/net/minecraft/src/ItemMultiTextureTile.class deleted file mode 100644 index dfc60f9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemMultiTextureTile.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemNameTag.class b/build/classes/java/main/net/minecraft/src/ItemNameTag.class deleted file mode 100644 index 6ef522b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemNameTag.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemPickaxe.class b/build/classes/java/main/net/minecraft/src/ItemPickaxe.class deleted file mode 100644 index 740d48c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemPickaxe.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemPiston.class b/build/classes/java/main/net/minecraft/src/ItemPiston.class deleted file mode 100644 index f8de85a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemPiston.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemPotion.class b/build/classes/java/main/net/minecraft/src/ItemPotion.class deleted file mode 100644 index 9c628b5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemPotion.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemRecord.class b/build/classes/java/main/net/minecraft/src/ItemRecord.class deleted file mode 100644 index cf5b842..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemRecord.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemRedstone.class b/build/classes/java/main/net/minecraft/src/ItemRedstone.class deleted file mode 100644 index ab57892..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemRedstone.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemReed.class b/build/classes/java/main/net/minecraft/src/ItemReed.class deleted file mode 100644 index e16bb22..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemReed.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemRenderer.class b/build/classes/java/main/net/minecraft/src/ItemRenderer.class deleted file mode 100644 index 2fb1c84..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemRenderer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemSaddle.class b/build/classes/java/main/net/minecraft/src/ItemSaddle.class deleted file mode 100644 index 717542a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemSaddle.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemSeedFood.class b/build/classes/java/main/net/minecraft/src/ItemSeedFood.class deleted file mode 100644 index 6072dff..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemSeedFood.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemSeeds.class b/build/classes/java/main/net/minecraft/src/ItemSeeds.class deleted file mode 100644 index 3da2a3c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemSeeds.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemShears.class b/build/classes/java/main/net/minecraft/src/ItemShears.class deleted file mode 100644 index f43c91e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemShears.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemSign.class b/build/classes/java/main/net/minecraft/src/ItemSign.class deleted file mode 100644 index 34962ce..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemSign.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemSimpleFoiled.class b/build/classes/java/main/net/minecraft/src/ItemSimpleFoiled.class deleted file mode 100644 index dc449ef..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemSimpleFoiled.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemSkull.class b/build/classes/java/main/net/minecraft/src/ItemSkull.class deleted file mode 100644 index aedcbae..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemSkull.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemSlab.class b/build/classes/java/main/net/minecraft/src/ItemSlab.class deleted file mode 100644 index 3411e07..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemSlab.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemSnow.class b/build/classes/java/main/net/minecraft/src/ItemSnow.class deleted file mode 100644 index d881a90..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemSnow.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemSnowball.class b/build/classes/java/main/net/minecraft/src/ItemSnowball.class deleted file mode 100644 index 9f2df02..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemSnowball.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemSoup.class b/build/classes/java/main/net/minecraft/src/ItemSoup.class deleted file mode 100644 index e2cfc18..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemSoup.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemSpade.class b/build/classes/java/main/net/minecraft/src/ItemSpade.class deleted file mode 100644 index 283244e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemSpade.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemStack.class b/build/classes/java/main/net/minecraft/src/ItemStack.class deleted file mode 100644 index 82bcf37..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemStack.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemSword.class b/build/classes/java/main/net/minecraft/src/ItemSword.class deleted file mode 100644 index 4c04b8c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemSword.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemTool.class b/build/classes/java/main/net/minecraft/src/ItemTool.class deleted file mode 100644 index 61b4982..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemTool.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ItemWritableBook.class b/build/classes/java/main/net/minecraft/src/ItemWritableBook.class deleted file mode 100644 index d57897c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ItemWritableBook.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/KeyBinding.class b/build/classes/java/main/net/minecraft/src/KeyBinding.class deleted file mode 100644 index 420e09a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/KeyBinding.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/LanServer.class b/build/classes/java/main/net/minecraft/src/LanServer.class deleted file mode 100644 index d5b1a85..0000000 Binary files a/build/classes/java/main/net/minecraft/src/LanServer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/LanServerList.class b/build/classes/java/main/net/minecraft/src/LanServerList.class deleted file mode 100644 index 2facdb6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/LanServerList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Language.class b/build/classes/java/main/net/minecraft/src/Language.class deleted file mode 100644 index 5641a80..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Language.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/LanguageManager.class b/build/classes/java/main/net/minecraft/src/LanguageManager.class deleted file mode 100644 index 3e78cd9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/LanguageManager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/LanguageMetadataSection.class b/build/classes/java/main/net/minecraft/src/LanguageMetadataSection.class deleted file mode 100644 index b0704dc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/LanguageMetadataSection.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/LanguageMetadataSectionSerializer.class b/build/classes/java/main/net/minecraft/src/LanguageMetadataSectionSerializer.class deleted file mode 100644 index e9be4de..0000000 Binary files a/build/classes/java/main/net/minecraft/src/LanguageMetadataSectionSerializer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/LayeredTexture.class b/build/classes/java/main/net/minecraft/src/LayeredTexture.class deleted file mode 100644 index 1baa5e8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/LayeredTexture.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/LoadingScreenRenderer.class b/build/classes/java/main/net/minecraft/src/LoadingScreenRenderer.class deleted file mode 100644 index e949f21..0000000 Binary files a/build/classes/java/main/net/minecraft/src/LoadingScreenRenderer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Locale.class b/build/classes/java/main/net/minecraft/src/Locale.class deleted file mode 100644 index a32445a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Locale.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/LogAgent.class b/build/classes/java/main/net/minecraft/src/LogAgent.class deleted file mode 100644 index 0fa0abd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/LogAgent.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/LogAgentEmptyAnon.class b/build/classes/java/main/net/minecraft/src/LogAgentEmptyAnon.class deleted file mode 100644 index 059241a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/LogAgentEmptyAnon.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/LogFormatter.class b/build/classes/java/main/net/minecraft/src/LogFormatter.class deleted file mode 100644 index 2f71cd8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/LogFormatter.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/LongHashMap.class b/build/classes/java/main/net/minecraft/src/LongHashMap.class deleted file mode 100644 index ed98f75..0000000 Binary files a/build/classes/java/main/net/minecraft/src/LongHashMap.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/LongHashMapEntry.class b/build/classes/java/main/net/minecraft/src/LongHashMapEntry.class deleted file mode 100644 index 93622a1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/LongHashMapEntry.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/LowerStringMap.class b/build/classes/java/main/net/minecraft/src/LowerStringMap.class deleted file mode 100644 index 9d9506e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/LowerStringMap.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MD5String.class b/build/classes/java/main/net/minecraft/src/MD5String.class deleted file mode 100644 index 305fcec..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MD5String.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MainProxyAuthenticator.class b/build/classes/java/main/net/minecraft/src/MainProxyAuthenticator.class deleted file mode 100644 index f622523..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MainProxyAuthenticator.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MainShutdownHook.class b/build/classes/java/main/net/minecraft/src/MainShutdownHook.class deleted file mode 100644 index b0bd916..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MainShutdownHook.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MapColor.class b/build/classes/java/main/net/minecraft/src/MapColor.class deleted file mode 100644 index bb52e0e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MapColor.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MapCoord.class b/build/classes/java/main/net/minecraft/src/MapCoord.class deleted file mode 100644 index 9ae64c8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MapCoord.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MapData.class b/build/classes/java/main/net/minecraft/src/MapData.class deleted file mode 100644 index 10a7b32..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MapData.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MapGenBase.class b/build/classes/java/main/net/minecraft/src/MapGenBase.class deleted file mode 100644 index b1fffdb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MapGenBase.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MapGenCaves.class b/build/classes/java/main/net/minecraft/src/MapGenCaves.class deleted file mode 100644 index 71b0617..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MapGenCaves.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MapGenCavesHell.class b/build/classes/java/main/net/minecraft/src/MapGenCavesHell.class deleted file mode 100644 index b65fc2e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MapGenCavesHell.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MapGenMineshaft.class b/build/classes/java/main/net/minecraft/src/MapGenMineshaft.class deleted file mode 100644 index 1d67ae3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MapGenMineshaft.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MapGenNetherBridge.class b/build/classes/java/main/net/minecraft/src/MapGenNetherBridge.class deleted file mode 100644 index 2bf1ee4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MapGenNetherBridge.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MapGenRavine.class b/build/classes/java/main/net/minecraft/src/MapGenRavine.class deleted file mode 100644 index cf4d9ac..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MapGenRavine.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MapGenScatteredFeature.class b/build/classes/java/main/net/minecraft/src/MapGenScatteredFeature.class deleted file mode 100644 index abef0e6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MapGenScatteredFeature.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MapGenStronghold.class b/build/classes/java/main/net/minecraft/src/MapGenStronghold.class deleted file mode 100644 index 293425a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MapGenStronghold.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MapGenStructure.class b/build/classes/java/main/net/minecraft/src/MapGenStructure.class deleted file mode 100644 index ea7856b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MapGenStructure.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MapGenStructureData.class b/build/classes/java/main/net/minecraft/src/MapGenStructureData.class deleted file mode 100644 index 7e41e0f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MapGenStructureData.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MapGenStructureIO.class b/build/classes/java/main/net/minecraft/src/MapGenStructureIO.class deleted file mode 100644 index 1767ae2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MapGenStructureIO.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MapGenVillage.class b/build/classes/java/main/net/minecraft/src/MapGenVillage.class deleted file mode 100644 index 0945764..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MapGenVillage.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MapInfo.class b/build/classes/java/main/net/minecraft/src/MapInfo.class deleted file mode 100644 index 9c71ccb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MapInfo.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MapItemRenderer.class b/build/classes/java/main/net/minecraft/src/MapItemRenderer.class deleted file mode 100644 index 4f935f0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MapItemRenderer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MapStorage.class b/build/classes/java/main/net/minecraft/src/MapStorage.class deleted file mode 100644 index db34d2d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MapStorage.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Material.class b/build/classes/java/main/net/minecraft/src/Material.class deleted file mode 100644 index 8c85a0e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Material.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MaterialLiquid.class b/build/classes/java/main/net/minecraft/src/MaterialLiquid.class deleted file mode 100644 index 5eea1e3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MaterialLiquid.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MaterialLogic.class b/build/classes/java/main/net/minecraft/src/MaterialLogic.class deleted file mode 100644 index 4c02a79..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MaterialLogic.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MaterialPortal.class b/build/classes/java/main/net/minecraft/src/MaterialPortal.class deleted file mode 100644 index 9cfefd6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MaterialPortal.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MaterialTransparent.class b/build/classes/java/main/net/minecraft/src/MaterialTransparent.class deleted file mode 100644 index ee335ec..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MaterialTransparent.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MaterialWeb.class b/build/classes/java/main/net/minecraft/src/MaterialWeb.class deleted file mode 100644 index aea5c91..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MaterialWeb.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MathHelper.class b/build/classes/java/main/net/minecraft/src/MathHelper.class deleted file mode 100644 index dcebcae..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MathHelper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/McoClient.class b/build/classes/java/main/net/minecraft/src/McoClient.class deleted file mode 100644 index 70cbaaf..0000000 Binary files a/build/classes/java/main/net/minecraft/src/McoClient.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/McoServer.class b/build/classes/java/main/net/minecraft/src/McoServer.class deleted file mode 100644 index b0a5617..0000000 Binary files a/build/classes/java/main/net/minecraft/src/McoServer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/McoServerAddress.class b/build/classes/java/main/net/minecraft/src/McoServerAddress.class deleted file mode 100644 index f9a8b69..0000000 Binary files a/build/classes/java/main/net/minecraft/src/McoServerAddress.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/McoServerList.class b/build/classes/java/main/net/minecraft/src/McoServerList.class deleted file mode 100644 index 1e3c709..0000000 Binary files a/build/classes/java/main/net/minecraft/src/McoServerList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/McoServerListEmptyAnon.class b/build/classes/java/main/net/minecraft/src/McoServerListEmptyAnon.class deleted file mode 100644 index 845beb9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/McoServerListEmptyAnon.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/McoServerListUpdateTask.class b/build/classes/java/main/net/minecraft/src/McoServerListUpdateTask.class deleted file mode 100644 index cff2b72..0000000 Binary files a/build/classes/java/main/net/minecraft/src/McoServerListUpdateTask.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/McoServerListUpdateTaskComparator.class b/build/classes/java/main/net/minecraft/src/McoServerListUpdateTaskComparator.class deleted file mode 100644 index 018840a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/McoServerListUpdateTaskComparator.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MemoryConnection.class b/build/classes/java/main/net/minecraft/src/MemoryConnection.class deleted file mode 100644 index 869dad8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MemoryConnection.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MerchantRecipe.class b/build/classes/java/main/net/minecraft/src/MerchantRecipe.class deleted file mode 100644 index 1e657fa..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MerchantRecipe.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MerchantRecipeList.class b/build/classes/java/main/net/minecraft/src/MerchantRecipeList.class deleted file mode 100644 index 905fd9a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MerchantRecipeList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MessageComponentSerializer.class b/build/classes/java/main/net/minecraft/src/MessageComponentSerializer.class deleted file mode 100644 index 17cfa02..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MessageComponentSerializer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MetadataSection.class b/build/classes/java/main/net/minecraft/src/MetadataSection.class deleted file mode 100644 index 24b178d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MetadataSection.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MetadataSectionSerializer.class b/build/classes/java/main/net/minecraft/src/MetadataSectionSerializer.class deleted file mode 100644 index ae78227..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MetadataSectionSerializer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MetadataSerializer.class b/build/classes/java/main/net/minecraft/src/MetadataSerializer.class deleted file mode 100644 index cea2c21..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MetadataSerializer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MetadataSerializerEmptyAnon.class b/build/classes/java/main/net/minecraft/src/MetadataSerializerEmptyAnon.class deleted file mode 100644 index 8d56db0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MetadataSerializerEmptyAnon.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MetadataSerializerRegistration.class b/build/classes/java/main/net/minecraft/src/MetadataSerializerRegistration.class deleted file mode 100644 index c1b734d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MetadataSerializerRegistration.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Minecraft.class b/build/classes/java/main/net/minecraft/src/Minecraft.class deleted file mode 100644 index 131038f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Minecraft.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MinecraftError.class b/build/classes/java/main/net/minecraft/src/MinecraftError.class deleted file mode 100644 index 77960ce..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MinecraftError.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MinecraftException.class b/build/classes/java/main/net/minecraft/src/MinecraftException.class deleted file mode 100644 index 238788c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MinecraftException.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MinecraftINNER13.class b/build/classes/java/main/net/minecraft/src/MinecraftINNER13.class deleted file mode 100644 index a5773a2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MinecraftINNER13.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MobSpawnerBaseLogic.class b/build/classes/java/main/net/minecraft/src/MobSpawnerBaseLogic.class deleted file mode 100644 index b0b19ba..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MobSpawnerBaseLogic.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelBase.class b/build/classes/java/main/net/minecraft/src/ModelBase.class deleted file mode 100644 index 3135740..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelBase.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelBat.class b/build/classes/java/main/net/minecraft/src/ModelBat.class deleted file mode 100644 index 5b36f65..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelBat.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelBiped.class b/build/classes/java/main/net/minecraft/src/ModelBiped.class deleted file mode 100644 index 2108461..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelBiped.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelBlaze.class b/build/classes/java/main/net/minecraft/src/ModelBlaze.class deleted file mode 100644 index b1b5058..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelBlaze.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelBoat.class b/build/classes/java/main/net/minecraft/src/ModelBoat.class deleted file mode 100644 index 5b410d0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelBoat.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelBook.class b/build/classes/java/main/net/minecraft/src/ModelBook.class deleted file mode 100644 index 139191c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelBook.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelBox.class b/build/classes/java/main/net/minecraft/src/ModelBox.class deleted file mode 100644 index da1542d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelBox.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelChest.class b/build/classes/java/main/net/minecraft/src/ModelChest.class deleted file mode 100644 index dde795a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelChest.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelChicken.class b/build/classes/java/main/net/minecraft/src/ModelChicken.class deleted file mode 100644 index 645d237..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelChicken.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelCow.class b/build/classes/java/main/net/minecraft/src/ModelCow.class deleted file mode 100644 index 03f7a14..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelCow.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelCreeper.class b/build/classes/java/main/net/minecraft/src/ModelCreeper.class deleted file mode 100644 index f6ab52e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelCreeper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelDragon.class b/build/classes/java/main/net/minecraft/src/ModelDragon.class deleted file mode 100644 index ff69a60..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelDragon.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelEnderCrystal.class b/build/classes/java/main/net/minecraft/src/ModelEnderCrystal.class deleted file mode 100644 index 12a3916..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelEnderCrystal.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelEnderman.class b/build/classes/java/main/net/minecraft/src/ModelEnderman.class deleted file mode 100644 index baa5de5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelEnderman.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelGhast.class b/build/classes/java/main/net/minecraft/src/ModelGhast.class deleted file mode 100644 index 94aafb1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelGhast.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelHorse.class b/build/classes/java/main/net/minecraft/src/ModelHorse.class deleted file mode 100644 index 819e614..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelHorse.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelIronGolem.class b/build/classes/java/main/net/minecraft/src/ModelIronGolem.class deleted file mode 100644 index a74ea82..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelIronGolem.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelLargeChest.class b/build/classes/java/main/net/minecraft/src/ModelLargeChest.class deleted file mode 100644 index 702851b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelLargeChest.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelLeashKnot.class b/build/classes/java/main/net/minecraft/src/ModelLeashKnot.class deleted file mode 100644 index ae9d76a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelLeashKnot.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelMagmaCube.class b/build/classes/java/main/net/minecraft/src/ModelMagmaCube.class deleted file mode 100644 index a542548..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelMagmaCube.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelMinecart.class b/build/classes/java/main/net/minecraft/src/ModelMinecart.class deleted file mode 100644 index 43bf964..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelMinecart.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelOcelot.class b/build/classes/java/main/net/minecraft/src/ModelOcelot.class deleted file mode 100644 index ab7ecd0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelOcelot.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelPig.class b/build/classes/java/main/net/minecraft/src/ModelPig.class deleted file mode 100644 index 0c53742..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelPig.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelQuadruped.class b/build/classes/java/main/net/minecraft/src/ModelQuadruped.class deleted file mode 100644 index 8807745..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelQuadruped.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelRenderer.class b/build/classes/java/main/net/minecraft/src/ModelRenderer.class deleted file mode 100644 index 2aa9b94..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelRenderer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelSheep1.class b/build/classes/java/main/net/minecraft/src/ModelSheep1.class deleted file mode 100644 index 30cdc01..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelSheep1.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelSheep2.class b/build/classes/java/main/net/minecraft/src/ModelSheep2.class deleted file mode 100644 index 8969a6d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelSheep2.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelSign.class b/build/classes/java/main/net/minecraft/src/ModelSign.class deleted file mode 100644 index b574206..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelSign.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelSilverfish.class b/build/classes/java/main/net/minecraft/src/ModelSilverfish.class deleted file mode 100644 index 0ae1e2d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelSilverfish.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelSkeleton.class b/build/classes/java/main/net/minecraft/src/ModelSkeleton.class deleted file mode 100644 index 5c757f6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelSkeleton.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelSkeletonHead.class b/build/classes/java/main/net/minecraft/src/ModelSkeletonHead.class deleted file mode 100644 index 70e02ea..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelSkeletonHead.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelSlime.class b/build/classes/java/main/net/minecraft/src/ModelSlime.class deleted file mode 100644 index 143564d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelSlime.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelSnowMan.class b/build/classes/java/main/net/minecraft/src/ModelSnowMan.class deleted file mode 100644 index ba82671..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelSnowMan.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelSpider.class b/build/classes/java/main/net/minecraft/src/ModelSpider.class deleted file mode 100644 index 8376518..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelSpider.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelSquid.class b/build/classes/java/main/net/minecraft/src/ModelSquid.class deleted file mode 100644 index 5228a7c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelSquid.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelVillager.class b/build/classes/java/main/net/minecraft/src/ModelVillager.class deleted file mode 100644 index fd67b11..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelVillager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelWitch.class b/build/classes/java/main/net/minecraft/src/ModelWitch.class deleted file mode 100644 index f5ae563..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelWitch.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelWither.class b/build/classes/java/main/net/minecraft/src/ModelWither.class deleted file mode 100644 index fddecc2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelWither.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelWolf.class b/build/classes/java/main/net/minecraft/src/ModelWolf.class deleted file mode 100644 index 8dd37b9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelWolf.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelZombie.class b/build/classes/java/main/net/minecraft/src/ModelZombie.class deleted file mode 100644 index 0177922..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelZombie.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModelZombieVillager.class b/build/classes/java/main/net/minecraft/src/ModelZombieVillager.class deleted file mode 100644 index 8221c0c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModelZombieVillager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ModifiableAttributeInstance.class b/build/classes/java/main/net/minecraft/src/ModifiableAttributeInstance.class deleted file mode 100644 index 543bebf..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ModifiableAttributeInstance.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MouseFilter.class b/build/classes/java/main/net/minecraft/src/MouseFilter.class deleted file mode 100644 index 758790e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MouseFilter.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MouseHelper.class b/build/classes/java/main/net/minecraft/src/MouseHelper.class deleted file mode 100644 index 6ba260d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MouseHelper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MovementInput.class b/build/classes/java/main/net/minecraft/src/MovementInput.class deleted file mode 100644 index 762f269..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MovementInput.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MovementInputFromOptions.class b/build/classes/java/main/net/minecraft/src/MovementInputFromOptions.class deleted file mode 100644 index 753bec9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MovementInputFromOptions.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/MovingObjectPosition.class b/build/classes/java/main/net/minecraft/src/MovingObjectPosition.class deleted file mode 100644 index ea5af58..0000000 Binary files a/build/classes/java/main/net/minecraft/src/MovingObjectPosition.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NBTBase.class b/build/classes/java/main/net/minecraft/src/NBTBase.class deleted file mode 100644 index 5b38397..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NBTBase.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NBTTagByte.class b/build/classes/java/main/net/minecraft/src/NBTTagByte.class deleted file mode 100644 index 2ea2069..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NBTTagByte.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NBTTagByteArray.class b/build/classes/java/main/net/minecraft/src/NBTTagByteArray.class deleted file mode 100644 index d624eb6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NBTTagByteArray.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NBTTagCompound.class b/build/classes/java/main/net/minecraft/src/NBTTagCompound.class deleted file mode 100644 index 7b7c1d1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NBTTagCompound.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NBTTagDouble.class b/build/classes/java/main/net/minecraft/src/NBTTagDouble.class deleted file mode 100644 index 9e2287c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NBTTagDouble.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NBTTagEnd.class b/build/classes/java/main/net/minecraft/src/NBTTagEnd.class deleted file mode 100644 index 5869d4b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NBTTagEnd.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NBTTagFloat.class b/build/classes/java/main/net/minecraft/src/NBTTagFloat.class deleted file mode 100644 index a04f050..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NBTTagFloat.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NBTTagInt.class b/build/classes/java/main/net/minecraft/src/NBTTagInt.class deleted file mode 100644 index 5a23d34..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NBTTagInt.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NBTTagIntArray.class b/build/classes/java/main/net/minecraft/src/NBTTagIntArray.class deleted file mode 100644 index 0af3cc2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NBTTagIntArray.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NBTTagList.class b/build/classes/java/main/net/minecraft/src/NBTTagList.class deleted file mode 100644 index da6f0ed..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NBTTagList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NBTTagLong.class b/build/classes/java/main/net/minecraft/src/NBTTagLong.class deleted file mode 100644 index 5431269..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NBTTagLong.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NBTTagShort.class b/build/classes/java/main/net/minecraft/src/NBTTagShort.class deleted file mode 100644 index 65f2a4e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NBTTagShort.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NBTTagString.class b/build/classes/java/main/net/minecraft/src/NBTTagString.class deleted file mode 100644 index 1b179d8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NBTTagString.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NetClientHandler.class b/build/classes/java/main/net/minecraft/src/NetClientHandler.class deleted file mode 100644 index f13a8db..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NetClientHandler.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NetHandler.class b/build/classes/java/main/net/minecraft/src/NetHandler.class deleted file mode 100644 index 4c9c7ba..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NetHandler.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NetLoginHandler.class b/build/classes/java/main/net/minecraft/src/NetLoginHandler.class deleted file mode 100644 index 7158a4e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NetLoginHandler.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NetServerHandler.class b/build/classes/java/main/net/minecraft/src/NetServerHandler.class deleted file mode 100644 index a9d9b90..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NetServerHandler.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NetworkListenThread.class b/build/classes/java/main/net/minecraft/src/NetworkListenThread.class deleted file mode 100644 index 96ee0b7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NetworkListenThread.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NextTickListEntry.class b/build/classes/java/main/net/minecraft/src/NextTickListEntry.class deleted file mode 100644 index 3104deb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NextTickListEntry.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NibbleArray.class b/build/classes/java/main/net/minecraft/src/NibbleArray.class deleted file mode 100644 index b9adbb1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NibbleArray.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NibbleArrayReader.class b/build/classes/java/main/net/minecraft/src/NibbleArrayReader.class deleted file mode 100644 index a6c560d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NibbleArrayReader.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NoiseGenerator.class b/build/classes/java/main/net/minecraft/src/NoiseGenerator.class deleted file mode 100644 index 08b4e0f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NoiseGenerator.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NoiseGeneratorOctaves.class b/build/classes/java/main/net/minecraft/src/NoiseGeneratorOctaves.class deleted file mode 100644 index fd85eaa..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NoiseGeneratorOctaves.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NoiseGeneratorPerlin.class b/build/classes/java/main/net/minecraft/src/NoiseGeneratorPerlin.class deleted file mode 100644 index b0fae0d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NoiseGeneratorPerlin.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NpcMerchant.class b/build/classes/java/main/net/minecraft/src/NpcMerchant.class deleted file mode 100644 index a39242d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NpcMerchant.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/NumberInvalidException.class b/build/classes/java/main/net/minecraft/src/NumberInvalidException.class deleted file mode 100644 index 2d9d34a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/NumberInvalidException.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/OpenGlCapsChecker.class b/build/classes/java/main/net/minecraft/src/OpenGlCapsChecker.class deleted file mode 100644 index 6782f44..0000000 Binary files a/build/classes/java/main/net/minecraft/src/OpenGlCapsChecker.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/OpenGlHelper.class b/build/classes/java/main/net/minecraft/src/OpenGlHelper.class deleted file mode 100644 index d9b80b7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/OpenGlHelper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PackMetadataSection.class b/build/classes/java/main/net/minecraft/src/PackMetadataSection.class deleted file mode 100644 index d3a0d67..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PackMetadataSection.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PackMetadataSectionSerializer.class b/build/classes/java/main/net/minecraft/src/PackMetadataSectionSerializer.class deleted file mode 100644 index 8db0e4e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PackMetadataSectionSerializer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet.class b/build/classes/java/main/net/minecraft/src/Packet.class deleted file mode 100644 index 4b20b38..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet0KeepAlive.class b/build/classes/java/main/net/minecraft/src/Packet0KeepAlive.class deleted file mode 100644 index 303123e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet0KeepAlive.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet100OpenWindow.class b/build/classes/java/main/net/minecraft/src/Packet100OpenWindow.class deleted file mode 100644 index b5b26b9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet100OpenWindow.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet101CloseWindow.class b/build/classes/java/main/net/minecraft/src/Packet101CloseWindow.class deleted file mode 100644 index 039f1f8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet101CloseWindow.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet102WindowClick.class b/build/classes/java/main/net/minecraft/src/Packet102WindowClick.class deleted file mode 100644 index 845dc60..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet102WindowClick.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet103SetSlot.class b/build/classes/java/main/net/minecraft/src/Packet103SetSlot.class deleted file mode 100644 index 6d542dd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet103SetSlot.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet104WindowItems.class b/build/classes/java/main/net/minecraft/src/Packet104WindowItems.class deleted file mode 100644 index d120d05..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet104WindowItems.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet105UpdateProgressbar.class b/build/classes/java/main/net/minecraft/src/Packet105UpdateProgressbar.class deleted file mode 100644 index 07dd780..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet105UpdateProgressbar.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet106Transaction.class b/build/classes/java/main/net/minecraft/src/Packet106Transaction.class deleted file mode 100644 index 548234e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet106Transaction.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet107CreativeSetSlot.class b/build/classes/java/main/net/minecraft/src/Packet107CreativeSetSlot.class deleted file mode 100644 index 41999a9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet107CreativeSetSlot.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet108EnchantItem.class b/build/classes/java/main/net/minecraft/src/Packet108EnchantItem.class deleted file mode 100644 index 6b93bb8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet108EnchantItem.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet10Flying.class b/build/classes/java/main/net/minecraft/src/Packet10Flying.class deleted file mode 100644 index db955a3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet10Flying.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet11PlayerPosition.class b/build/classes/java/main/net/minecraft/src/Packet11PlayerPosition.class deleted file mode 100644 index 2027015..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet11PlayerPosition.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet12PlayerLook.class b/build/classes/java/main/net/minecraft/src/Packet12PlayerLook.class deleted file mode 100644 index 6d0dda5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet12PlayerLook.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet130UpdateSign.class b/build/classes/java/main/net/minecraft/src/Packet130UpdateSign.class deleted file mode 100644 index d1b3095..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet130UpdateSign.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet131MapData.class b/build/classes/java/main/net/minecraft/src/Packet131MapData.class deleted file mode 100644 index 2a5c0d9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet131MapData.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet132TileEntityData.class b/build/classes/java/main/net/minecraft/src/Packet132TileEntityData.class deleted file mode 100644 index 6c87e2d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet132TileEntityData.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet133TileEditorOpen.class b/build/classes/java/main/net/minecraft/src/Packet133TileEditorOpen.class deleted file mode 100644 index 6fcf8c5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet133TileEditorOpen.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet13PlayerLookMove.class b/build/classes/java/main/net/minecraft/src/Packet13PlayerLookMove.class deleted file mode 100644 index 64ba59b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet13PlayerLookMove.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet14BlockDig.class b/build/classes/java/main/net/minecraft/src/Packet14BlockDig.class deleted file mode 100644 index fb67f3d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet14BlockDig.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet15Place.class b/build/classes/java/main/net/minecraft/src/Packet15Place.class deleted file mode 100644 index f159c31..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet15Place.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet16BlockItemSwitch.class b/build/classes/java/main/net/minecraft/src/Packet16BlockItemSwitch.class deleted file mode 100644 index aee1523..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet16BlockItemSwitch.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet17Sleep.class b/build/classes/java/main/net/minecraft/src/Packet17Sleep.class deleted file mode 100644 index 0a64b5d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet17Sleep.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet18Animation.class b/build/classes/java/main/net/minecraft/src/Packet18Animation.class deleted file mode 100644 index 593db0a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet18Animation.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet19EntityAction.class b/build/classes/java/main/net/minecraft/src/Packet19EntityAction.class deleted file mode 100644 index 798ac5a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet19EntityAction.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet1Login.class b/build/classes/java/main/net/minecraft/src/Packet1Login.class deleted file mode 100644 index 1676718..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet1Login.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet200Statistic.class b/build/classes/java/main/net/minecraft/src/Packet200Statistic.class deleted file mode 100644 index 0780c58..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet200Statistic.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet201PlayerInfo.class b/build/classes/java/main/net/minecraft/src/Packet201PlayerInfo.class deleted file mode 100644 index 7da04c1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet201PlayerInfo.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet202PlayerAbilities.class b/build/classes/java/main/net/minecraft/src/Packet202PlayerAbilities.class deleted file mode 100644 index e7682b1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet202PlayerAbilities.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet203AutoComplete.class b/build/classes/java/main/net/minecraft/src/Packet203AutoComplete.class deleted file mode 100644 index bc567ce..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet203AutoComplete.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet204ClientInfo.class b/build/classes/java/main/net/minecraft/src/Packet204ClientInfo.class deleted file mode 100644 index 9fe0605..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet204ClientInfo.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet205ClientCommand.class b/build/classes/java/main/net/minecraft/src/Packet205ClientCommand.class deleted file mode 100644 index 69cb006..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet205ClientCommand.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet206SetObjective.class b/build/classes/java/main/net/minecraft/src/Packet206SetObjective.class deleted file mode 100644 index 68394e1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet206SetObjective.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet207SetScore.class b/build/classes/java/main/net/minecraft/src/Packet207SetScore.class deleted file mode 100644 index e3936f5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet207SetScore.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet208SetDisplayObjective.class b/build/classes/java/main/net/minecraft/src/Packet208SetDisplayObjective.class deleted file mode 100644 index e0e3f82..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet208SetDisplayObjective.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet209SetPlayerTeam.class b/build/classes/java/main/net/minecraft/src/Packet209SetPlayerTeam.class deleted file mode 100644 index 642689e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet209SetPlayerTeam.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet20NamedEntitySpawn.class b/build/classes/java/main/net/minecraft/src/Packet20NamedEntitySpawn.class deleted file mode 100644 index 246cbcd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet20NamedEntitySpawn.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet22Collect.class b/build/classes/java/main/net/minecraft/src/Packet22Collect.class deleted file mode 100644 index 4076a04..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet22Collect.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet23VehicleSpawn.class b/build/classes/java/main/net/minecraft/src/Packet23VehicleSpawn.class deleted file mode 100644 index 63f3c1f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet23VehicleSpawn.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet24MobSpawn.class b/build/classes/java/main/net/minecraft/src/Packet24MobSpawn.class deleted file mode 100644 index 7e796b6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet24MobSpawn.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet250CustomPayload.class b/build/classes/java/main/net/minecraft/src/Packet250CustomPayload.class deleted file mode 100644 index 59e2638..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet250CustomPayload.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet252SharedKey.class b/build/classes/java/main/net/minecraft/src/Packet252SharedKey.class deleted file mode 100644 index 3c72870..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet252SharedKey.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet253ServerAuthData.class b/build/classes/java/main/net/minecraft/src/Packet253ServerAuthData.class deleted file mode 100644 index f6d5341..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet253ServerAuthData.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet254ServerPing.class b/build/classes/java/main/net/minecraft/src/Packet254ServerPing.class deleted file mode 100644 index d4a9f24..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet254ServerPing.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet255KickDisconnect.class b/build/classes/java/main/net/minecraft/src/Packet255KickDisconnect.class deleted file mode 100644 index b562e1f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet255KickDisconnect.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet25EntityPainting.class b/build/classes/java/main/net/minecraft/src/Packet25EntityPainting.class deleted file mode 100644 index f881e3c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet25EntityPainting.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet26EntityExpOrb.class b/build/classes/java/main/net/minecraft/src/Packet26EntityExpOrb.class deleted file mode 100644 index 776c995..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet26EntityExpOrb.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet27PlayerInput.class b/build/classes/java/main/net/minecraft/src/Packet27PlayerInput.class deleted file mode 100644 index 7cb7914..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet27PlayerInput.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet28EntityVelocity.class b/build/classes/java/main/net/minecraft/src/Packet28EntityVelocity.class deleted file mode 100644 index 1967970..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet28EntityVelocity.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet29DestroyEntity.class b/build/classes/java/main/net/minecraft/src/Packet29DestroyEntity.class deleted file mode 100644 index feead7e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet29DestroyEntity.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet2ClientProtocol.class b/build/classes/java/main/net/minecraft/src/Packet2ClientProtocol.class deleted file mode 100644 index fdaccf4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet2ClientProtocol.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet30Entity.class b/build/classes/java/main/net/minecraft/src/Packet30Entity.class deleted file mode 100644 index 742f901..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet30Entity.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet31RelEntityMove.class b/build/classes/java/main/net/minecraft/src/Packet31RelEntityMove.class deleted file mode 100644 index bd35a78..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet31RelEntityMove.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet32EntityLook.class b/build/classes/java/main/net/minecraft/src/Packet32EntityLook.class deleted file mode 100644 index 0351ced..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet32EntityLook.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet33RelEntityMoveLook.class b/build/classes/java/main/net/minecraft/src/Packet33RelEntityMoveLook.class deleted file mode 100644 index f17af50..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet33RelEntityMoveLook.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet34EntityTeleport.class b/build/classes/java/main/net/minecraft/src/Packet34EntityTeleport.class deleted file mode 100644 index bc2c5cd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet34EntityTeleport.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet35EntityHeadRotation.class b/build/classes/java/main/net/minecraft/src/Packet35EntityHeadRotation.class deleted file mode 100644 index 109faf8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet35EntityHeadRotation.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet38EntityStatus.class b/build/classes/java/main/net/minecraft/src/Packet38EntityStatus.class deleted file mode 100644 index 680e7e6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet38EntityStatus.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet39AttachEntity.class b/build/classes/java/main/net/minecraft/src/Packet39AttachEntity.class deleted file mode 100644 index 306cfb3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet39AttachEntity.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet3Chat.class b/build/classes/java/main/net/minecraft/src/Packet3Chat.class deleted file mode 100644 index 08225f3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet3Chat.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet40EntityMetadata.class b/build/classes/java/main/net/minecraft/src/Packet40EntityMetadata.class deleted file mode 100644 index 3c8d40a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet40EntityMetadata.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet41EntityEffect.class b/build/classes/java/main/net/minecraft/src/Packet41EntityEffect.class deleted file mode 100644 index 40fd510..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet41EntityEffect.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet42RemoveEntityEffect.class b/build/classes/java/main/net/minecraft/src/Packet42RemoveEntityEffect.class deleted file mode 100644 index af44d65..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet42RemoveEntityEffect.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet43Experience.class b/build/classes/java/main/net/minecraft/src/Packet43Experience.class deleted file mode 100644 index 3a94ea9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet43Experience.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet44UpdateAttributes.class b/build/classes/java/main/net/minecraft/src/Packet44UpdateAttributes.class deleted file mode 100644 index d5a342d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet44UpdateAttributes.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet44UpdateAttributesSnapshot.class b/build/classes/java/main/net/minecraft/src/Packet44UpdateAttributesSnapshot.class deleted file mode 100644 index 53591e1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet44UpdateAttributesSnapshot.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet4UpdateTime.class b/build/classes/java/main/net/minecraft/src/Packet4UpdateTime.class deleted file mode 100644 index 7508752..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet4UpdateTime.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet51MapChunk.class b/build/classes/java/main/net/minecraft/src/Packet51MapChunk.class deleted file mode 100644 index 36431db..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet51MapChunk.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet51MapChunkData.class b/build/classes/java/main/net/minecraft/src/Packet51MapChunkData.class deleted file mode 100644 index aad0a38..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet51MapChunkData.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet52MultiBlockChange.class b/build/classes/java/main/net/minecraft/src/Packet52MultiBlockChange.class deleted file mode 100644 index 0a6760b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet52MultiBlockChange.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet53BlockChange.class b/build/classes/java/main/net/minecraft/src/Packet53BlockChange.class deleted file mode 100644 index 6fe7dea..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet53BlockChange.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet54PlayNoteBlock.class b/build/classes/java/main/net/minecraft/src/Packet54PlayNoteBlock.class deleted file mode 100644 index 0cb180c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet54PlayNoteBlock.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet55BlockDestroy.class b/build/classes/java/main/net/minecraft/src/Packet55BlockDestroy.class deleted file mode 100644 index 106cd96..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet55BlockDestroy.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet56MapChunks.class b/build/classes/java/main/net/minecraft/src/Packet56MapChunks.class deleted file mode 100644 index 65e945d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet56MapChunks.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet5PlayerInventory.class b/build/classes/java/main/net/minecraft/src/Packet5PlayerInventory.class deleted file mode 100644 index e455340..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet5PlayerInventory.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet60Explosion.class b/build/classes/java/main/net/minecraft/src/Packet60Explosion.class deleted file mode 100644 index 270edd4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet60Explosion.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet61DoorChange.class b/build/classes/java/main/net/minecraft/src/Packet61DoorChange.class deleted file mode 100644 index a3bb7ab..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet61DoorChange.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet62LevelSound.class b/build/classes/java/main/net/minecraft/src/Packet62LevelSound.class deleted file mode 100644 index a6a8a6c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet62LevelSound.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet63WorldParticles.class b/build/classes/java/main/net/minecraft/src/Packet63WorldParticles.class deleted file mode 100644 index a033a92..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet63WorldParticles.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet6SpawnPosition.class b/build/classes/java/main/net/minecraft/src/Packet6SpawnPosition.class deleted file mode 100644 index 9f32ec4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet6SpawnPosition.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet70GameEvent.class b/build/classes/java/main/net/minecraft/src/Packet70GameEvent.class deleted file mode 100644 index 90cb7a9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet70GameEvent.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet71Weather.class b/build/classes/java/main/net/minecraft/src/Packet71Weather.class deleted file mode 100644 index 2c6ceb5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet71Weather.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet7UseEntity.class b/build/classes/java/main/net/minecraft/src/Packet7UseEntity.class deleted file mode 100644 index 7c75b61..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet7UseEntity.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet8UpdateHealth.class b/build/classes/java/main/net/minecraft/src/Packet8UpdateHealth.class deleted file mode 100644 index 18f27d5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet8UpdateHealth.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Packet9Respawn.class b/build/classes/java/main/net/minecraft/src/Packet9Respawn.class deleted file mode 100644 index 89f0020..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Packet9Respawn.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PacketCount.class b/build/classes/java/main/net/minecraft/src/PacketCount.class deleted file mode 100644 index df90127..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PacketCount.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Path.class b/build/classes/java/main/net/minecraft/src/Path.class deleted file mode 100644 index e8281df..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Path.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PathEntity.class b/build/classes/java/main/net/minecraft/src/PathEntity.class deleted file mode 100644 index 02ba7dd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PathEntity.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PathFinder.class b/build/classes/java/main/net/minecraft/src/PathFinder.class deleted file mode 100644 index e18d832..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PathFinder.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PathNavigate.class b/build/classes/java/main/net/minecraft/src/PathNavigate.class deleted file mode 100644 index e165049..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PathNavigate.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PathPoint.class b/build/classes/java/main/net/minecraft/src/PathPoint.class deleted file mode 100644 index 810677c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PathPoint.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PendingInvite.class b/build/classes/java/main/net/minecraft/src/PendingInvite.class deleted file mode 100644 index 6e7ee64..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PendingInvite.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PendingInvitesList.class b/build/classes/java/main/net/minecraft/src/PendingInvitesList.class deleted file mode 100644 index 38ea2d2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PendingInvitesList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PlayerCapabilities.class b/build/classes/java/main/net/minecraft/src/PlayerCapabilities.class deleted file mode 100644 index e180ee8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PlayerCapabilities.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PlayerControllerMP.class b/build/classes/java/main/net/minecraft/src/PlayerControllerMP.class deleted file mode 100644 index 4adf76d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PlayerControllerMP.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PlayerInstance.class b/build/classes/java/main/net/minecraft/src/PlayerInstance.class deleted file mode 100644 index c492b76..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PlayerInstance.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PlayerManager.class b/build/classes/java/main/net/minecraft/src/PlayerManager.class deleted file mode 100644 index deb5876..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PlayerManager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PlayerNotFoundException.class b/build/classes/java/main/net/minecraft/src/PlayerNotFoundException.class deleted file mode 100644 index e527439..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PlayerNotFoundException.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PlayerPositionComparator.class b/build/classes/java/main/net/minecraft/src/PlayerPositionComparator.class deleted file mode 100644 index 3032822..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PlayerPositionComparator.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PlayerSelector.class b/build/classes/java/main/net/minecraft/src/PlayerSelector.class deleted file mode 100644 index a9e91ef..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PlayerSelector.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PlayerUsageSnooper.class b/build/classes/java/main/net/minecraft/src/PlayerUsageSnooper.class deleted file mode 100644 index dcca6ae..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PlayerUsageSnooper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PlayerUsageSnooperThread.class b/build/classes/java/main/net/minecraft/src/PlayerUsageSnooperThread.class deleted file mode 100644 index ed981dc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PlayerUsageSnooperThread.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PortalPosition.class b/build/classes/java/main/net/minecraft/src/PortalPosition.class deleted file mode 100644 index fa2b4be..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PortalPosition.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PositionImpl.class b/build/classes/java/main/net/minecraft/src/PositionImpl.class deleted file mode 100644 index 2fc3c0d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PositionImpl.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PositionTextureVertex.class b/build/classes/java/main/net/minecraft/src/PositionTextureVertex.class deleted file mode 100644 index 1b85044..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PositionTextureVertex.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Potion.class b/build/classes/java/main/net/minecraft/src/Potion.class deleted file mode 100644 index ba0cac5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Potion.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PotionAbsoption.class b/build/classes/java/main/net/minecraft/src/PotionAbsoption.class deleted file mode 100644 index d17f51e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PotionAbsoption.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PotionAttackDamage.class b/build/classes/java/main/net/minecraft/src/PotionAttackDamage.class deleted file mode 100644 index 12d3ea1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PotionAttackDamage.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PotionEffect.class b/build/classes/java/main/net/minecraft/src/PotionEffect.class deleted file mode 100644 index 0cbcdb0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PotionEffect.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PotionHealth.class b/build/classes/java/main/net/minecraft/src/PotionHealth.class deleted file mode 100644 index 620fc88..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PotionHealth.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PotionHealthBoost.class b/build/classes/java/main/net/minecraft/src/PotionHealthBoost.class deleted file mode 100644 index 85f9706..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PotionHealthBoost.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PotionHelper.class b/build/classes/java/main/net/minecraft/src/PotionHelper.class deleted file mode 100644 index dffbad0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PotionHelper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Profiler.class b/build/classes/java/main/net/minecraft/src/Profiler.class deleted file mode 100644 index b288724..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Profiler.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ProfilerResult.class b/build/classes/java/main/net/minecraft/src/ProfilerResult.class deleted file mode 100644 index c9abe85..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ProfilerResult.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/PropertyManager.class b/build/classes/java/main/net/minecraft/src/PropertyManager.class deleted file mode 100644 index 2b6a8a7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/PropertyManager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RConConsoleSource.class b/build/classes/java/main/net/minecraft/src/RConConsoleSource.class deleted file mode 100644 index 412f575..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RConConsoleSource.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RConOutputStream.class b/build/classes/java/main/net/minecraft/src/RConOutputStream.class deleted file mode 100644 index db77cab..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RConOutputStream.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RConThreadBase.class b/build/classes/java/main/net/minecraft/src/RConThreadBase.class deleted file mode 100644 index bdac55c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RConThreadBase.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RConThreadClient.class b/build/classes/java/main/net/minecraft/src/RConThreadClient.class deleted file mode 100644 index 19719ee..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RConThreadClient.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RConThreadMain.class b/build/classes/java/main/net/minecraft/src/RConThreadMain.class deleted file mode 100644 index 9b2659c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RConThreadMain.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RConThreadQuery.class b/build/classes/java/main/net/minecraft/src/RConThreadQuery.class deleted file mode 100644 index 7e3817a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RConThreadQuery.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RConThreadQueryAuth.class b/build/classes/java/main/net/minecraft/src/RConThreadQueryAuth.class deleted file mode 100644 index 9e025ae..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RConThreadQueryAuth.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RConUtils.class b/build/classes/java/main/net/minecraft/src/RConUtils.class deleted file mode 100644 index fb727bd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RConUtils.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RandomPositionGenerator.class b/build/classes/java/main/net/minecraft/src/RandomPositionGenerator.class deleted file mode 100644 index 74d650a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RandomPositionGenerator.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RangedAttribute.class b/build/classes/java/main/net/minecraft/src/RangedAttribute.class deleted file mode 100644 index 9945cf9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RangedAttribute.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RecipeFireworks.class b/build/classes/java/main/net/minecraft/src/RecipeFireworks.class deleted file mode 100644 index 3cc7104..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RecipeFireworks.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RecipeSorter.class b/build/classes/java/main/net/minecraft/src/RecipeSorter.class deleted file mode 100644 index 4573acc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RecipeSorter.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RecipesArmor.class b/build/classes/java/main/net/minecraft/src/RecipesArmor.class deleted file mode 100644 index 6e05b04..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RecipesArmor.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RecipesArmorDyes.class b/build/classes/java/main/net/minecraft/src/RecipesArmorDyes.class deleted file mode 100644 index 5ad4baf..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RecipesArmorDyes.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RecipesCrafting.class b/build/classes/java/main/net/minecraft/src/RecipesCrafting.class deleted file mode 100644 index b9ec280..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RecipesCrafting.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RecipesDyes.class b/build/classes/java/main/net/minecraft/src/RecipesDyes.class deleted file mode 100644 index 62b4061..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RecipesDyes.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RecipesFood.class b/build/classes/java/main/net/minecraft/src/RecipesFood.class deleted file mode 100644 index d1f6109..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RecipesFood.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RecipesIngots.class b/build/classes/java/main/net/minecraft/src/RecipesIngots.class deleted file mode 100644 index cbefeba..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RecipesIngots.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RecipesMapCloning.class b/build/classes/java/main/net/minecraft/src/RecipesMapCloning.class deleted file mode 100644 index a6fefae..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RecipesMapCloning.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RecipesMapExtending.class b/build/classes/java/main/net/minecraft/src/RecipesMapExtending.class deleted file mode 100644 index 5334a43..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RecipesMapExtending.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RecipesTools.class b/build/classes/java/main/net/minecraft/src/RecipesTools.class deleted file mode 100644 index d17d370..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RecipesTools.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RecipesWeapons.class b/build/classes/java/main/net/minecraft/src/RecipesWeapons.class deleted file mode 100644 index 4dd2797..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RecipesWeapons.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RedstoneUpdateInfo.class b/build/classes/java/main/net/minecraft/src/RedstoneUpdateInfo.class deleted file mode 100644 index 9567dbd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RedstoneUpdateInfo.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RegionFile.class b/build/classes/java/main/net/minecraft/src/RegionFile.class deleted file mode 100644 index 2cbdadf..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RegionFile.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RegionFileCache.class b/build/classes/java/main/net/minecraft/src/RegionFileCache.class deleted file mode 100644 index b0f240a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RegionFileCache.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RegionFileChunkBuffer.class b/build/classes/java/main/net/minecraft/src/RegionFileChunkBuffer.class deleted file mode 100644 index e035ad3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RegionFileChunkBuffer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RegistryDefaulted.class b/build/classes/java/main/net/minecraft/src/RegistryDefaulted.class deleted file mode 100644 index 00c4eb4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RegistryDefaulted.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RegistrySimple.class b/build/classes/java/main/net/minecraft/src/RegistrySimple.class deleted file mode 100644 index 9870267..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RegistrySimple.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ReloadableResourceManager.class b/build/classes/java/main/net/minecraft/src/ReloadableResourceManager.class deleted file mode 100644 index c5f688d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ReloadableResourceManager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Render.class b/build/classes/java/main/net/minecraft/src/Render.class deleted file mode 100644 index cf17409..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Render.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderArrow.class b/build/classes/java/main/net/minecraft/src/RenderArrow.class deleted file mode 100644 index 1870ab1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderArrow.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderBat.class b/build/classes/java/main/net/minecraft/src/RenderBat.class deleted file mode 100644 index 7e24d36..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderBat.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderBiped.class b/build/classes/java/main/net/minecraft/src/RenderBiped.class deleted file mode 100644 index 2b1dac6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderBiped.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderBlaze.class b/build/classes/java/main/net/minecraft/src/RenderBlaze.class deleted file mode 100644 index 9b1c496..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderBlaze.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderBlocks.class b/build/classes/java/main/net/minecraft/src/RenderBlocks.class deleted file mode 100644 index a04c697..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderBlocks.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderBoat.class b/build/classes/java/main/net/minecraft/src/RenderBoat.class deleted file mode 100644 index 3c166cf..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderBoat.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderCaveSpider.class b/build/classes/java/main/net/minecraft/src/RenderCaveSpider.class deleted file mode 100644 index a3c3b5f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderCaveSpider.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderChicken.class b/build/classes/java/main/net/minecraft/src/RenderChicken.class deleted file mode 100644 index 4d26f75..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderChicken.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderCow.class b/build/classes/java/main/net/minecraft/src/RenderCow.class deleted file mode 100644 index 400afac..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderCow.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderCreeper.class b/build/classes/java/main/net/minecraft/src/RenderCreeper.class deleted file mode 100644 index 1536a79..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderCreeper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderDragon.class b/build/classes/java/main/net/minecraft/src/RenderDragon.class deleted file mode 100644 index 92cb439..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderDragon.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderEnchantmentTable.class b/build/classes/java/main/net/minecraft/src/RenderEnchantmentTable.class deleted file mode 100644 index 0dcbb69..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderEnchantmentTable.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderEndPortal.class b/build/classes/java/main/net/minecraft/src/RenderEndPortal.class deleted file mode 100644 index e172e84..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderEndPortal.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderEnderCrystal.class b/build/classes/java/main/net/minecraft/src/RenderEnderCrystal.class deleted file mode 100644 index 87ed65c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderEnderCrystal.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderEnderman.class b/build/classes/java/main/net/minecraft/src/RenderEnderman.class deleted file mode 100644 index 138ae02..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderEnderman.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderEntity.class b/build/classes/java/main/net/minecraft/src/RenderEntity.class deleted file mode 100644 index 84ddbe8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderEntity.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderFallingSand.class b/build/classes/java/main/net/minecraft/src/RenderFallingSand.class deleted file mode 100644 index 8fcf1d0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderFallingSand.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderFireball.class b/build/classes/java/main/net/minecraft/src/RenderFireball.class deleted file mode 100644 index b5711ac..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderFireball.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderFish.class b/build/classes/java/main/net/minecraft/src/RenderFish.class deleted file mode 100644 index 1b7b023..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderFish.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderGhast.class b/build/classes/java/main/net/minecraft/src/RenderGhast.class deleted file mode 100644 index e0065d6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderGhast.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderGiantZombie.class b/build/classes/java/main/net/minecraft/src/RenderGiantZombie.class deleted file mode 100644 index 97c93cd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderGiantZombie.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderGlobal.class b/build/classes/java/main/net/minecraft/src/RenderGlobal.class deleted file mode 100644 index 0d6f2b8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderGlobal.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderHelper.class b/build/classes/java/main/net/minecraft/src/RenderHelper.class deleted file mode 100644 index 0690261..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderHelper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderHorse.class b/build/classes/java/main/net/minecraft/src/RenderHorse.class deleted file mode 100644 index 3c82668..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderHorse.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderIronGolem.class b/build/classes/java/main/net/minecraft/src/RenderIronGolem.class deleted file mode 100644 index 1f0a3ce..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderIronGolem.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderItem.class b/build/classes/java/main/net/minecraft/src/RenderItem.class deleted file mode 100644 index 8418dde..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderItem.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderItemFrame.class b/build/classes/java/main/net/minecraft/src/RenderItemFrame.class deleted file mode 100644 index 7ef06df..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderItemFrame.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderLeashKnot.class b/build/classes/java/main/net/minecraft/src/RenderLeashKnot.class deleted file mode 100644 index a0a2c62..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderLeashKnot.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderLightningBolt.class b/build/classes/java/main/net/minecraft/src/RenderLightningBolt.class deleted file mode 100644 index ccc33a2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderLightningBolt.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderList.class b/build/classes/java/main/net/minecraft/src/RenderList.class deleted file mode 100644 index 362c47c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderLiving.class b/build/classes/java/main/net/minecraft/src/RenderLiving.class deleted file mode 100644 index 55f8f6a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderLiving.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderMagmaCube.class b/build/classes/java/main/net/minecraft/src/RenderMagmaCube.class deleted file mode 100644 index 15239db..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderMagmaCube.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderManager.class b/build/classes/java/main/net/minecraft/src/RenderManager.class deleted file mode 100644 index fa69757..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderManager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderMinecart.class b/build/classes/java/main/net/minecraft/src/RenderMinecart.class deleted file mode 100644 index f193f8b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderMinecart.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderMinecartMobSpawner.class b/build/classes/java/main/net/minecraft/src/RenderMinecartMobSpawner.class deleted file mode 100644 index 079bc95..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderMinecartMobSpawner.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderMooshroom.class b/build/classes/java/main/net/minecraft/src/RenderMooshroom.class deleted file mode 100644 index 56abaf6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderMooshroom.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderOcelot.class b/build/classes/java/main/net/minecraft/src/RenderOcelot.class deleted file mode 100644 index c27dbba..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderOcelot.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderPainting.class b/build/classes/java/main/net/minecraft/src/RenderPainting.class deleted file mode 100644 index 229f1e7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderPainting.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderPig.class b/build/classes/java/main/net/minecraft/src/RenderPig.class deleted file mode 100644 index 56bf677..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderPig.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderPlayer.class b/build/classes/java/main/net/minecraft/src/RenderPlayer.class deleted file mode 100644 index 8ec92aa..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderPlayer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderSheep.class b/build/classes/java/main/net/minecraft/src/RenderSheep.class deleted file mode 100644 index a76d13e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderSheep.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderSilverfish.class b/build/classes/java/main/net/minecraft/src/RenderSilverfish.class deleted file mode 100644 index ff38cb9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderSilverfish.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderSkeleton.class b/build/classes/java/main/net/minecraft/src/RenderSkeleton.class deleted file mode 100644 index 6cbfeb0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderSkeleton.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderSlime.class b/build/classes/java/main/net/minecraft/src/RenderSlime.class deleted file mode 100644 index 7c44167..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderSlime.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderSnowMan.class b/build/classes/java/main/net/minecraft/src/RenderSnowMan.class deleted file mode 100644 index c8ba42d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderSnowMan.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderSnowball.class b/build/classes/java/main/net/minecraft/src/RenderSnowball.class deleted file mode 100644 index 60c6ab5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderSnowball.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderSorter.class b/build/classes/java/main/net/minecraft/src/RenderSorter.class deleted file mode 100644 index 937c6a3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderSorter.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderSpider.class b/build/classes/java/main/net/minecraft/src/RenderSpider.class deleted file mode 100644 index 538d445..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderSpider.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderSquid.class b/build/classes/java/main/net/minecraft/src/RenderSquid.class deleted file mode 100644 index 5c203f4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderSquid.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderTNTPrimed.class b/build/classes/java/main/net/minecraft/src/RenderTNTPrimed.class deleted file mode 100644 index f260798..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderTNTPrimed.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderTntMinecart.class b/build/classes/java/main/net/minecraft/src/RenderTntMinecart.class deleted file mode 100644 index cbeb27f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderTntMinecart.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderVillager.class b/build/classes/java/main/net/minecraft/src/RenderVillager.class deleted file mode 100644 index 35b3d40..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderVillager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderWitch.class b/build/classes/java/main/net/minecraft/src/RenderWitch.class deleted file mode 100644 index c42ddf8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderWitch.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderWither.class b/build/classes/java/main/net/minecraft/src/RenderWither.class deleted file mode 100644 index 947256a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderWither.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderWitherSkull.class b/build/classes/java/main/net/minecraft/src/RenderWitherSkull.class deleted file mode 100644 index 427d736..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderWitherSkull.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderWolf.class b/build/classes/java/main/net/minecraft/src/RenderWolf.class deleted file mode 100644 index 3fc0404..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderWolf.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderXPOrb.class b/build/classes/java/main/net/minecraft/src/RenderXPOrb.class deleted file mode 100644 index b1a6230..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderXPOrb.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RenderZombie.class b/build/classes/java/main/net/minecraft/src/RenderZombie.class deleted file mode 100644 index 3e09e4b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RenderZombie.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RendererLivingEntity.class b/build/classes/java/main/net/minecraft/src/RendererLivingEntity.class deleted file mode 100644 index 67a53b4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RendererLivingEntity.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ReportedException.class b/build/classes/java/main/net/minecraft/src/ReportedException.class deleted file mode 100644 index 033e4ee..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ReportedException.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Request.class b/build/classes/java/main/net/minecraft/src/Request.class deleted file mode 100644 index 6cabf8e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Request.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RequestDelete.class b/build/classes/java/main/net/minecraft/src/RequestDelete.class deleted file mode 100644 index b7f29f1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RequestDelete.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RequestGet.class b/build/classes/java/main/net/minecraft/src/RequestGet.class deleted file mode 100644 index 574868d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RequestGet.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RequestPost.class b/build/classes/java/main/net/minecraft/src/RequestPost.class deleted file mode 100644 index 5f0618a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RequestPost.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RequestPut.class b/build/classes/java/main/net/minecraft/src/RequestPut.class deleted file mode 100644 index fa74775..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RequestPut.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Resource.class b/build/classes/java/main/net/minecraft/src/Resource.class deleted file mode 100644 index 0bdc696..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Resource.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ResourceLocation.class b/build/classes/java/main/net/minecraft/src/ResourceLocation.class deleted file mode 100644 index f651227..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ResourceLocation.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ResourceManager.class b/build/classes/java/main/net/minecraft/src/ResourceManager.class deleted file mode 100644 index 3a2057f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ResourceManager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ResourceManagerReloadListener.class b/build/classes/java/main/net/minecraft/src/ResourceManagerReloadListener.class deleted file mode 100644 index 8d3bb77..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ResourceManagerReloadListener.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ResourcePack.class b/build/classes/java/main/net/minecraft/src/ResourcePack.class deleted file mode 100644 index 90536eb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ResourcePack.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ResourcePackFileNotFoundException.class b/build/classes/java/main/net/minecraft/src/ResourcePackFileNotFoundException.class deleted file mode 100644 index ea14596..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ResourcePackFileNotFoundException.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ResourcePackRepository.class b/build/classes/java/main/net/minecraft/src/ResourcePackRepository.class deleted file mode 100644 index 9508333..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ResourcePackRepository.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ResourcePackRepositoryEntry.class b/build/classes/java/main/net/minecraft/src/ResourcePackRepositoryEntry.class deleted file mode 100644 index da240dd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ResourcePackRepositoryEntry.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ResourcePackRepositoryFilter.class b/build/classes/java/main/net/minecraft/src/ResourcePackRepositoryFilter.class deleted file mode 100644 index cb43c13..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ResourcePackRepositoryFilter.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/RunnableTitleScreen.class b/build/classes/java/main/net/minecraft/src/RunnableTitleScreen.class deleted file mode 100644 index 46ef5f4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/RunnableTitleScreen.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SaveFormatComparator.class b/build/classes/java/main/net/minecraft/src/SaveFormatComparator.class deleted file mode 100644 index fd8535f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SaveFormatComparator.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SaveFormatOld.class b/build/classes/java/main/net/minecraft/src/SaveFormatOld.class deleted file mode 100644 index afd79b1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SaveFormatOld.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SaveHandler.class b/build/classes/java/main/net/minecraft/src/SaveHandler.class deleted file mode 100644 index ba88446..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SaveHandler.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SaveHandlerMP.class b/build/classes/java/main/net/minecraft/src/SaveHandlerMP.class deleted file mode 100644 index 104cdb8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SaveHandlerMP.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ScaledResolution.class b/build/classes/java/main/net/minecraft/src/ScaledResolution.class deleted file mode 100644 index 45e8c98..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ScaledResolution.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ScheduledSound.class b/build/classes/java/main/net/minecraft/src/ScheduledSound.class deleted file mode 100644 index daf235d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ScheduledSound.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Score.class b/build/classes/java/main/net/minecraft/src/Score.class deleted file mode 100644 index e7c3691..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Score.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ScoreComparator.class b/build/classes/java/main/net/minecraft/src/ScoreComparator.class deleted file mode 100644 index 980c7cc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ScoreComparator.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ScoreDummyCriteria.class b/build/classes/java/main/net/minecraft/src/ScoreDummyCriteria.class deleted file mode 100644 index b74f8b1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ScoreDummyCriteria.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ScoreHealthCriteria.class b/build/classes/java/main/net/minecraft/src/ScoreHealthCriteria.class deleted file mode 100644 index 5c55d12..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ScoreHealthCriteria.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ScoreObjective.class b/build/classes/java/main/net/minecraft/src/ScoreObjective.class deleted file mode 100644 index 28b6bba..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ScoreObjective.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ScoreObjectiveCriteria.class b/build/classes/java/main/net/minecraft/src/ScoreObjectiveCriteria.class deleted file mode 100644 index d708e5d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ScoreObjectiveCriteria.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ScorePlayerTeam.class b/build/classes/java/main/net/minecraft/src/ScorePlayerTeam.class deleted file mode 100644 index 5420a1d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ScorePlayerTeam.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Scoreboard.class b/build/classes/java/main/net/minecraft/src/Scoreboard.class deleted file mode 100644 index e941870..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Scoreboard.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ScoreboardSaveData.class b/build/classes/java/main/net/minecraft/src/ScoreboardSaveData.class deleted file mode 100644 index 3cab54b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ScoreboardSaveData.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ScreenChatOptions.class b/build/classes/java/main/net/minecraft/src/ScreenChatOptions.class deleted file mode 100644 index d71c0a9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ScreenChatOptions.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ScreenShotHelper.class b/build/classes/java/main/net/minecraft/src/ScreenShotHelper.class deleted file mode 100644 index 972db5c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ScreenShotHelper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ScreenWithCallback.class b/build/classes/java/main/net/minecraft/src/ScreenWithCallback.class deleted file mode 100644 index dd75fc3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ScreenWithCallback.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SelectionListBase.class b/build/classes/java/main/net/minecraft/src/SelectionListBase.class deleted file mode 100644 index 1240196..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SelectionListBase.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SelectionListInvited.class b/build/classes/java/main/net/minecraft/src/SelectionListInvited.class deleted file mode 100644 index 15bd688..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SelectionListInvited.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ServerAddress.class b/build/classes/java/main/net/minecraft/src/ServerAddress.class deleted file mode 100644 index 56651e3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ServerAddress.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ServerBlockEvent.class b/build/classes/java/main/net/minecraft/src/ServerBlockEvent.class deleted file mode 100644 index c2180ac..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ServerBlockEvent.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ServerBlockEventList.class b/build/classes/java/main/net/minecraft/src/ServerBlockEventList.class deleted file mode 100644 index fc2e0bb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ServerBlockEventList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ServerCommand.class b/build/classes/java/main/net/minecraft/src/ServerCommand.class deleted file mode 100644 index 84b22e3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ServerCommand.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ServerCommandManager.class b/build/classes/java/main/net/minecraft/src/ServerCommandManager.class deleted file mode 100644 index 71afb3c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ServerCommandManager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ServerCommandScoreboard.class b/build/classes/java/main/net/minecraft/src/ServerCommandScoreboard.class deleted file mode 100644 index e332a2d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ServerCommandScoreboard.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ServerCommandTestFor.class b/build/classes/java/main/net/minecraft/src/ServerCommandTestFor.class deleted file mode 100644 index d2010b0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ServerCommandTestFor.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ServerConfigurationManager.class b/build/classes/java/main/net/minecraft/src/ServerConfigurationManager.class deleted file mode 100644 index 1cbc917..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ServerConfigurationManager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ServerData.class b/build/classes/java/main/net/minecraft/src/ServerData.class deleted file mode 100644 index a951e53..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ServerData.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ServerList.class b/build/classes/java/main/net/minecraft/src/ServerList.class deleted file mode 100644 index 50027d8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ServerList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ServerListenThread.class b/build/classes/java/main/net/minecraft/src/ServerListenThread.class deleted file mode 100644 index b596d7d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ServerListenThread.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ServerScoreboard.class b/build/classes/java/main/net/minecraft/src/ServerScoreboard.class deleted file mode 100644 index e48d62a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ServerScoreboard.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ServersideAttributeMap.class b/build/classes/java/main/net/minecraft/src/ServersideAttributeMap.class deleted file mode 100644 index 2ce86ff..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ServersideAttributeMap.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Session.class b/build/classes/java/main/net/minecraft/src/Session.class deleted file mode 100644 index cbb884b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Session.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ShapedRecipes.class b/build/classes/java/main/net/minecraft/src/ShapedRecipes.class deleted file mode 100644 index b2c8096..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ShapedRecipes.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ShapelessRecipes.class b/build/classes/java/main/net/minecraft/src/ShapelessRecipes.class deleted file mode 100644 index 76111cc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ShapelessRecipes.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SharedMonsterAttributes.class b/build/classes/java/main/net/minecraft/src/SharedMonsterAttributes.class deleted file mode 100644 index d81e0fc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SharedMonsterAttributes.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SimpleReloadableResourceManager.class b/build/classes/java/main/net/minecraft/src/SimpleReloadableResourceManager.class deleted file mode 100644 index 256da10..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SimpleReloadableResourceManager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SimpleReloadableResourceManagerINNER1.class b/build/classes/java/main/net/minecraft/src/SimpleReloadableResourceManagerINNER1.class deleted file mode 100644 index a168fbd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SimpleReloadableResourceManagerINNER1.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SimpleResource.class b/build/classes/java/main/net/minecraft/src/SimpleResource.class deleted file mode 100644 index e39bf16..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SimpleResource.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SimpleTexture.class b/build/classes/java/main/net/minecraft/src/SimpleTexture.class deleted file mode 100644 index b7dd841..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SimpleTexture.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Slot.class b/build/classes/java/main/net/minecraft/src/Slot.class deleted file mode 100644 index 575fef8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Slot.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SlotArmor.class b/build/classes/java/main/net/minecraft/src/SlotArmor.class deleted file mode 100644 index 9c56534..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SlotArmor.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SlotBeacon.class b/build/classes/java/main/net/minecraft/src/SlotBeacon.class deleted file mode 100644 index 6a0425b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SlotBeacon.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SlotBrewingStandIngredient.class b/build/classes/java/main/net/minecraft/src/SlotBrewingStandIngredient.class deleted file mode 100644 index df4f97d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SlotBrewingStandIngredient.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SlotBrewingStandPotion.class b/build/classes/java/main/net/minecraft/src/SlotBrewingStandPotion.class deleted file mode 100644 index f3dc9f8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SlotBrewingStandPotion.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SlotCrafting.class b/build/classes/java/main/net/minecraft/src/SlotCrafting.class deleted file mode 100644 index ee2ed44..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SlotCrafting.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SlotCreativeInventory.class b/build/classes/java/main/net/minecraft/src/SlotCreativeInventory.class deleted file mode 100644 index 240b5a7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SlotCreativeInventory.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SlotEnchantment.class b/build/classes/java/main/net/minecraft/src/SlotEnchantment.class deleted file mode 100644 index 03b96dc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SlotEnchantment.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SlotEnchantmentTable.class b/build/classes/java/main/net/minecraft/src/SlotEnchantmentTable.class deleted file mode 100644 index 8b5f402..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SlotEnchantmentTable.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SlotFurnace.class b/build/classes/java/main/net/minecraft/src/SlotFurnace.class deleted file mode 100644 index b34404b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SlotFurnace.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SlotMerchantResult.class b/build/classes/java/main/net/minecraft/src/SlotMerchantResult.class deleted file mode 100644 index 2272424..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SlotMerchantResult.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SorterStatsBlock.class b/build/classes/java/main/net/minecraft/src/SorterStatsBlock.class deleted file mode 100644 index 328a6a0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SorterStatsBlock.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SorterStatsItem.class b/build/classes/java/main/net/minecraft/src/SorterStatsItem.class deleted file mode 100644 index 155433c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SorterStatsItem.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SoundManager.class b/build/classes/java/main/net/minecraft/src/SoundManager.class deleted file mode 100644 index 2fb7f3f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SoundManager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SoundManagerINNER1.class b/build/classes/java/main/net/minecraft/src/SoundManagerINNER1.class deleted file mode 100644 index a75a47c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SoundManagerINNER1.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SoundPool.class b/build/classes/java/main/net/minecraft/src/SoundPool.class deleted file mode 100644 index ace6531..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SoundPool.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SoundPoolEntry.class b/build/classes/java/main/net/minecraft/src/SoundPoolEntry.class deleted file mode 100644 index 3756b7a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SoundPoolEntry.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SoundPoolProtocolHandler.class b/build/classes/java/main/net/minecraft/src/SoundPoolProtocolHandler.class deleted file mode 100644 index 57792af..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SoundPoolProtocolHandler.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SoundPoolURLConnection.class b/build/classes/java/main/net/minecraft/src/SoundPoolURLConnection.class deleted file mode 100644 index eb5aabe..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SoundPoolURLConnection.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SoundUpdaterMinecart.class b/build/classes/java/main/net/minecraft/src/SoundUpdaterMinecart.class deleted file mode 100644 index b34804b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SoundUpdaterMinecart.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SpawnListEntry.class b/build/classes/java/main/net/minecraft/src/SpawnListEntry.class deleted file mode 100644 index 7d7544e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SpawnListEntry.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SpawnerAnimals.class b/build/classes/java/main/net/minecraft/src/SpawnerAnimals.class deleted file mode 100644 index a08fb65..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SpawnerAnimals.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SpiderEffectsGroupData.class b/build/classes/java/main/net/minecraft/src/SpiderEffectsGroupData.class deleted file mode 100644 index 88fd230..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SpiderEffectsGroupData.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StatBase.class b/build/classes/java/main/net/minecraft/src/StatBase.class deleted file mode 100644 index 8ac3ed2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StatBase.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StatBasic.class b/build/classes/java/main/net/minecraft/src/StatBasic.class deleted file mode 100644 index 200e728..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StatBasic.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StatCollector.class b/build/classes/java/main/net/minecraft/src/StatCollector.class deleted file mode 100644 index 287b702..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StatCollector.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StatCrafting.class b/build/classes/java/main/net/minecraft/src/StatCrafting.class deleted file mode 100644 index e0fd488..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StatCrafting.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StatFileWriter.class b/build/classes/java/main/net/minecraft/src/StatFileWriter.class deleted file mode 100644 index 779d6f0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StatFileWriter.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StatList.class b/build/classes/java/main/net/minecraft/src/StatList.class deleted file mode 100644 index 4b7a292..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StatList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StatPlaceholder.class b/build/classes/java/main/net/minecraft/src/StatPlaceholder.class deleted file mode 100644 index 7a5bd28..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StatPlaceholder.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StatStringFormatKeyInv.class b/build/classes/java/main/net/minecraft/src/StatStringFormatKeyInv.class deleted file mode 100644 index 2afe166..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StatStringFormatKeyInv.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StatTypeDistance.class b/build/classes/java/main/net/minecraft/src/StatTypeDistance.class deleted file mode 100644 index 055a535..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StatTypeDistance.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StatTypeFloat.class b/build/classes/java/main/net/minecraft/src/StatTypeFloat.class deleted file mode 100644 index 35bd4fa..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StatTypeFloat.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StatTypeSimple.class b/build/classes/java/main/net/minecraft/src/StatTypeSimple.class deleted file mode 100644 index 972bfed..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StatTypeSimple.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StatTypeTime.class b/build/classes/java/main/net/minecraft/src/StatTypeTime.class deleted file mode 100644 index 6345efb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StatTypeTime.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StatsSyncher.class b/build/classes/java/main/net/minecraft/src/StatsSyncher.class deleted file mode 100644 index d0bac0c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StatsSyncher.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StepSound.class b/build/classes/java/main/net/minecraft/src/StepSound.class deleted file mode 100644 index 514d601..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StepSound.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StepSoundAnvil.class b/build/classes/java/main/net/minecraft/src/StepSoundAnvil.class deleted file mode 100644 index 28e9940..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StepSoundAnvil.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StepSoundSand.class b/build/classes/java/main/net/minecraft/src/StepSoundSand.class deleted file mode 100644 index ef227ed..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StepSoundSand.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StepSoundStone.class b/build/classes/java/main/net/minecraft/src/StepSoundStone.class deleted file mode 100644 index 265bc2e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StepSoundStone.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StitchHolder.class b/build/classes/java/main/net/minecraft/src/StitchHolder.class deleted file mode 100644 index 1301772..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StitchHolder.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StitchSlot.class b/build/classes/java/main/net/minecraft/src/StitchSlot.class deleted file mode 100644 index 63e1038..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StitchSlot.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Stitcher.class b/build/classes/java/main/net/minecraft/src/Stitcher.class deleted file mode 100644 index b8c2714..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Stitcher.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StitcherException.class b/build/classes/java/main/net/minecraft/src/StitcherException.class deleted file mode 100644 index 32a5139..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StitcherException.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StringTranslate.class b/build/classes/java/main/net/minecraft/src/StringTranslate.class deleted file mode 100644 index 9c22742..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StringTranslate.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StringUtils.class b/build/classes/java/main/net/minecraft/src/StringUtils.class deleted file mode 100644 index ba81bb7..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StringUtils.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StructureBoundingBox.class b/build/classes/java/main/net/minecraft/src/StructureBoundingBox.class deleted file mode 100644 index d4bf9ad..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StructureBoundingBox.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StructureComponent.class b/build/classes/java/main/net/minecraft/src/StructureComponent.class deleted file mode 100644 index 0ace1f4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StructureComponent.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StructureMineshaftPieces.class b/build/classes/java/main/net/minecraft/src/StructureMineshaftPieces.class deleted file mode 100644 index 20c6deb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StructureMineshaftPieces.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StructureMineshaftStart.class b/build/classes/java/main/net/minecraft/src/StructureMineshaftStart.class deleted file mode 100644 index a0300ba..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StructureMineshaftStart.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StructureNetherBridgePieceWeight.class b/build/classes/java/main/net/minecraft/src/StructureNetherBridgePieceWeight.class deleted file mode 100644 index 4509f02..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StructureNetherBridgePieceWeight.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StructureNetherBridgePieces.class b/build/classes/java/main/net/minecraft/src/StructureNetherBridgePieces.class deleted file mode 100644 index c0f63d5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StructureNetherBridgePieces.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StructureNetherBridgeStart.class b/build/classes/java/main/net/minecraft/src/StructureNetherBridgeStart.class deleted file mode 100644 index e22a5a2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StructureNetherBridgeStart.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StructurePieceBlockSelector.class b/build/classes/java/main/net/minecraft/src/StructurePieceBlockSelector.class deleted file mode 100644 index b4ee2b3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StructurePieceBlockSelector.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StructureScatteredFeatureStart.class b/build/classes/java/main/net/minecraft/src/StructureScatteredFeatureStart.class deleted file mode 100644 index 59b59b3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StructureScatteredFeatureStart.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StructureScatteredFeatureStones.class b/build/classes/java/main/net/minecraft/src/StructureScatteredFeatureStones.class deleted file mode 100644 index c5f7edc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StructureScatteredFeatureStones.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StructureStart.class b/build/classes/java/main/net/minecraft/src/StructureStart.class deleted file mode 100644 index a6819df..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StructureStart.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StructureStrongholdPieceWeight.class b/build/classes/java/main/net/minecraft/src/StructureStrongholdPieceWeight.class deleted file mode 100644 index 527d99d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StructureStrongholdPieceWeight.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StructureStrongholdPieceWeight2.class b/build/classes/java/main/net/minecraft/src/StructureStrongholdPieceWeight2.class deleted file mode 100644 index f269951..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StructureStrongholdPieceWeight2.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StructureStrongholdPieceWeight3.class b/build/classes/java/main/net/minecraft/src/StructureStrongholdPieceWeight3.class deleted file mode 100644 index 83f2969..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StructureStrongholdPieceWeight3.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StructureStrongholdPieces.class b/build/classes/java/main/net/minecraft/src/StructureStrongholdPieces.class deleted file mode 100644 index 7a727bf..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StructureStrongholdPieces.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StructureStrongholdStart.class b/build/classes/java/main/net/minecraft/src/StructureStrongholdStart.class deleted file mode 100644 index 3a3ba80..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StructureStrongholdStart.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StructureStrongholdStones.class b/build/classes/java/main/net/minecraft/src/StructureStrongholdStones.class deleted file mode 100644 index 49c634f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StructureStrongholdStones.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StructureVillagePieceWeight.class b/build/classes/java/main/net/minecraft/src/StructureVillagePieceWeight.class deleted file mode 100644 index c86c7f0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StructureVillagePieceWeight.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StructureVillagePieces.class b/build/classes/java/main/net/minecraft/src/StructureVillagePieces.class deleted file mode 100644 index 51cfdc6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StructureVillagePieces.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/StructureVillageStart.class b/build/classes/java/main/net/minecraft/src/StructureVillageStart.class deleted file mode 100644 index 11e3d8b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/StructureVillageStart.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/SyntaxErrorException.class b/build/classes/java/main/net/minecraft/src/SyntaxErrorException.class deleted file mode 100644 index 360c837..0000000 Binary files a/build/classes/java/main/net/minecraft/src/SyntaxErrorException.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TaskLongRunning.class b/build/classes/java/main/net/minecraft/src/TaskLongRunning.class deleted file mode 100644 index 6e410d8..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TaskLongRunning.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TaskOnlineConnect.class b/build/classes/java/main/net/minecraft/src/TaskOnlineConnect.class deleted file mode 100644 index fbb1446..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TaskOnlineConnect.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TaskResetWorld.class b/build/classes/java/main/net/minecraft/src/TaskResetWorld.class deleted file mode 100644 index c7d8715..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TaskResetWorld.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TaskWorldCreation.class b/build/classes/java/main/net/minecraft/src/TaskWorldCreation.class deleted file mode 100644 index f118fd6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TaskWorldCreation.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TcpConnection.class b/build/classes/java/main/net/minecraft/src/TcpConnection.class deleted file mode 100644 index 377f50b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TcpConnection.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TcpMasterThread.class b/build/classes/java/main/net/minecraft/src/TcpMasterThread.class deleted file mode 100644 index cde9d56..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TcpMasterThread.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TcpMonitorThread.class b/build/classes/java/main/net/minecraft/src/TcpMonitorThread.class deleted file mode 100644 index 1712bab..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TcpMonitorThread.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TcpReaderThread.class b/build/classes/java/main/net/minecraft/src/TcpReaderThread.class deleted file mode 100644 index 9bc8206..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TcpReaderThread.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TcpWriterThread.class b/build/classes/java/main/net/minecraft/src/TcpWriterThread.class deleted file mode 100644 index 76edc70..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TcpWriterThread.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Team.class b/build/classes/java/main/net/minecraft/src/Team.class deleted file mode 100644 index 0660356..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Team.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Teleporter.class b/build/classes/java/main/net/minecraft/src/Teleporter.class deleted file mode 100644 index 745457c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Teleporter.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Tessellator.class b/build/classes/java/main/net/minecraft/src/Tessellator.class deleted file mode 100644 index d0b6231..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Tessellator.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TextureAtlasSprite.class b/build/classes/java/main/net/minecraft/src/TextureAtlasSprite.class deleted file mode 100644 index a5db54f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TextureAtlasSprite.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TextureClock.class b/build/classes/java/main/net/minecraft/src/TextureClock.class deleted file mode 100644 index 39e4257..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TextureClock.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TextureCompass.class b/build/classes/java/main/net/minecraft/src/TextureCompass.class deleted file mode 100644 index 9269640..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TextureCompass.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TextureManager.class b/build/classes/java/main/net/minecraft/src/TextureManager.class deleted file mode 100644 index 781cbba..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TextureManager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TextureManagerINNER1.class b/build/classes/java/main/net/minecraft/src/TextureManagerINNER1.class deleted file mode 100644 index 37e040b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TextureManagerINNER1.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TextureMap.class b/build/classes/java/main/net/minecraft/src/TextureMap.class deleted file mode 100644 index 8a5681f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TextureMap.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TextureMetadataSection.class b/build/classes/java/main/net/minecraft/src/TextureMetadataSection.class deleted file mode 100644 index aa46488..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TextureMetadataSection.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TextureMetadataSectionSerializer.class b/build/classes/java/main/net/minecraft/src/TextureMetadataSectionSerializer.class deleted file mode 100644 index 52bd504..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TextureMetadataSectionSerializer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TextureObject.class b/build/classes/java/main/net/minecraft/src/TextureObject.class deleted file mode 100644 index a8c545d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TextureObject.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TextureOffset.class b/build/classes/java/main/net/minecraft/src/TextureOffset.class deleted file mode 100644 index a3a4894..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TextureOffset.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TextureUtil.class b/build/classes/java/main/net/minecraft/src/TextureUtil.class deleted file mode 100644 index d96507c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TextureUtil.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TexturedQuad.class b/build/classes/java/main/net/minecraft/src/TexturedQuad.class deleted file mode 100644 index e79d796..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TexturedQuad.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ThreadClientSleep.class b/build/classes/java/main/net/minecraft/src/ThreadClientSleep.class deleted file mode 100644 index 8f3572b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ThreadClientSleep.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ThreadConnectToOnlineServer.class b/build/classes/java/main/net/minecraft/src/ThreadConnectToOnlineServer.class deleted file mode 100644 index ed88933..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ThreadConnectToOnlineServer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ThreadConnectToServer.class b/build/classes/java/main/net/minecraft/src/ThreadConnectToServer.class deleted file mode 100644 index af45b92..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ThreadConnectToServer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ThreadDownloadImageData.class b/build/classes/java/main/net/minecraft/src/ThreadDownloadImageData.class deleted file mode 100644 index 06054cb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ThreadDownloadImageData.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ThreadDownloadImageDataINNER1.class b/build/classes/java/main/net/minecraft/src/ThreadDownloadImageDataINNER1.class deleted file mode 100644 index 11660fd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ThreadDownloadImageDataINNER1.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ThreadLanServerFind.class b/build/classes/java/main/net/minecraft/src/ThreadLanServerFind.class deleted file mode 100644 index 25cb263..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ThreadLanServerFind.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ThreadLanServerPing.class b/build/classes/java/main/net/minecraft/src/ThreadLanServerPing.class deleted file mode 100644 index 540a862..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ThreadLanServerPing.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ThreadLoginVerifier.class b/build/classes/java/main/net/minecraft/src/ThreadLoginVerifier.class deleted file mode 100644 index 6723634..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ThreadLoginVerifier.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ThreadMinecraftServer.class b/build/classes/java/main/net/minecraft/src/ThreadMinecraftServer.class deleted file mode 100644 index 0567bb1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ThreadMinecraftServer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ThreadOnlineConnect.class b/build/classes/java/main/net/minecraft/src/ThreadOnlineConnect.class deleted file mode 100644 index afe9686..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ThreadOnlineConnect.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ThreadOnlineScreen.class b/build/classes/java/main/net/minecraft/src/ThreadOnlineScreen.class deleted file mode 100644 index c4e14dc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ThreadOnlineScreen.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ThreadPollServers.class b/build/classes/java/main/net/minecraft/src/ThreadPollServers.class deleted file mode 100644 index a4d0a66..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ThreadPollServers.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ThreadStatSyncherReceive.class b/build/classes/java/main/net/minecraft/src/ThreadStatSyncherReceive.class deleted file mode 100644 index 5957a68..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ThreadStatSyncherReceive.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ThreadStatSyncherSend.class b/build/classes/java/main/net/minecraft/src/ThreadStatSyncherSend.class deleted file mode 100644 index 633741c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ThreadStatSyncherSend.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ThreadedFileIOBase.class b/build/classes/java/main/net/minecraft/src/ThreadedFileIOBase.class deleted file mode 100644 index fcfa810..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ThreadedFileIOBase.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Tickable.class b/build/classes/java/main/net/minecraft/src/Tickable.class deleted file mode 100644 index 822ba60..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Tickable.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TickableTextureObject.class b/build/classes/java/main/net/minecraft/src/TickableTextureObject.class deleted file mode 100644 index 343d778..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TickableTextureObject.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntity.class b/build/classes/java/main/net/minecraft/src/TileEntity.class deleted file mode 100644 index ce08ef6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntity.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityBeacon.class b/build/classes/java/main/net/minecraft/src/TileEntityBeacon.class deleted file mode 100644 index 5448b95..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityBeacon.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityBeaconRenderer.class b/build/classes/java/main/net/minecraft/src/TileEntityBeaconRenderer.class deleted file mode 100644 index 2fbd541..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityBeaconRenderer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityBrewingStand.class b/build/classes/java/main/net/minecraft/src/TileEntityBrewingStand.class deleted file mode 100644 index de43636..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityBrewingStand.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityChest.class b/build/classes/java/main/net/minecraft/src/TileEntityChest.class deleted file mode 100644 index a41fc9d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityChest.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityChestRenderer.class b/build/classes/java/main/net/minecraft/src/TileEntityChestRenderer.class deleted file mode 100644 index 3d1dd88..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityChestRenderer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityCommandBlock.class b/build/classes/java/main/net/minecraft/src/TileEntityCommandBlock.class deleted file mode 100644 index bf9640a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityCommandBlock.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityComparator.class b/build/classes/java/main/net/minecraft/src/TileEntityComparator.class deleted file mode 100644 index 8309734..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityComparator.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityDaylightDetector.class b/build/classes/java/main/net/minecraft/src/TileEntityDaylightDetector.class deleted file mode 100644 index f05fa3e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityDaylightDetector.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityDispenser.class b/build/classes/java/main/net/minecraft/src/TileEntityDispenser.class deleted file mode 100644 index 6cb054d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityDispenser.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityDropper.class b/build/classes/java/main/net/minecraft/src/TileEntityDropper.class deleted file mode 100644 index 7a15048..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityDropper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityEnchantmentTable.class b/build/classes/java/main/net/minecraft/src/TileEntityEnchantmentTable.class deleted file mode 100644 index 7bb82e2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityEnchantmentTable.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityEndPortal.class b/build/classes/java/main/net/minecraft/src/TileEntityEndPortal.class deleted file mode 100644 index 4b78f32..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityEndPortal.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityEnderChest.class b/build/classes/java/main/net/minecraft/src/TileEntityEnderChest.class deleted file mode 100644 index 4fbdd84..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityEnderChest.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityEnderChestRenderer.class b/build/classes/java/main/net/minecraft/src/TileEntityEnderChestRenderer.class deleted file mode 100644 index 48f6bb0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityEnderChestRenderer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityFurnace.class b/build/classes/java/main/net/minecraft/src/TileEntityFurnace.class deleted file mode 100644 index b6f0b29..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityFurnace.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityHopper.class b/build/classes/java/main/net/minecraft/src/TileEntityHopper.class deleted file mode 100644 index d8477b6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityHopper.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityMobSpawner.class b/build/classes/java/main/net/minecraft/src/TileEntityMobSpawner.class deleted file mode 100644 index 4f52029..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityMobSpawner.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityMobSpawnerLogic.class b/build/classes/java/main/net/minecraft/src/TileEntityMobSpawnerLogic.class deleted file mode 100644 index 1f6f854..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityMobSpawnerLogic.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityMobSpawnerRenderer.class b/build/classes/java/main/net/minecraft/src/TileEntityMobSpawnerRenderer.class deleted file mode 100644 index ef93dac..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityMobSpawnerRenderer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityNote.class b/build/classes/java/main/net/minecraft/src/TileEntityNote.class deleted file mode 100644 index 47415ca..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityNote.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityPiston.class b/build/classes/java/main/net/minecraft/src/TileEntityPiston.class deleted file mode 100644 index fb55dd5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityPiston.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityRecordPlayer.class b/build/classes/java/main/net/minecraft/src/TileEntityRecordPlayer.class deleted file mode 100644 index 12dd2ee..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityRecordPlayer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityRenderer.class b/build/classes/java/main/net/minecraft/src/TileEntityRenderer.class deleted file mode 100644 index 99a19c5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityRenderer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntityRendererPiston.class b/build/classes/java/main/net/minecraft/src/TileEntityRendererPiston.class deleted file mode 100644 index 6df1d24..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntityRendererPiston.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntitySign.class b/build/classes/java/main/net/minecraft/src/TileEntitySign.class deleted file mode 100644 index 29c2c84..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntitySign.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntitySignRenderer.class b/build/classes/java/main/net/minecraft/src/TileEntitySignRenderer.class deleted file mode 100644 index ad16cc5..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntitySignRenderer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntitySkull.class b/build/classes/java/main/net/minecraft/src/TileEntitySkull.class deleted file mode 100644 index 6ee6dc9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntitySkull.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntitySkullRenderer.class b/build/classes/java/main/net/minecraft/src/TileEntitySkullRenderer.class deleted file mode 100644 index 1ec5802..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntitySkullRenderer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/TileEntitySpecialRenderer.class b/build/classes/java/main/net/minecraft/src/TileEntitySpecialRenderer.class deleted file mode 100644 index 2fd72fd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/TileEntitySpecialRenderer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Timer.class b/build/classes/java/main/net/minecraft/src/Timer.class deleted file mode 100644 index 87c9165..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Timer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Tuple.class b/build/classes/java/main/net/minecraft/src/Tuple.class deleted file mode 100644 index 2b97309..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Tuple.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Util.class b/build/classes/java/main/net/minecraft/src/Util.class deleted file mode 100644 index eb94414..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Util.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ValueObject.class b/build/classes/java/main/net/minecraft/src/ValueObject.class deleted file mode 100644 index 1d9274b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ValueObject.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ValueObjectList.class b/build/classes/java/main/net/minecraft/src/ValueObjectList.class deleted file mode 100644 index 497e3b9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ValueObjectList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/ValueObjectSubscription.class b/build/classes/java/main/net/minecraft/src/ValueObjectSubscription.class deleted file mode 100644 index af9df99..0000000 Binary files a/build/classes/java/main/net/minecraft/src/ValueObjectSubscription.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Vec3.class b/build/classes/java/main/net/minecraft/src/Vec3.class deleted file mode 100644 index 0b178db..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Vec3.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Vec3Pool.class b/build/classes/java/main/net/minecraft/src/Vec3Pool.class deleted file mode 100644 index dd3cd2d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Vec3Pool.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/Village.class b/build/classes/java/main/net/minecraft/src/Village.class deleted file mode 100644 index e54e0c3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/Village.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/VillageAgressor.class b/build/classes/java/main/net/minecraft/src/VillageAgressor.class deleted file mode 100644 index 84db9e1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/VillageAgressor.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/VillageCollection.class b/build/classes/java/main/net/minecraft/src/VillageCollection.class deleted file mode 100644 index 5427e89..0000000 Binary files a/build/classes/java/main/net/minecraft/src/VillageCollection.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/VillageDoorInfo.class b/build/classes/java/main/net/minecraft/src/VillageDoorInfo.class deleted file mode 100644 index bc3c3fc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/VillageDoorInfo.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/VillageSiege.class b/build/classes/java/main/net/minecraft/src/VillageSiege.class deleted file mode 100644 index 867a504..0000000 Binary files a/build/classes/java/main/net/minecraft/src/VillageSiege.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WatchableObject.class b/build/classes/java/main/net/minecraft/src/WatchableObject.class deleted file mode 100644 index 504101a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WatchableObject.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WeightedRandom.class b/build/classes/java/main/net/minecraft/src/WeightedRandom.class deleted file mode 100644 index 41383c2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WeightedRandom.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WeightedRandomChestContent.class b/build/classes/java/main/net/minecraft/src/WeightedRandomChestContent.class deleted file mode 100644 index e886d74..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WeightedRandomChestContent.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WeightedRandomItem.class b/build/classes/java/main/net/minecraft/src/WeightedRandomItem.class deleted file mode 100644 index 7e9b29d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WeightedRandomItem.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WeightedRandomMinecart.class b/build/classes/java/main/net/minecraft/src/WeightedRandomMinecart.class deleted file mode 100644 index 0e411ec..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WeightedRandomMinecart.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/World.class b/build/classes/java/main/net/minecraft/src/World.class deleted file mode 100644 index 67bfa7f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/World.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldChunkManager.class b/build/classes/java/main/net/minecraft/src/WorldChunkManager.class deleted file mode 100644 index d151fe3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldChunkManager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldChunkManagerHell.class b/build/classes/java/main/net/minecraft/src/WorldChunkManagerHell.class deleted file mode 100644 index 0b388ce..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldChunkManagerHell.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldClient.class b/build/classes/java/main/net/minecraft/src/WorldClient.class deleted file mode 100644 index 8b611a3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldClient.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldClientINNER3.class b/build/classes/java/main/net/minecraft/src/WorldClientINNER3.class deleted file mode 100644 index cbba466..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldClientINNER3.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldClientINNER4.class b/build/classes/java/main/net/minecraft/src/WorldClientINNER4.class deleted file mode 100644 index 9966f3f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldClientINNER4.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenBigMushroom.class b/build/classes/java/main/net/minecraft/src/WorldGenBigMushroom.class deleted file mode 100644 index 75e15cf..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenBigMushroom.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenBigTree.class b/build/classes/java/main/net/minecraft/src/WorldGenBigTree.class deleted file mode 100644 index bafef50..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenBigTree.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenCactus.class b/build/classes/java/main/net/minecraft/src/WorldGenCactus.class deleted file mode 100644 index 23bdf1a..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenCactus.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenClay.class b/build/classes/java/main/net/minecraft/src/WorldGenClay.class deleted file mode 100644 index bab1730..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenClay.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenDeadBush.class b/build/classes/java/main/net/minecraft/src/WorldGenDeadBush.class deleted file mode 100644 index bb09cdc..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenDeadBush.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenDesertWells.class b/build/classes/java/main/net/minecraft/src/WorldGenDesertWells.class deleted file mode 100644 index 953016c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenDesertWells.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenDungeons.class b/build/classes/java/main/net/minecraft/src/WorldGenDungeons.class deleted file mode 100644 index d484904..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenDungeons.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenFire.class b/build/classes/java/main/net/minecraft/src/WorldGenFire.class deleted file mode 100644 index 8fba7bb..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenFire.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenFlowers.class b/build/classes/java/main/net/minecraft/src/WorldGenFlowers.class deleted file mode 100644 index 6aaa213..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenFlowers.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenForest.class b/build/classes/java/main/net/minecraft/src/WorldGenForest.class deleted file mode 100644 index aa2caf1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenForest.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenGlowStone1.class b/build/classes/java/main/net/minecraft/src/WorldGenGlowStone1.class deleted file mode 100644 index d8326a0..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenGlowStone1.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenGlowStone2.class b/build/classes/java/main/net/minecraft/src/WorldGenGlowStone2.class deleted file mode 100644 index 887d2a6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenGlowStone2.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenHellLava.class b/build/classes/java/main/net/minecraft/src/WorldGenHellLava.class deleted file mode 100644 index 66d55d9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenHellLava.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenHugeTrees.class b/build/classes/java/main/net/minecraft/src/WorldGenHugeTrees.class deleted file mode 100644 index c6e93f1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenHugeTrees.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenLakes.class b/build/classes/java/main/net/minecraft/src/WorldGenLakes.class deleted file mode 100644 index eb5f7c3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenLakes.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenLiquids.class b/build/classes/java/main/net/minecraft/src/WorldGenLiquids.class deleted file mode 100644 index 7b7a016..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenLiquids.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenMinable.class b/build/classes/java/main/net/minecraft/src/WorldGenMinable.class deleted file mode 100644 index 439cbb9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenMinable.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenPumpkin.class b/build/classes/java/main/net/minecraft/src/WorldGenPumpkin.class deleted file mode 100644 index 3ffe0a2..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenPumpkin.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenReed.class b/build/classes/java/main/net/minecraft/src/WorldGenReed.class deleted file mode 100644 index 028204e..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenReed.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenSand.class b/build/classes/java/main/net/minecraft/src/WorldGenSand.class deleted file mode 100644 index c48797b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenSand.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenShrub.class b/build/classes/java/main/net/minecraft/src/WorldGenShrub.class deleted file mode 100644 index 32f5b2b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenShrub.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenSpikes.class b/build/classes/java/main/net/minecraft/src/WorldGenSpikes.class deleted file mode 100644 index c74d60b..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenSpikes.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenSwamp.class b/build/classes/java/main/net/minecraft/src/WorldGenSwamp.class deleted file mode 100644 index 535c3e6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenSwamp.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenTaiga1.class b/build/classes/java/main/net/minecraft/src/WorldGenTaiga1.class deleted file mode 100644 index 31e0c12..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenTaiga1.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenTaiga2.class b/build/classes/java/main/net/minecraft/src/WorldGenTaiga2.class deleted file mode 100644 index 367f287..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenTaiga2.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenTallGrass.class b/build/classes/java/main/net/minecraft/src/WorldGenTallGrass.class deleted file mode 100644 index 29530d6..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenTallGrass.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenTrees.class b/build/classes/java/main/net/minecraft/src/WorldGenTrees.class deleted file mode 100644 index 837caa4..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenTrees.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenVines.class b/build/classes/java/main/net/minecraft/src/WorldGenVines.class deleted file mode 100644 index b0354c9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenVines.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenWaterlily.class b/build/classes/java/main/net/minecraft/src/WorldGenWaterlily.class deleted file mode 100644 index 127c89d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenWaterlily.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGenerator.class b/build/classes/java/main/net/minecraft/src/WorldGenerator.class deleted file mode 100644 index 32598fd..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGenerator.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldGeneratorBonusChest.class b/build/classes/java/main/net/minecraft/src/WorldGeneratorBonusChest.class deleted file mode 100644 index c8a539f..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldGeneratorBonusChest.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldInfo.class b/build/classes/java/main/net/minecraft/src/WorldInfo.class deleted file mode 100644 index 8feff53..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldInfo.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldManager.class b/build/classes/java/main/net/minecraft/src/WorldManager.class deleted file mode 100644 index 2537655..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldManager.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldProvider.class b/build/classes/java/main/net/minecraft/src/WorldProvider.class deleted file mode 100644 index ae0a511..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldProvider.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldProviderEnd.class b/build/classes/java/main/net/minecraft/src/WorldProviderEnd.class deleted file mode 100644 index fb12cc1..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldProviderEnd.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldProviderHell.class b/build/classes/java/main/net/minecraft/src/WorldProviderHell.class deleted file mode 100644 index d5fba34..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldProviderHell.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldProviderSurface.class b/build/classes/java/main/net/minecraft/src/WorldProviderSurface.class deleted file mode 100644 index a5255c9..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldProviderSurface.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldRenderer.class b/build/classes/java/main/net/minecraft/src/WorldRenderer.class deleted file mode 100644 index dcc0f0d..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldRenderer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldSavedData.class b/build/classes/java/main/net/minecraft/src/WorldSavedData.class deleted file mode 100644 index c94ed82..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldSavedData.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldServer.class b/build/classes/java/main/net/minecraft/src/WorldServer.class deleted file mode 100644 index c7a1554..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldServer.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldServerMulti.class b/build/classes/java/main/net/minecraft/src/WorldServerMulti.class deleted file mode 100644 index 95e5b02..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldServerMulti.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldSettings.class b/build/classes/java/main/net/minecraft/src/WorldSettings.class deleted file mode 100644 index 3192d05..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldSettings.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldTemplate.class b/build/classes/java/main/net/minecraft/src/WorldTemplate.class deleted file mode 100644 index a684c73..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldTemplate.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldTemplateList.class b/build/classes/java/main/net/minecraft/src/WorldTemplateList.class deleted file mode 100644 index c6a9bf3..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldTemplateList.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WorldType.class b/build/classes/java/main/net/minecraft/src/WorldType.class deleted file mode 100644 index 1d15791..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WorldType.class and /dev/null differ diff --git a/build/classes/java/main/net/minecraft/src/WrongUsageException.class b/build/classes/java/main/net/minecraft/src/WrongUsageException.class deleted file mode 100644 index 44fb44c..0000000 Binary files a/build/classes/java/main/net/minecraft/src/WrongUsageException.class and /dev/null differ diff --git a/build/distributions/eaglercraft.tar b/build/distributions/eaglercraft.tar deleted file mode 100644 index 1e4859a..0000000 Binary files a/build/distributions/eaglercraft.tar and /dev/null differ diff --git a/build/distributions/eaglercraft.zip b/build/distributions/eaglercraft.zip deleted file mode 100644 index c806e1d..0000000 Binary files a/build/distributions/eaglercraft.zip and /dev/null differ diff --git a/build/libs/eaglercraft.jar b/build/libs/eaglercraft.jar deleted file mode 100644 index a031daa..0000000 Binary files a/build/libs/eaglercraft.jar and /dev/null differ diff --git a/build/scripts/eaglercraft b/build/scripts/eaglercraft deleted file mode 100755 index 8f5218e..0000000 --- a/build/scripts/eaglercraft +++ /dev/null @@ -1,243 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# eaglercraft start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh eaglercraft -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and EAGLERCRAFT_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}.." && pwd -P ) || exit - -# Add default JVM options here. You can also use JAVA_OPTS and EAGLERCRAFT_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Djava.library.path=lwjgl-rundir"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/lib/eaglercraft.jar:$APP_HOME/lib/librarylwjglopenal-20100824.jar:$APP_HOME/lib/commons-io-2.4.jar:$APP_HOME/lib/argo-2.25_fixed.jar:$APP_HOME/lib/lwjgl_util-2.9.0.jar:$APP_HOME/lib/libraryjavasound-20101123.jar:$APP_HOME/lib/codecwav-20101023.jar:$APP_HOME/lib/soundsystem-20120107.jar:$APP_HOME/lib/codecjorbis-20101023.jar:$APP_HOME/lib/gson-2.2.2.jar:$APP_HOME/lib/jopt-simple-4.5.jar:$APP_HOME/lib/lwjgl-2.9.0.jar:$APP_HOME/lib/guava-14.0.jar:$APP_HOME/lib/lwjgl-platform-2.9.0-natives-linux.jar:$APP_HOME/lib/commons-lang3-3.1.jar:$APP_HOME/lib/bcprov-jdk15on-1.47.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and EAGLERCRAFT_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $EAGLERCRAFT_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - -classpath "$CLASSPATH" \ - net.minecraft.client.main.Main \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $EAGLERCRAFT_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/build/scripts/eaglercraft.bat b/build/scripts/eaglercraft.bat deleted file mode 100644 index ab06eb9..0000000 --- a/build/scripts/eaglercraft.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem eaglercraft startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME%.. - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and EAGLERCRAFT_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Djava.library.path=lwjgl-rundir" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\lib\eaglercraft.jar;%APP_HOME%\lib\librarylwjglopenal-20100824.jar;%APP_HOME%\lib\commons-io-2.4.jar;%APP_HOME%\lib\argo-2.25_fixed.jar;%APP_HOME%\lib\lwjgl_util-2.9.0.jar;%APP_HOME%\lib\libraryjavasound-20101123.jar;%APP_HOME%\lib\codecwav-20101023.jar;%APP_HOME%\lib\soundsystem-20120107.jar;%APP_HOME%\lib\codecjorbis-20101023.jar;%APP_HOME%\lib\gson-2.2.2.jar;%APP_HOME%\lib\jopt-simple-4.5.jar;%APP_HOME%\lib\lwjgl-2.9.0.jar;%APP_HOME%\lib\guava-14.0.jar;%APP_HOME%\lib\lwjgl-platform-2.9.0-natives-linux.jar;%APP_HOME%\lib\commons-lang3-3.1.jar;%APP_HOME%\lib\bcprov-jdk15on-1.47.jar - - -@rem Execute eaglercraft -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %EAGLERCRAFT_OPTS% -classpath "%CLASSPATH%" net.minecraft.client.main.Main %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable EAGLERCRAFT_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%EAGLERCRAFT_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/build/tmp/compileJava/previous-compilation-data.bin b/build/tmp/compileJava/previous-compilation-data.bin deleted file mode 100644 index 7c4ab00..0000000 Binary files a/build/tmp/compileJava/previous-compilation-data.bin and /dev/null differ diff --git a/build/tmp/jar/MANIFEST.MF b/build/tmp/jar/MANIFEST.MF deleted file mode 100644 index 58630c0..0000000 --- a/build/tmp/jar/MANIFEST.MF +++ /dev/null @@ -1,2 +0,0 @@ -Manifest-Version: 1.0 - diff --git a/lwjgl-rundir/_start_desktop_runtime.sh b/lwjgl-rundir/_start_desktop_runtime.sh deleted file mode 100755 index 9f3b765..0000000 --- a/lwjgl-rundir/_start_desktop_runtime.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -java -Xmx4G -Xms4G -Djava.library.path=. -cp "eaglercraft.jar:lwjgl-2.9.0.jar:lwjgl-util-2.9.0.jar:soundsystem-20120107.jar:codecjorbis-20101023.jar:codecwav-20101023.jar:lwjgl-platform-2.9.0-natives-linux.jar:jopt-simple-4.5.jar:gson-2.2.2.jar:guava-14.0.jar:commons-lang3-3.1.jar:commons-io-2.4.jar:libraryjavasound-20101123.jar:librarylwjglopenal-20100824.jar:bcprov-jdk15on-1.47.jar:argo-2.25_fixed.jar" net.minecraft.client.main.Main \ No newline at end of file diff --git a/lwjgl-rundir/jopt-simple-4.5.jar b/lwjgl-rundir/jopt-simple-4.5.jar deleted file mode 100644 index 6aa0c61..0000000 Binary files a/lwjgl-rundir/jopt-simple-4.5.jar and /dev/null differ diff --git a/lwjgl-rundir/launch.sh b/lwjgl-rundir/launch.sh new file mode 100755 index 0000000..0ae4dec --- /dev/null +++ b/lwjgl-rundir/launch.sh @@ -0,0 +1,2 @@ +#!/bin/sh +java -Xmx4G -Xms4G -Djava.library.path=. -cp "eaglercraft.jar:lwjgl-2.9.0.jar:lwjgl-util-2.9.0.jar:soundsystem-20120107.jar:codecjorbis-20101023.jar:codecwav-20101023.jar:lwjgl-platform-2.9.0-natives-linux.jar:gson-2.2.2.jar:guava-14.0.jar:commons-lang3-3.1.jar:commons-io-2.4.jar:libraryjavasound-20101123.jar:librarylwjglopenal-20100824.jar:bcprov-jdk15on-1.47.jar:argo-2.25_fixed.jar" net.lax1dude.eaglercraft.MinecraftMain \ No newline at end of file diff --git a/src/lwjgl/java/com/jcraft/jzlib/Adler32.java b/src/lwjgl/java/com/jcraft/jzlib/Adler32.java new file mode 100644 index 0000000..02a07e1 --- /dev/null +++ b/src/lwjgl/java/com/jcraft/jzlib/Adler32.java @@ -0,0 +1,118 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2000-2011 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package com.jcraft.jzlib; + +final public class Adler32 implements Checksum { + + // largest prime smaller than 65536 + static final private int BASE=65521; + // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 + static final private int NMAX=5552; + + private long s1=1L; + private long s2=0L; + + public void reset(long init){ + s1=init&0xffff; + s2=(init>>16)&0xffff; + } + + public void reset(){ + s1=1L; + s2=0L; + } + + public long getValue(){ + return ((s2<<16)|s1); + } + + public void update(byte[] buf, int index, int len){ + + if(len==1){ + s1+=buf[index++]&0xff; s2+=s1; + s1%=BASE; + s2%=BASE; + return; + } + + int len1 = len/NMAX; + int len2 = len%NMAX; + while(len1-->0) { + int k=NMAX; + len-=k; + while(k-->0){ + s1+=buf[index++]&0xff; s2+=s1; + } + s1%=BASE; + s2%=BASE; + } + + int k=len2; + len-=k; + while(k-->0){ + s1+=buf[index++]&0xff; s2+=s1; + } + s1%=BASE; + s2%=BASE; + } + + public Adler32 copy(){ + Adler32 foo = new Adler32(); + foo.s1 = this.s1; + foo.s2 = this.s2; + return foo; + } + + // The following logic has come from zlib.1.2. + static long combine(long adler1, long adler2, long len2){ + long BASEL = (long)BASE; + long sum1; + long sum2; + long rem; // unsigned int + + rem = len2 % BASEL; + sum1 = adler1 & 0xffffL; + sum2 = rem * sum1; + sum2 %= BASEL; // MOD(sum2); + sum1 += (adler2 & 0xffffL) + BASEL - 1; + sum2 += ((adler1 >> 16) & 0xffffL) + ((adler2 >> 16) & 0xffffL) + BASEL - rem; + if (sum1 >= BASEL) sum1 -= BASEL; + if (sum1 >= BASEL) sum1 -= BASEL; + if (sum2 >= (BASEL << 1)) sum2 -= (BASEL << 1); + if (sum2 >= BASEL) sum2 -= BASEL; + return sum1 | (sum2 << 16); + } + +} diff --git a/src/lwjgl/java/com/jcraft/jzlib/CRC32.java b/src/lwjgl/java/com/jcraft/jzlib/CRC32.java new file mode 100644 index 0000000..a1b6e75 --- /dev/null +++ b/src/lwjgl/java/com/jcraft/jzlib/CRC32.java @@ -0,0 +1,157 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package com.jcraft.jzlib; + +final public class CRC32 implements Checksum { + + /* + * The following logic has come from RFC1952. + */ + private int v = 0; + private static int[] crc_table = null; + static { + crc_table = new int[256]; + for (int n = 0; n < 256; n++) { + int c = n; + for (int k = 8; --k >= 0; ) { + if ((c & 1) != 0) + c = 0xedb88320 ^ (c >>> 1); + else + c = c >>> 1; + } + crc_table[n] = c; + } + } + + public void update (byte[] buf, int index, int len) { + int c = ~v; + while (--len >= 0) + c = crc_table[(c^buf[index++])&0xff]^(c >>> 8); + v = ~c; + } + + public void reset(){ + v = 0; + } + + public void reset(long vv){ + v = (int)(vv&0xffffffffL); + } + + public long getValue(){ + return (long)(v&0xffffffffL); + } + + // The following logic has come from zlib.1.2. + private static final int GF2_DIM = 32; + static long combine(long crc1, long crc2, long len2){ + long row; + long[] even = new long[GF2_DIM]; + long[] odd = new long[GF2_DIM]; + + // degenerate case (also disallow negative lengths) + if (len2 <= 0) + return crc1; + + // put operator for one zero bit in odd + odd[0] = 0xedb88320L; // CRC-32 polynomial + row = 1; + for (int n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + // put operator for two zero bits in even + gf2_matrix_square(even, odd); + + // put operator for four zero bits in odd + gf2_matrix_square(odd, even); + + // apply len2 zeros to crc1 (first square will put the operator for one + // zero byte, eight zero bits, in even) + do { + // apply zeros operator for this bit of len2 + gf2_matrix_square(even, odd); + if ((len2 & 1)!=0) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + // if no more bits set, then done + if (len2 == 0) + break; + + // another iteration of the loop with odd and even swapped + gf2_matrix_square(odd, even); + if ((len2 & 1)!=0) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + // if no more bits set, then done + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; + } + + private static long gf2_matrix_times(long[] mat, long vec){ + long sum = 0; + int index = 0; + while (vec!=0) { + if ((vec & 1)!=0) + sum ^= mat[index]; + vec >>= 1; + index++; + } + return sum; + } + + static final void gf2_matrix_square(long[] square, long[] mat) { + for (int n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); + } + + public CRC32 copy(){ + CRC32 foo = new CRC32(); + foo.v = this.v; + return foo; + } + + public static int[] getCRC32Table(){ + int[] tmp = new int[crc_table.length]; + System.arraycopy(crc_table, 0, tmp, 0, tmp.length); + return tmp; + } +} diff --git a/src/lwjgl/java/com/jcraft/jzlib/Checksum.java b/src/lwjgl/java/com/jcraft/jzlib/Checksum.java new file mode 100644 index 0000000..1139093 --- /dev/null +++ b/src/lwjgl/java/com/jcraft/jzlib/Checksum.java @@ -0,0 +1,43 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package com.jcraft.jzlib; + +interface Checksum { + void update(byte[] buf, int index, int len); + void reset(); + void reset(long init); + long getValue(); + Checksum copy(); +} diff --git a/src/lwjgl/java/com/jcraft/jzlib/Deflate.java b/src/lwjgl/java/com/jcraft/jzlib/Deflate.java new file mode 100644 index 0000000..cfda0f0 --- /dev/null +++ b/src/lwjgl/java/com/jcraft/jzlib/Deflate.java @@ -0,0 +1,1757 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2000-2011 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package com.jcraft.jzlib; + +public +final class Deflate implements Cloneable { + + static final private int MAX_MEM_LEVEL=9; + + static final private int Z_DEFAULT_COMPRESSION=-1; + + static final private int MAX_WBITS=15; // 32K LZ77 window + static final private int DEF_MEM_LEVEL=8; + + static class Config{ + int good_length; // reduce lazy search above this match length + int max_lazy; // do not perform lazy search above this match length + int nice_length; // quit search above this match length + int max_chain; + int func; + Config(int good_length, int max_lazy, + int nice_length, int max_chain, int func){ + this.good_length=good_length; + this.max_lazy=max_lazy; + this.nice_length=nice_length; + this.max_chain=max_chain; + this.func=func; + } + } + + static final private int STORED=0; + static final private int FAST=1; + static final private int SLOW=2; + static final private Config[] config_table; + static{ + config_table=new Config[10]; + // good lazy nice chain + config_table[0]=new Config(0, 0, 0, 0, STORED); + config_table[1]=new Config(4, 4, 8, 4, FAST); + config_table[2]=new Config(4, 5, 16, 8, FAST); + config_table[3]=new Config(4, 6, 32, 32, FAST); + + config_table[4]=new Config(4, 4, 16, 16, SLOW); + config_table[5]=new Config(8, 16, 32, 32, SLOW); + config_table[6]=new Config(8, 16, 128, 128, SLOW); + config_table[7]=new Config(8, 32, 128, 256, SLOW); + config_table[8]=new Config(32, 128, 258, 1024, SLOW); + config_table[9]=new Config(32, 258, 258, 4096, SLOW); + } + + static final private String[] z_errmsg = { + "need dictionary", // Z_NEED_DICT 2 + "stream end", // Z_STREAM_END 1 + "", // Z_OK 0 + "file error", // Z_ERRNO (-1) + "stream error", // Z_STREAM_ERROR (-2) + "data error", // Z_DATA_ERROR (-3) + "insufficient memory", // Z_MEM_ERROR (-4) + "buffer error", // Z_BUF_ERROR (-5) + "incompatible version",// Z_VERSION_ERROR (-6) + "" + }; + + // block not completed, need more input or more output + static final private int NeedMore=0; + + // block flush performed + static final private int BlockDone=1; + + // finish started, need only more output at next deflate + static final private int FinishStarted=2; + + // finish done, accept no more input or output + static final private int FinishDone=3; + + // preset dictionary flag in zlib header + static final private int PRESET_DICT=0x20; + + static final private int Z_FILTERED=1; + static final private int Z_HUFFMAN_ONLY=2; + static final private int Z_DEFAULT_STRATEGY=0; + + static final private int Z_NO_FLUSH=0; + static final private int Z_PARTIAL_FLUSH=1; + static final private int Z_SYNC_FLUSH=2; + static final private int Z_FULL_FLUSH=3; + static final private int Z_FINISH=4; + + static final private int Z_OK=0; + static final private int Z_STREAM_END=1; + static final private int Z_NEED_DICT=2; + static final private int Z_ERRNO=-1; + static final private int Z_STREAM_ERROR=-2; + static final private int Z_DATA_ERROR=-3; + static final private int Z_MEM_ERROR=-4; + static final private int Z_BUF_ERROR=-5; + static final private int Z_VERSION_ERROR=-6; + + static final private int INIT_STATE=42; + static final private int BUSY_STATE=113; + static final private int FINISH_STATE=666; + + // The deflate compression method + static final private int Z_DEFLATED=8; + + static final private int STORED_BLOCK=0; + static final private int STATIC_TREES=1; + static final private int DYN_TREES=2; + + // The three kinds of block type + static final private int Z_BINARY=0; + static final private int Z_ASCII=1; + static final private int Z_UNKNOWN=2; + + static final private int Buf_size=8*2; + + // repeat previous bit length 3-6 times (2 bits of repeat count) + static final private int REP_3_6=16; + + // repeat a zero length 3-10 times (3 bits of repeat count) + static final private int REPZ_3_10=17; + + // repeat a zero length 11-138 times (7 bits of repeat count) + static final private int REPZ_11_138=18; + + static final private int MIN_MATCH=3; + static final private int MAX_MATCH=258; + static final private int MIN_LOOKAHEAD=(MAX_MATCH+MIN_MATCH+1); + + static final private int MAX_BITS=15; + static final private int D_CODES=30; + static final private int BL_CODES=19; + static final private int LENGTH_CODES=29; + static final private int LITERALS=256; + static final private int L_CODES=(LITERALS+1+LENGTH_CODES); + static final private int HEAP_SIZE=(2*L_CODES+1); + + static final private int END_BLOCK=256; + + ZStream strm; // pointer back to this zlib stream + int status; // as the name implies + byte[] pending_buf; // output still pending + int pending_buf_size; // size of pending_buf + int pending_out; // next pending byte to output to the stream + int pending; // nb of bytes in the pending buffer + int wrap = 1; + byte data_type; // UNKNOWN, BINARY or ASCII + byte method; // STORED (for zip only) or DEFLATED + int last_flush; // value of flush param for previous deflate call + + int w_size; // LZ77 window size (32K by default) + int w_bits; // log2(w_size) (8..16) + int w_mask; // w_size - 1 + + byte[] window; + // Sliding window. Input bytes are read into the second half of the window, + // and move to the first half later to keep a dictionary of at least wSize + // bytes. With this organization, matches are limited to a distance of + // wSize-MAX_MATCH bytes, but this ensures that IO is always + // performed with a length multiple of the block size. Also, it limits + // the window size to 64K, which is quite useful on MSDOS. + // To do: use the user input buffer as sliding window. + + int window_size; + // Actual size of window: 2*wSize, except when the user input buffer + // is directly used as sliding window. + + short[] prev; + // Link to older string with same hash index. To limit the size of this + // array to 64K, this link is maintained only for the last 32K strings. + // An index in this array is thus a window index modulo 32K. + + short[] head; // Heads of the hash chains or NIL. + + int ins_h; // hash index of string to be inserted + int hash_size; // number of elements in hash table + int hash_bits; // log2(hash_size) + int hash_mask; // hash_size-1 + + // Number of bits by which ins_h must be shifted at each input + // step. It must be such that after MIN_MATCH steps, the oldest + // byte no longer takes part in the hash key, that is: + // hash_shift * MIN_MATCH >= hash_bits + int hash_shift; + + // Window position at the beginning of the current output block. Gets + // negative when the window is moved backwards. + + int block_start; + + int match_length; // length of best match + int prev_match; // previous match + int match_available; // set if previous match exists + int strstart; // start of string to insert + int match_start; // start of matching string + int lookahead; // number of valid bytes ahead in window + + // Length of the best match at previous step. Matches not greater than this + // are discarded. This is used in the lazy match evaluation. + int prev_length; + + // To speed up deflation, hash chains are never searched beyond this + // length. A higher limit improves compression ratio but degrades the speed. + int max_chain_length; + + // Attempt to find a better match only when the current match is strictly + // smaller than this value. This mechanism is used only for compression + // levels >= 4. + int max_lazy_match; + + // Insert new strings in the hash table only if the match length is not + // greater than this length. This saves time but degrades compression. + // max_insert_length is used only for compression levels <= 3. + + int level; // compression level (1..9) + int strategy; // favor or force Huffman coding + + // Use a faster search when the previous match is longer than this + int good_match; + + // Stop searching when current match exceeds this + int nice_match; + + short[] dyn_ltree; // literal and length tree + short[] dyn_dtree; // distance tree + short[] bl_tree; // Huffman tree for bit lengths + + Tree l_desc=new Tree(); // desc for literal tree + Tree d_desc=new Tree(); // desc for distance tree + Tree bl_desc=new Tree(); // desc for bit length tree + + // number of codes at each bit length for an optimal tree + short[] bl_count=new short[MAX_BITS+1]; + // working area to be used in Tree#gen_codes() + short[] next_code=new short[MAX_BITS+1]; + + // heap used to build the Huffman trees + int[] heap=new int[2*L_CODES+1]; + + int heap_len; // number of elements in the heap + int heap_max; // element of largest frequency + // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + // The same heap array is used to build all trees. + + // Depth of each subtree used as tie breaker for trees of equal frequency + byte[] depth=new byte[2*L_CODES+1]; + + byte[] l_buf; // index for literals or lengths */ + + // Size of match buffer for literals/lengths. There are 4 reasons for + // limiting lit_bufsize to 64K: + // - frequencies can be kept in 16 bit counters + // - if compression is not successful for the first block, all input + // data is still in the window so we can still emit a stored block even + // when input comes from standard input. (This can also be done for + // all blocks if lit_bufsize is not greater than 32K.) + // - if compression is not successful for a file smaller than 64K, we can + // even emit a stored file instead of a stored block (saving 5 bytes). + // This is applicable only for zip (not gzip or zlib). + // - creating new Huffman trees less frequently may not provide fast + // adaptation to changes in the input data statistics. (Take for + // example a binary file with poorly compressible code followed by + // a highly compressible string table.) Smaller buffer sizes give + // fast adaptation but have of course the overhead of transmitting + // trees more frequently. + // - I can't count above 4 + int lit_bufsize; + + int last_lit; // running index in l_buf + + // Buffer for distances. To simplify the code, d_buf and l_buf have + // the same number of elements. To use different lengths, an extra flag + // array would be necessary. + + int d_buf; // index of pendig_buf + + int opt_len; // bit length of current block with optimal trees + int static_len; // bit length of current block with static trees + int matches; // number of string matches in current block + int last_eob_len; // bit length of EOB code for last block + + // Output buffer. bits are inserted starting at the bottom (least + // significant bits). + short bi_buf; + + // Number of valid bits in bi_buf. All bits above the last valid bit + // are always zero. + int bi_valid; + + GZIPHeader gheader = null; + + Deflate(ZStream strm){ + this.strm=strm; + dyn_ltree=new short[HEAP_SIZE*2]; + dyn_dtree=new short[(2*D_CODES+1)*2]; // distance tree + bl_tree=new short[(2*BL_CODES+1)*2]; // Huffman tree for bit lengths + } + + void lm_init() { + window_size=2*w_size; + + head[hash_size-1]=0; + for(int i=0; i= 3; max_blindex--) { + if (bl_tree[Tree.bl_order[max_blindex]*2+1] != 0) break; + } + // Update opt_len to include the bit length tree and counts + opt_len += 3*(max_blindex+1) + 5+5+4; + + return max_blindex; + } + + + // Send the header for a block using dynamic Huffman trees: the counts, the + // lengths of the bit length codes, the literal tree and the distance tree. + // IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + void send_all_trees(int lcodes, int dcodes, int blcodes){ + int rank; // index in bl_order + + send_bits(lcodes-257, 5); // not +255 as stated in appnote.txt + send_bits(dcodes-1, 5); + send_bits(blcodes-4, 4); // not -3 as stated in appnote.txt + for (rank = 0; rank < blcodes; rank++) { + send_bits(bl_tree[Tree.bl_order[rank]*2+1], 3); + } + send_tree(dyn_ltree, lcodes-1); // literal tree + send_tree(dyn_dtree, dcodes-1); // distance tree + } + + // Send a literal or distance tree in compressed form, using the codes in + // bl_tree. + void send_tree (short[] tree,// the tree to be sent + int max_code // and its largest code of non zero frequency + ){ + int n; // iterates over all tree elements + int prevlen = -1; // last emitted length + int curlen; // length of current code + int nextlen = tree[0*2+1]; // length of next code + int count = 0; // repeat count of the current code + int max_count = 7; // max repeat count + int min_count = 4; // min repeat count + + if (nextlen == 0){ max_count = 138; min_count = 3; } + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[(n+1)*2+1]; + if(++count < max_count && curlen == nextlen) { + continue; + } + else if(count < min_count) { + do { send_code(curlen, bl_tree); } while (--count != 0); + } + else if(curlen != 0){ + if(curlen != prevlen){ + send_code(curlen, bl_tree); count--; + } + send_code(REP_3_6, bl_tree); + send_bits(count-3, 2); + } + else if(count <= 10){ + send_code(REPZ_3_10, bl_tree); + send_bits(count-3, 3); + } + else{ + send_code(REPZ_11_138, bl_tree); + send_bits(count-11, 7); + } + count = 0; prevlen = curlen; + if(nextlen == 0){ + max_count = 138; min_count = 3; + } + else if(curlen == nextlen){ + max_count = 6; min_count = 3; + } + else{ + max_count = 7; min_count = 4; + } + } + } + + // Output a byte on the stream. + // IN assertion: there is enough room in pending_buf. + final void put_byte(byte[] p, int start, int len){ + System.arraycopy(p, start, pending_buf, pending, len); + pending+=len; + } + + final void put_byte(byte c){ + pending_buf[pending++]=c; + } + final void put_short(int w) { + put_byte((byte)(w/*&0xff*/)); + put_byte((byte)(w>>>8)); + } + final void putShortMSB(int b){ + put_byte((byte)(b>>8)); + put_byte((byte)(b/*&0xff*/)); + } + + final void send_code(int c, short[] tree){ + int c2=c*2; + send_bits((tree[c2]&0xffff), (tree[c2+1]&0xffff)); + } + + void send_bits(int value, int length){ + int len = length; + if (bi_valid > (int)Buf_size - len) { + int val = value; +// bi_buf |= (val << bi_valid); + bi_buf |= ((val << bi_valid)&0xffff); + put_short(bi_buf); + bi_buf = (short)(val >>> (Buf_size - bi_valid)); + bi_valid += len - Buf_size; + } else { +// bi_buf |= (value) << bi_valid; + bi_buf |= (((value) << bi_valid)&0xffff); + bi_valid += len; + } + } + + // Send one empty static block to give enough lookahead for inflate. + // This takes 10 bits, of which 7 may remain in the bit buffer. + // The current inflate code requires 9 bits of lookahead. If the + // last two codes for the previous block (real code plus EOB) were coded + // on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + // the last real code. In this case we send two empty static blocks instead + // of one. (There are no problems if the previous block is stored or fixed.) + // To simplify the code, we assume the worst case of last real code encoded + // on one bit only. + void _tr_align(){ + send_bits(STATIC_TREES<<1, 3); + send_code(END_BLOCK, StaticTree.static_ltree); + + bi_flush(); + + // Of the 10 bits for the empty block, we have already sent + // (10 - bi_valid) bits. The lookahead for the last real code (before + // the EOB of the previous block) was thus at least one plus the length + // of the EOB plus what we have just sent of the empty static block. + if (1 + last_eob_len + 10 - bi_valid < 9) { + send_bits(STATIC_TREES<<1, 3); + send_code(END_BLOCK, StaticTree.static_ltree); + bi_flush(); + } + last_eob_len = 7; + } + + + // Save the match info and tally the frequency counts. Return true if + // the current block must be flushed. + boolean _tr_tally (int dist, // distance of matched string + int lc // match length-MIN_MATCH or unmatched char (if dist==0) + ){ + + pending_buf[d_buf+last_lit*2] = (byte)(dist>>>8); + pending_buf[d_buf+last_lit*2+1] = (byte)dist; + + l_buf[last_lit] = (byte)lc; last_lit++; + + if (dist == 0) { + // lc is the unmatched char + dyn_ltree[lc*2]++; + } + else { + matches++; + // Here, lc is the match length - MIN_MATCH + dist--; // dist = match distance - 1 + dyn_ltree[(Tree._length_code[lc]+LITERALS+1)*2]++; + dyn_dtree[Tree.d_code(dist)*2]++; + } + + if ((last_lit & 0x1fff) == 0 && level > 2) { + // Compute an upper bound for the compressed length + int out_length = last_lit*8; + int in_length = strstart - block_start; + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (int)dyn_dtree[dcode*2] * + (5L+Tree.extra_dbits[dcode]); + } + out_length >>>= 3; + if ((matches < (last_lit/2)) && out_length < in_length/2) return true; + } + + return (last_lit == lit_bufsize-1); + // We avoid equality with lit_bufsize because of wraparound at 64K + // on 16 bit machines and because stored blocks are restricted to + // 64K-1 bytes. + } + + // Send the block data compressed using the given Huffman trees + void compress_block(short[] ltree, short[] dtree){ + int dist; // distance of matched string + int lc; // match length or unmatched char (if dist == 0) + int lx = 0; // running index in l_buf + int code; // the code to send + int extra; // number of extra bits to send + + if (last_lit != 0){ + do{ + dist=((pending_buf[d_buf+lx*2]<<8)&0xff00)| + (pending_buf[d_buf+lx*2+1]&0xff); + lc=(l_buf[lx])&0xff; lx++; + + if(dist == 0){ + send_code(lc, ltree); // send a literal byte + } + else{ + // Here, lc is the match length - MIN_MATCH + code = Tree._length_code[lc]; + + send_code(code+LITERALS+1, ltree); // send the length code + extra = Tree.extra_lbits[code]; + if(extra != 0){ + lc -= Tree.base_length[code]; + send_bits(lc, extra); // send the extra length bits + } + dist--; // dist is now the match distance - 1 + code = Tree.d_code(dist); + + send_code(code, dtree); // send the distance code + extra = Tree.extra_dbits[code]; + if (extra != 0) { + dist -= Tree.base_dist[code]; + send_bits(dist, extra); // send the extra distance bits + } + } // literal or match pair ? + + // Check that the overlay between pending_buf and d_buf+l_buf is ok: + } + while (lx < last_lit); + } + + send_code(END_BLOCK, ltree); + last_eob_len = ltree[END_BLOCK*2+1]; + } + + // Set the data type to ASCII or BINARY, using a crude approximation: + // binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + // IN assertion: the fields freq of dyn_ltree are set and the total of all + // frequencies does not exceed 64K (to fit in an int on 16 bit machines). + void set_data_type(){ + int n = 0; + int ascii_freq = 0; + int bin_freq = 0; + while(n<7){ bin_freq += dyn_ltree[n*2]; n++;} + while(n<128){ ascii_freq += dyn_ltree[n*2]; n++;} + while(n (ascii_freq >>> 2) ? Z_BINARY : Z_ASCII); + } + + // Flush the bit buffer, keeping at most 7 bits in it. + void bi_flush(){ + if (bi_valid == 16) { + put_short(bi_buf); + bi_buf=0; + bi_valid=0; + } + else if (bi_valid >= 8) { + put_byte((byte)bi_buf); + bi_buf>>>=8; + bi_valid-=8; + } + } + + // Flush the bit buffer and align the output on a byte boundary + void bi_windup(){ + if (bi_valid > 8) { + put_short(bi_buf); + } else if (bi_valid > 0) { + put_byte((byte)bi_buf); + } + bi_buf = 0; + bi_valid = 0; + } + + // Copy a stored block, storing first the length and its + // one's complement if requested. + void copy_block(int buf, // the input data + int len, // its length + boolean header // true if block header must be written + ){ + int index=0; + bi_windup(); // align on byte boundary + last_eob_len = 8; // enough lookahead for inflate + + if (header) { + put_short((short)len); + put_short((short)~len); + } + + // while(len--!=0) { + // put_byte(window[buf+index]); + // index++; + // } + put_byte(window, buf, len); + } + + void flush_block_only(boolean eof){ + _tr_flush_block(block_start>=0 ? block_start : -1, + strstart-block_start, + eof); + block_start=strstart; + strm.flush_pending(); + } + + // Copy without compression as much as possible from the input stream, return + // the current block state. + // This function does not insert new strings in the dictionary since + // uncompressible data is probably not useful. This function is used + // only for the level=0 compression option. + // NOTE: this function should be optimized to avoid extra copying from + // window to pending_buf. + int deflate_stored(int flush){ + // Stored blocks are limited to 0xffff bytes, pending_buf is limited + // to pending_buf_size, and each stored block has a 5 byte header: + + int max_block_size = 0xffff; + int max_start; + + if(max_block_size > pending_buf_size - 5) { + max_block_size = pending_buf_size - 5; + } + + // Copy as much as possible from input to output: + while(true){ + // Fill the window as much as possible: + if(lookahead<=1){ + fill_window(); + if(lookahead==0 && flush==Z_NO_FLUSH) return NeedMore; + if(lookahead==0) break; // flush the current block + } + + strstart+=lookahead; + lookahead=0; + + // Emit a stored block if pending_buf will be full: + max_start=block_start+max_block_size; + if(strstart==0|| strstart>=max_start) { + // strstart == 0 is possible when wraparound on 16-bit machine + lookahead = (int)(strstart-max_start); + strstart = (int)max_start; + + flush_block_only(false); + if(strm.avail_out==0) return NeedMore; + + } + + // Flush if we may have to slide, otherwise block_start may become + // negative and the data will be gone: + if(strstart-block_start >= w_size-MIN_LOOKAHEAD) { + flush_block_only(false); + if(strm.avail_out==0) return NeedMore; + } + } + + flush_block_only(flush == Z_FINISH); + if(strm.avail_out==0) + return (flush == Z_FINISH) ? FinishStarted : NeedMore; + + return flush == Z_FINISH ? FinishDone : BlockDone; + } + + // Send a stored block + void _tr_stored_block(int buf, // input block + int stored_len, // length of input block + boolean eof // true if this is the last block for a file + ){ + send_bits((STORED_BLOCK<<1)+(eof?1:0), 3); // send block type + copy_block(buf, stored_len, true); // with header + } + + // Determine the best encoding for the current block: dynamic trees, static + // trees or store, and output the encoded block to the zip file. + void _tr_flush_block(int buf, // input block, or NULL if too old + int stored_len, // length of input block + boolean eof // true if this is the last block for a file + ) { + int opt_lenb, static_lenb;// opt_len and static_len in bytes + int max_blindex = 0; // index of last bit length code of non zero freq + + // Build the Huffman trees unless a stored block is forced + if(level > 0) { + // Check if the file is ascii or binary + if(data_type == Z_UNKNOWN) set_data_type(); + + // Construct the literal and distance trees + l_desc.build_tree(this); + + d_desc.build_tree(this); + + // At this point, opt_len and static_len are the total bit lengths of + // the compressed block data, excluding the tree representations. + + // Build the bit length tree for the above two trees, and get the index + // in bl_order of the last bit length code to send. + max_blindex=build_bl_tree(); + + // Determine the best encoding. Compute first the block length in bytes + opt_lenb=(opt_len+3+7)>>>3; + static_lenb=(static_len+3+7)>>>3; + + if(static_lenb<=opt_lenb) opt_lenb=static_lenb; + } + else { + opt_lenb=static_lenb=stored_len+5; // force a stored block + } + + if(stored_len+4<=opt_lenb && buf != -1){ + // 4: two words for the lengths + // The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + // Otherwise we can't have processed more than WSIZE input bytes since + // the last block flush, because compression would have been + // successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + // transform a block into a stored block. + _tr_stored_block(buf, stored_len, eof); + } + else if(static_lenb == opt_lenb){ + send_bits((STATIC_TREES<<1)+(eof?1:0), 3); + compress_block(StaticTree.static_ltree, StaticTree.static_dtree); + } + else{ + send_bits((DYN_TREES<<1)+(eof?1:0), 3); + send_all_trees(l_desc.max_code+1, d_desc.max_code+1, max_blindex+1); + compress_block(dyn_ltree, dyn_dtree); + } + + // The above check is made mod 2^32, for files larger than 512 MB + // and uLong implemented on 32 bits. + + init_block(); + + if(eof){ + bi_windup(); + } + } + + // Fill the window when the lookahead becomes insufficient. + // Updates strstart and lookahead. + // + // IN assertion: lookahead < MIN_LOOKAHEAD + // OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + // At least one byte has been read, or avail_in == 0; reads are + // performed for at least two bytes (required for the zip translate_eol + // option -- not supported here). + void fill_window(){ + int n, m; + int p; + int more; // Amount of free space at the end of the window. + + do{ + more = (window_size-lookahead-strstart); + + // Deal with !@#$% 64K limit: + if(more==0 && strstart==0 && lookahead==0){ + more = w_size; + } + else if(more==-1) { + // Very unlikely, but possible on 16 bit machine if strstart == 0 + // and lookahead == 1 (input done one byte at time) + more--; + + // If the window is almost full and there is insufficient lookahead, + // move the upper half to the lower one to make room in the upper half. + } + else if(strstart >= w_size+ w_size-MIN_LOOKAHEAD) { + System.arraycopy(window, w_size, window, 0, w_size); + match_start-=w_size; + strstart-=w_size; // we now have strstart >= MAX_DIST + block_start-=w_size; + + // Slide the hash table (could be avoided with 32 bit values + // at the expense of memory usage). We slide even when level == 0 + // to keep the hash table consistent if we switch back to level > 0 + // later. (Using level 0 permanently is not an optimal usage of + // zlib, so we don't care about this pathological case.) + + n = hash_size; + p=n; + do { + m = (head[--p]&0xffff); + head[p]=(m>=w_size ? (short)(m-w_size) : 0); + } + while (--n != 0); + + n = w_size; + p = n; + do { + m = (prev[--p]&0xffff); + prev[p] = (m >= w_size ? (short)(m-w_size) : 0); + // If n is not on any hash chain, prev[n] is garbage but + // its value will never be used. + } + while (--n!=0); + more += w_size; + } + + if (strm.avail_in == 0) return; + + // If there was no sliding: + // strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + // more == window_size - lookahead - strstart + // => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + // => more >= window_size - 2*WSIZE + 2 + // In the BIG_MEM or MMAP case (not yet supported), + // window_size == input_size + MIN_LOOKAHEAD && + // strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + // Otherwise, window_size == 2*WSIZE so more >= 2. + // If there was sliding, more >= WSIZE. So in all cases, more >= 2. + + n = strm.read_buf(window, strstart + lookahead, more); + lookahead += n; + + // Initialize the hash value now that we have some input: + if(lookahead >= MIN_MATCH) { + ins_h = window[strstart]&0xff; + ins_h=(((ins_h)<= MIN_MATCH){ + ins_h=(((ins_h)<=MIN_MATCH){ + // check_match(strstart, match_start, match_length); + + bflush=_tr_tally(strstart-match_start, match_length-MIN_MATCH); + + lookahead -= match_length; + + // Insert new strings in the hash table only if the match length + // is not too large. This saves time but degrades compression. + if(match_length <= max_lazy_match && + lookahead >= MIN_MATCH) { + match_length--; // string at strstart already in hash table + do{ + strstart++; + + ins_h=((ins_h<= MIN_MATCH) { + ins_h=(((ins_h)< 4096))) { + + // If prev_match is also MIN_MATCH, match_start is garbage + // but we will ignore the current match anyway. + match_length = MIN_MATCH-1; + } + } + + // If there was a match at the previous step and the current + // match is not better, output the previous match: + if(prev_length >= MIN_MATCH && match_length <= prev_length) { + int max_insert = strstart + lookahead - MIN_MATCH; + // Do not insert strings in hash table beyond this. + + // check_match(strstart-1, prev_match, prev_length); + + bflush=_tr_tally(strstart-1-prev_match, prev_length - MIN_MATCH); + + // Insert in hash table all strings up to the end of the match. + // strstart-1 and strstart are already inserted. If there is not + // enough lookahead, the last two strings are not inserted in + // the hash table. + lookahead -= prev_length-1; + prev_length -= 2; + do{ + if(++strstart <= max_insert) { + ins_h=(((ins_h)<(w_size-MIN_LOOKAHEAD) ? + strstart-(w_size-MIN_LOOKAHEAD) : 0; + int nice_match=this.nice_match; + + // Stop when cur_match becomes <= limit. To simplify the code, + // we prevent matches with the string of window index 0. + + int wmask = w_mask; + + int strend = strstart + MAX_MATCH; + byte scan_end1 = window[scan+best_len-1]; + byte scan_end = window[scan+best_len]; + + // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + // It is easy to get rid of this optimization if necessary. + + // Do not waste too much time if we already have a good match: + if (prev_length >= good_match) { + chain_length >>= 2; + } + + // Do not look for matches beyond the end of the input. This is necessary + // to make deflate deterministic. + if (nice_match > lookahead) nice_match = lookahead; + + do { + match = cur_match; + + // Skip to next match if the match length cannot increase + // or if the match length is less than 2: + if (window[match+best_len] != scan_end || + window[match+best_len-1] != scan_end1 || + window[match] != window[scan] || + window[++match] != window[scan+1]) continue; + + // The check at best_len-1 can be removed because it will be made + // again later. (This heuristic is not always a win.) + // It is not necessary to compare scan[2] and match[2] since they + // are always equal when the other bytes match, given that + // the hash keys are equal and that HASH_BITS >= 8. + scan += 2; match++; + + // We check for insufficient lookahead only every 8th comparison; + // the 256th check will be made at strstart+258. + do { + } while (window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + scan < strend); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + + if(len>best_len) { + match_start = cur_match; + best_len = len; + if (len >= nice_match) break; + scan_end1 = window[scan+best_len-1]; + scan_end = window[scan+best_len]; + } + + } while ((cur_match = (prev[cur_match & wmask]&0xffff)) > limit + && --chain_length != 0); + + if (best_len <= lookahead) return best_len; + return lookahead; + } + + int deflateInit(int level, int bits, int memlevel){ + return deflateInit(level, Z_DEFLATED, bits, memlevel, + Z_DEFAULT_STRATEGY); + } + + int deflateInit(int level, int bits){ + return deflateInit(level, Z_DEFLATED, bits, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY); + } + int deflateInit(int level){ + return deflateInit(level, MAX_WBITS); + } + private int deflateInit(int level, int method, int windowBits, + int memLevel, int strategy){ + int wrap = 1; + // byte[] my_version=ZLIB_VERSION; + + // + // if (version == null || version[0] != my_version[0] + // || stream_size != sizeof(z_stream)) { + // return Z_VERSION_ERROR; + // } + + strm.msg = null; + + if (level == Z_DEFAULT_COMPRESSION) level = 6; + + if (windowBits < 0) { // undocumented feature: suppress zlib header + wrap = 0; + windowBits = -windowBits; + } + else if(windowBits > 15){ + wrap = 2; + windowBits -= 16; + strm.adler=new CRC32(); + } + + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || + method != Z_DEFLATED || + windowBits < 9 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + + strm.dstate = (Deflate)this; + + this.wrap = wrap; + w_bits = windowBits; + w_size = 1 << w_bits; + w_mask = w_size - 1; + + hash_bits = memLevel + 7; + hash_size = 1 << hash_bits; + hash_mask = hash_size - 1; + hash_shift = ((hash_bits+MIN_MATCH-1)/MIN_MATCH); + + window = new byte[w_size*2]; + prev = new short[w_size]; + head = new short[hash_size]; + + lit_bufsize = 1 << (memLevel + 6); // 16K elements by default + + // We overlay pending_buf and d_buf+l_buf. This works since the average + // output size for (length,distance) codes is <= 24 bits. + pending_buf = new byte[lit_bufsize*3]; + pending_buf_size = lit_bufsize*3; + + d_buf = lit_bufsize; + l_buf = new byte[lit_bufsize]; + + this.level = level; + + this.strategy = strategy; + this.method = (byte)method; + + return deflateReset(); + } + + int deflateReset(){ + strm.total_in = strm.total_out = 0; + strm.msg = null; // + strm.data_type = Z_UNKNOWN; + + pending = 0; + pending_out = 0; + + if(wrap < 0){ + wrap = -wrap; + } + status = (wrap==0) ? BUSY_STATE : INIT_STATE; + strm.adler.reset(); + + last_flush = Z_NO_FLUSH; + + tr_init(); + lm_init(); + return Z_OK; + } + + int deflateEnd(){ + if(status!=INIT_STATE && status!=BUSY_STATE && status!=FINISH_STATE){ + return Z_STREAM_ERROR; + } + // Deallocate in reverse order of allocations: + pending_buf=null; + l_buf=null; + head=null; + prev=null; + window=null; + // free + // dstate=null; + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; + } + + int deflateParams(int _level, int _strategy){ + int err=Z_OK; + + if(_level == Z_DEFAULT_COMPRESSION){ + _level = 6; + } + if(_level < 0 || _level > 9 || + _strategy < 0 || _strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + + if(config_table[level].func!=config_table[_level].func && + strm.total_in != 0) { + // Flush the last buffer: + err = strm.deflate(Z_PARTIAL_FLUSH); + } + + if(level != _level) { + level = _level; + max_lazy_match = config_table[level].max_lazy; + good_match = config_table[level].good_length; + nice_match = config_table[level].nice_length; + max_chain_length = config_table[level].max_chain; + } + strategy = _strategy; + return err; + } + + int deflateSetDictionary (byte[] dictionary, int dictLength){ + int length = dictLength; + int index=0; + + if(dictionary == null || status != INIT_STATE) + return Z_STREAM_ERROR; + + strm.adler.update(dictionary, 0, dictLength); + + if(length < MIN_MATCH) return Z_OK; + if(length > w_size-MIN_LOOKAHEAD){ + length = w_size-MIN_LOOKAHEAD; + index=dictLength-length; // use the tail of the dictionary + } + System.arraycopy(dictionary, index, window, 0, length); + strstart = length; + block_start = length; + + // Insert all strings in the hash table (except for the last two bytes). + // s->lookahead stays null, so s->ins_h will be recomputed at the next + // call of fill_window. + + ins_h = window[0]&0xff; + ins_h=(((ins_h)<Z_FINISH || flush<0){ + return Z_STREAM_ERROR; + } + + if(strm.next_out == null || + (strm.next_in == null && strm.avail_in != 0) || + (status == FINISH_STATE && flush != Z_FINISH)) { + strm.msg=z_errmsg[Z_NEED_DICT-(Z_STREAM_ERROR)]; + return Z_STREAM_ERROR; + } + if(strm.avail_out == 0){ + strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)]; + return Z_BUF_ERROR; + } + + old_flush = last_flush; + last_flush = flush; + + // Write the zlib header + if(status == INIT_STATE) { + if(wrap == 2){ + getGZIPHeader().put(this); + status=BUSY_STATE; + strm.adler.reset(); + } + else{ + int header = (Z_DEFLATED+((w_bits-8)<<4))<<8; + int level_flags=((level-1)&0xff)>>1; + + if(level_flags>3) level_flags=3; + header |= (level_flags<<6); + if(strstart!=0) header |= PRESET_DICT; + header+=31-(header % 31); + + status=BUSY_STATE; + putShortMSB(header); + + + // Save the adler32 of the preset dictionary: + if(strstart!=0){ + long adler=strm.adler.getValue(); + putShortMSB((int)(adler>>>16)); + putShortMSB((int)(adler&0xffff)); + } + strm.adler.reset(); + } + } + + // Flush as much pending output as possible + if(pending != 0) { + strm.flush_pending(); + if(strm.avail_out == 0) { + // Since avail_out is 0, deflate will be called again with + // more output space, but possibly with both pending and + // avail_in equal to zero. There won't be anything to do, + // but this is not an error situation so make sure we + // return OK instead of BUF_ERROR at next call of deflate: + last_flush = -1; + return Z_OK; + } + + // Make sure there is something to do and avoid duplicate consecutive + // flushes. For repeated and useless calls with Z_FINISH, we keep + // returning Z_STREAM_END instead of Z_BUFF_ERROR. + } + else if(strm.avail_in==0 && flush <= old_flush && + flush != Z_FINISH) { + strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)]; + return Z_BUF_ERROR; + } + + // User must not provide more input after the first FINISH: + if(status == FINISH_STATE && strm.avail_in != 0) { + strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)]; + return Z_BUF_ERROR; + } + + // Start a new block or continue the current one. + if(strm.avail_in!=0 || lookahead!=0 || + (flush != Z_NO_FLUSH && status != FINISH_STATE)) { + int bstate=-1; + switch(config_table[level].func){ + case STORED: + bstate = deflate_stored(flush); + break; + case FAST: + bstate = deflate_fast(flush); + break; + case SLOW: + bstate = deflate_slow(flush); + break; + default: + } + + if (bstate==FinishStarted || bstate==FinishDone) { + status = FINISH_STATE; + } + if (bstate==NeedMore || bstate==FinishStarted) { + if(strm.avail_out == 0) { + last_flush = -1; // avoid BUF_ERROR next call, see above + } + return Z_OK; + // If flush != Z_NO_FLUSH && avail_out == 0, the next call + // of deflate should use the same flush parameter to make sure + // that the flush is complete. So we don't have to output an + // empty block here, this will be done at next call. This also + // ensures that for a very small output buffer, we emit at most + // one empty block. + } + + if (bstate==BlockDone) { + if(flush == Z_PARTIAL_FLUSH) { + _tr_align(); + } + else { // FULL_FLUSH or SYNC_FLUSH + _tr_stored_block(0, 0, false); + // For a full flush, this empty block will be recognized + // as a special marker by inflate_sync(). + if(flush == Z_FULL_FLUSH) { + //state.head[s.hash_size-1]=0; + for(int i=0; i>8)&0xff)); + put_byte((byte)((adler>>16)&0xff)); + put_byte((byte)((adler>>24)&0xff)); + put_byte((byte)(strm.total_in&0xff)); + put_byte((byte)((strm.total_in>>8)&0xff)); + put_byte((byte)((strm.total_in>>16)&0xff)); + put_byte((byte)((strm.total_in>>24)&0xff)); + + getGZIPHeader().setCRC(adler); + } + else{ + // Write the zlib trailer (adler32) + long adler=strm.adler.getValue(); + putShortMSB((int)(adler>>>16)); + putShortMSB((int)(adler&0xffff)); + } + + strm.flush_pending(); + + // If avail_out is zero, the application will call deflate again + // to flush the rest. + + if(wrap > 0) wrap = -wrap; // write the trailer only once! + return pending != 0 ? Z_OK : Z_STREAM_END; + } + + static int deflateCopy(ZStream dest, ZStream src){ + + if(src.dstate == null){ + return Z_STREAM_ERROR; + } + + if(src.next_in!=null){ + dest.next_in = new byte[src.next_in.length]; + System.arraycopy(src.next_in, 0, dest.next_in, 0, src.next_in.length); + } + dest.next_in_index = src.next_in_index; + dest.avail_in = src.avail_in; + dest.total_in = src.total_in; + + if(src.next_out!=null){ + dest.next_out = new byte[src.next_out.length]; + System.arraycopy(src.next_out, 0, dest.next_out ,0 , src.next_out.length); + } + + dest.next_out_index = src.next_out_index; + dest.avail_out = src.avail_out; + dest.total_out = src.total_out; + + dest.msg = src.msg; + dest.data_type = src.data_type; + dest.adler = src.adler.copy(); + + try{ + dest.dstate = (Deflate)src.dstate.clone(); + dest.dstate.strm = dest; + } + catch(CloneNotSupportedException e){ + // + } + return Z_OK; + } + + public Object clone() throws CloneNotSupportedException { + Deflate dest = (Deflate)super.clone(); + + dest.pending_buf = dup(dest.pending_buf); + dest.d_buf = dest.d_buf; + dest.l_buf = dup(dest.l_buf); + dest.window = dup(dest.window); + + dest.prev = dup(dest.prev); + dest.head = dup(dest.head); + dest.dyn_ltree = dup(dest.dyn_ltree); + dest.dyn_dtree = dup(dest.dyn_dtree); + dest.bl_tree = dup(dest.bl_tree); + + dest.bl_count = dup(dest.bl_count); + dest.next_code = dup(dest.next_code); + dest.heap = dup(dest.heap); + dest.depth = dup(dest.depth); + + dest.l_desc.dyn_tree = dest.dyn_ltree; + dest.d_desc.dyn_tree = dest.dyn_dtree; + dest.bl_desc.dyn_tree = dest.bl_tree; + + /* + dest.l_desc.stat_desc = StaticTree.static_l_desc; + dest.d_desc.stat_desc = StaticTree.static_d_desc; + dest.bl_desc.stat_desc = StaticTree.static_bl_desc; + */ + + if(dest.gheader!=null){ + dest.gheader = (GZIPHeader)dest.gheader.clone(); + } + + return dest; + } + + private byte[] dup(byte[] buf){ + byte[] foo = new byte[buf.length]; + System.arraycopy(buf, 0, foo, 0, foo.length); + return foo; + } + private short[] dup(short[] buf){ + short[] foo = new short[buf.length]; + System.arraycopy(buf, 0, foo, 0, foo.length); + return foo; + } + private int[] dup(int[] buf){ + int[] foo = new int[buf.length]; + System.arraycopy(buf, 0, foo, 0, foo.length); + return foo; + } + + synchronized GZIPHeader getGZIPHeader(){ + if(gheader==null){ + gheader = new GZIPHeader(); + } + return gheader; + } +} diff --git a/src/lwjgl/java/com/jcraft/jzlib/Deflater.java b/src/lwjgl/java/com/jcraft/jzlib/Deflater.java new file mode 100644 index 0000000..ce0580d --- /dev/null +++ b/src/lwjgl/java/com/jcraft/jzlib/Deflater.java @@ -0,0 +1,171 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package com.jcraft.jzlib; + +final public class Deflater extends ZStream{ + + static final private int MAX_WBITS=15; // 32K LZ77 window + static final private int DEF_WBITS=MAX_WBITS; + + static final private int Z_NO_FLUSH=0; + static final private int Z_PARTIAL_FLUSH=1; + static final private int Z_SYNC_FLUSH=2; + static final private int Z_FULL_FLUSH=3; + static final private int Z_FINISH=4; + + static final private int MAX_MEM_LEVEL=9; + + static final private int Z_OK=0; + static final private int Z_STREAM_END=1; + static final private int Z_NEED_DICT=2; + static final private int Z_ERRNO=-1; + static final private int Z_STREAM_ERROR=-2; + static final private int Z_DATA_ERROR=-3; + static final private int Z_MEM_ERROR=-4; + static final private int Z_BUF_ERROR=-5; + static final private int Z_VERSION_ERROR=-6; + + private boolean finished = false; + + public Deflater(){ + super(); + } + + public Deflater(int level) throws GZIPException { + this(level, MAX_WBITS); + } + + public Deflater(int level, boolean nowrap) throws GZIPException { + this(level, MAX_WBITS, nowrap); + } + + public Deflater(int level, int bits) throws GZIPException { + this(level, bits, false); + } + + public Deflater(int level, int bits, boolean nowrap) throws GZIPException { + super(); + int ret = init(level, bits, nowrap); + if(ret!=Z_OK) + throw new GZIPException(ret+": "+msg); + } + + public Deflater(int level, int bits, int memlevel, JZlib.WrapperType wrapperType) throws GZIPException { + super(); + int ret = init(level, bits, memlevel, wrapperType); + if(ret!=Z_OK) + throw new GZIPException(ret+": "+msg); + } + + public Deflater(int level, int bits, int memlevel) throws GZIPException { + super(); + int ret = init(level, bits, memlevel); + if(ret!=Z_OK) + throw new GZIPException(ret+": "+msg); + } + + public int init(int level){ + return init(level, MAX_WBITS); + } + public int init(int level, boolean nowrap){ + return init(level, MAX_WBITS, nowrap); + } + public int init(int level, int bits){ + return init(level, bits, false); + } + public int init(int level, int bits, int memlevel, JZlib.WrapperType wrapperType){ + if(bits < 9 || bits > 15){ + return Z_STREAM_ERROR; + } + if(wrapperType == JZlib.W_NONE) { + bits *= -1; + } + else if(wrapperType == JZlib.W_GZIP) { + bits += 16; + } + else if(wrapperType == JZlib.W_ANY) { + return Z_STREAM_ERROR; + } + else if(wrapperType == JZlib.W_ZLIB) { + } + return init(level, bits, memlevel); + } + public int init(int level, int bits, int memlevel){ + finished = false; + dstate=new Deflate(this); + return dstate.deflateInit(level, bits, memlevel); + } + public int init(int level, int bits, boolean nowrap){ + finished = false; + dstate=new Deflate(this); + return dstate.deflateInit(level, nowrap?-bits:bits); + } + + public int deflate(int flush){ + if(dstate==null){ + return Z_STREAM_ERROR; + } + int ret = dstate.deflate(flush); + if(ret == Z_STREAM_END) + finished = true; + return ret; + } + public int end(){ + finished = true; + if(dstate==null) return Z_STREAM_ERROR; + int ret=dstate.deflateEnd(); + dstate=null; + free(); + return ret; + } + public int params(int level, int strategy){ + if(dstate==null) return Z_STREAM_ERROR; + return dstate.deflateParams(level, strategy); + } + public int setDictionary (byte[] dictionary, int dictLength){ + if(dstate == null) + return Z_STREAM_ERROR; + return dstate.deflateSetDictionary(dictionary, dictLength); + } + + public boolean finished(){ + return finished; + } + + public int copy(Deflater src){ + this.finished = src.finished; + return Deflate.deflateCopy(this, src); + } +} diff --git a/src/lwjgl/java/com/jcraft/jzlib/DeflaterOutputStream.java b/src/lwjgl/java/com/jcraft/jzlib/DeflaterOutputStream.java new file mode 100644 index 0000000..3c18836 --- /dev/null +++ b/src/lwjgl/java/com/jcraft/jzlib/DeflaterOutputStream.java @@ -0,0 +1,181 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jcraft.jzlib; +import java.io.*; + +public class DeflaterOutputStream extends FilterOutputStream { + + protected final Deflater deflater; + + protected byte[] buffer; + + private boolean closed = false; + + private boolean syncFlush = false; + + private final byte[] buf1 = new byte[1]; + + protected boolean mydeflater = false; + + private boolean close_out = true; + + protected static final int DEFAULT_BUFSIZE = 512; + + public DeflaterOutputStream(OutputStream out) throws IOException { + this(out, + new Deflater(JZlib.Z_DEFAULT_COMPRESSION), + DEFAULT_BUFSIZE, true); + mydeflater = true; + } + + public DeflaterOutputStream(OutputStream out, Deflater def) throws IOException { + this(out, def, DEFAULT_BUFSIZE, true); + } + + public DeflaterOutputStream(OutputStream out, + Deflater deflater, + int size) throws IOException { + this(out, deflater, size, true); + } + public DeflaterOutputStream(OutputStream out, + Deflater deflater, + int size, + boolean close_out) throws IOException { + super(out); + if (out == null || deflater == null) { + throw new NullPointerException(); + } + else if (size <= 0) { + throw new IllegalArgumentException("buffer size must be greater than 0"); + } + this.deflater = deflater; + buffer = new byte[size]; + this.close_out = close_out; + } + + public void write(int b) throws IOException { + buf1[0] = (byte)(b & 0xff); + write(buf1, 0, 1); + } + + public void write(byte[] b, int off, int len) throws IOException { + if (deflater.finished()) { + throw new IOException("finished"); + } + else if (off<0 | len<0 | off+len>b.length) { + throw new IndexOutOfBoundsException(); + } + else if (len == 0) { + return; + } + else { + int flush = syncFlush ? JZlib.Z_SYNC_FLUSH : JZlib.Z_NO_FLUSH; + deflater.setInput(b, off, len, true); + while (deflater.avail_in>0) { + int err = deflate(flush); + if (err == JZlib.Z_STREAM_END) + break; + } + } + } + + public void finish() throws IOException { + while (!deflater.finished()) { + deflate(JZlib.Z_FINISH); + } + } + + public void close() throws IOException { + if (!closed) { + finish(); + if (mydeflater){ + deflater.end(); + } + if(close_out) + out.close(); + closed = true; + } + } + + protected int deflate(int flush) throws IOException { + deflater.setOutput(buffer, 0, buffer.length); + int err = deflater.deflate(flush); + switch(err) { + case JZlib.Z_OK: + case JZlib.Z_STREAM_END: + break; + case JZlib.Z_BUF_ERROR: + if(deflater.avail_in<=0 && flush!=JZlib.Z_FINISH){ + // flush() without any data + break; + } + default: + throw new IOException("failed to deflate: error="+err+" avail_out="+deflater.avail_out); + } + int len = deflater.next_out_index; + if (len > 0) { + out.write(buffer, 0, len); + } + return err; + } + + public void flush() throws IOException { + if (syncFlush && !deflater.finished()) { + while (true) { + int err = deflate(JZlib.Z_SYNC_FLUSH); + if (deflater.next_out_index < buffer.length) + break; + if (err == JZlib.Z_STREAM_END) + break; + } + } + out.flush(); + } + + public long getTotalIn() { + return deflater.getTotalIn(); + } + + public long getTotalOut() { + return deflater.getTotalOut(); + } + + public void setSyncFlush(boolean syncFlush){ + this.syncFlush = syncFlush; + } + + public boolean getSyncFlush(){ + return this.syncFlush; + } + + public Deflater getDeflater(){ + return deflater; + } +} diff --git a/src/lwjgl/java/com/jcraft/jzlib/GZIPException.java b/src/lwjgl/java/com/jcraft/jzlib/GZIPException.java new file mode 100644 index 0000000..0beef40 --- /dev/null +++ b/src/lwjgl/java/com/jcraft/jzlib/GZIPException.java @@ -0,0 +1,44 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package com.jcraft.jzlib; + +public class GZIPException extends java.io.IOException { + public GZIPException() { + super(); + } + public GZIPException(String s) { + super(s); + } +} diff --git a/src/lwjgl/java/com/jcraft/jzlib/GZIPHeader.java b/src/lwjgl/java/com/jcraft/jzlib/GZIPHeader.java new file mode 100644 index 0000000..0405e00 --- /dev/null +++ b/src/lwjgl/java/com/jcraft/jzlib/GZIPHeader.java @@ -0,0 +1,214 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package com.jcraft.jzlib; + +import java.io.UnsupportedEncodingException; + +/** + * @see "http://www.ietf.org/rfc/rfc1952.txt" + */ +public class GZIPHeader implements Cloneable { + + public static final byte OS_MSDOS = (byte) 0x00; + public static final byte OS_AMIGA = (byte) 0x01; + public static final byte OS_VMS = (byte) 0x02; + public static final byte OS_UNIX = (byte) 0x03; + public static final byte OS_ATARI = (byte) 0x05; + public static final byte OS_OS2 = (byte) 0x06; + public static final byte OS_MACOS = (byte) 0x07; + public static final byte OS_TOPS20 = (byte) 0x0a; + public static final byte OS_WIN32 = (byte) 0x0b; + public static final byte OS_VMCMS = (byte) 0x04; + public static final byte OS_ZSYSTEM = (byte) 0x08; + public static final byte OS_CPM = (byte) 0x09; + public static final byte OS_QDOS = (byte) 0x0c; + public static final byte OS_RISCOS = (byte) 0x0d; + public static final byte OS_UNKNOWN = (byte) 0xff; + + boolean text = false; + private boolean fhcrc = false; + long time; + int xflags; + int os = 255; + byte[] extra; + byte[] name; + byte[] comment; + int hcrc; + long crc; + boolean done = false; + long mtime = 0; + + public void setModifiedTime(long mtime) { + this.mtime = mtime; + } + + public long getModifiedTime() { + return mtime; + } + + public void setOS(int os) { + if((0<=os && os <=13) || os==255) + this.os=os; + else + throw new IllegalArgumentException("os: "+os); + } + + public int getOS(){ + return os; + } + + public void setName(String name) { + try{ + this.name=name.getBytes("ISO-8859-1"); + } + catch(UnsupportedEncodingException e){ + throw new IllegalArgumentException("name must be in ISO-8859-1 "+name); + } + } + + public String getName(){ + if(name==null) return ""; + try { + return new String(name, "ISO-8859-1"); + } + catch (UnsupportedEncodingException e) { + throw new InternalError(e.toString()); + } + } + + public void setComment(String comment) { + try{ + this.comment=comment.getBytes("ISO-8859-1"); + } + catch(UnsupportedEncodingException e){ + throw new IllegalArgumentException("comment must be in ISO-8859-1 "+name); + } + } + + public String getComment(){ + if(comment==null) return ""; + try { + return new String(comment, "ISO-8859-1"); + } + catch (UnsupportedEncodingException e) { + throw new InternalError(e.toString()); + } + } + + public void setCRC(long crc){ + this.crc = crc; + } + + public long getCRC(){ + return crc; + } + + void put(Deflate d){ + int flag = 0; + if(text){ + flag |= 1; // FTEXT + } + if(fhcrc){ + flag |= 2; // FHCRC + } + if(extra!=null){ + flag |= 4; // FEXTRA + } + if(name!=null){ + flag |= 8; // FNAME + } + if(comment!=null){ + flag |= 16; // FCOMMENT + } + int xfl = 0; + if(d.level == JZlib.Z_BEST_SPEED){ + xfl |= 4; + } + else if (d.level == JZlib.Z_BEST_COMPRESSION){ + xfl |= 2; + } + + d.put_short((short)0x8b1f); // ID1 ID2 + d.put_byte((byte)8); // CM(Compression Method) + d.put_byte((byte)flag); + d.put_byte((byte)mtime); + d.put_byte((byte)(mtime>>8)); + d.put_byte((byte)(mtime>>16)); + d.put_byte((byte)(mtime>>24)); + d.put_byte((byte)xfl); + d.put_byte((byte)os); + + if(extra!=null){ + d.put_byte((byte)extra.length); + d.put_byte((byte)(extra.length>>8)); + d.put_byte(extra, 0, extra.length); + } + + if(name!=null){ + d.put_byte(name, 0, name.length); + d.put_byte((byte)0); + } + + if(comment!=null){ + d.put_byte(comment, 0, comment.length); + d.put_byte((byte)0); + } + } + + @Override + public Object clone() throws CloneNotSupportedException { + GZIPHeader gheader = (GZIPHeader)super.clone(); + byte[] tmp; + if(gheader.extra!=null){ + tmp=new byte[gheader.extra.length]; + System.arraycopy(gheader.extra, 0, tmp, 0, tmp.length); + gheader.extra = tmp; + } + + if(gheader.name!=null){ + tmp=new byte[gheader.name.length]; + System.arraycopy(gheader.name, 0, tmp, 0, tmp.length); + gheader.name = tmp; + } + + if(gheader.comment!=null){ + tmp=new byte[gheader.comment.length]; + System.arraycopy(gheader.comment, 0, tmp, 0, tmp.length); + gheader.comment = tmp; + } + + return gheader; + } +} diff --git a/src/lwjgl/java/com/jcraft/jzlib/GZIPInputStream.java b/src/lwjgl/java/com/jcraft/jzlib/GZIPInputStream.java new file mode 100644 index 0000000..5d29dca --- /dev/null +++ b/src/lwjgl/java/com/jcraft/jzlib/GZIPInputStream.java @@ -0,0 +1,145 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jcraft.jzlib; +import java.io.*; + +public class GZIPInputStream extends InflaterInputStream { + + public GZIPInputStream(InputStream in) throws IOException { + this(in, DEFAULT_BUFSIZE, true); + } + + public GZIPInputStream(InputStream in, + int size, + boolean close_in) throws IOException { + this(in, new Inflater(15+16), size, close_in); + myinflater = true; + } + + public GZIPInputStream(InputStream in, + Inflater inflater, + int size, + boolean close_in) throws IOException { + super(in, inflater, size, close_in); + } + + public long getModifiedtime() { + return inflater.istate.getGZIPHeader().getModifiedTime(); + } + + public int getOS() { + return inflater.istate.getGZIPHeader().getOS(); + } + + public String getName() { + return inflater.istate.getGZIPHeader().getName(); + } + + public String getComment() { + return inflater.istate.getGZIPHeader().getComment(); + } + + public long getCRC() throws GZIPException { + if(inflater.istate.mode != 12 /*DONE*/) + throw new GZIPException("checksum is not calculated yet."); + return inflater.istate.getGZIPHeader().getCRC(); + } + + public void readHeader() throws IOException { + + byte[] empty = "".getBytes(); + inflater.setOutput(empty, 0, 0); + inflater.setInput(empty, 0, 0, false); + + byte[] b = new byte[10]; + + int n = fill(b); + if(n!=10){ + if(n>0){ + inflater.setInput(b, 0, n, false); + //inflater.next_in_index = n; + inflater.next_in_index = 0; + inflater.avail_in = n; + } + throw new IOException("no input"); + } + + inflater.setInput(b, 0, n, false); + + byte[] b1 = new byte[1]; + do{ + if(inflater.avail_in<=0){ + int i = in.read(b1); + if(i<=0) + throw new IOException("no input"); + inflater.setInput(b1, 0, 1, true); + } + + int err = inflater.inflate(JZlib.Z_NO_FLUSH); + + if(err!=0/*Z_OK*/){ + int len = 2048-inflater.next_in.length; + if(len>0){ + byte[] tmp = new byte[len]; + n = fill(tmp); + if(n>0){ + inflater.avail_in += inflater.next_in_index; + inflater.next_in_index = 0; + inflater.setInput(tmp, 0, n, true); + } + } + //inflater.next_in_index = inflater.next_in.length; + inflater.avail_in += inflater.next_in_index; + inflater.next_in_index = 0; + throw new IOException(inflater.msg); + } + } + while(inflater.istate.inParsingHeader()); + } + + private int fill(byte[] buf) { + int len = buf.length; + int n = 0; + do{ + int i = -1; + try { + i = in.read(buf, n, buf.length - n); + } + catch(IOException e){ + } + if(i == -1){ + break; + } + n+=i; + } + while(n>> 1){ + case 0: // stored + {b>>>=(3);k-=(3);} + t = k & 7; // go to byte boundary + + {b>>>=(t);k-=(t);} + mode = LENS; // get length of stored block + break; + case 1: // fixed + InfTree.inflate_trees_fixed(bl, bd, tl, td, z); + codes.init(bl[0], bd[0], tl[0], 0, td[0], 0); + + {b>>>=(3);k-=(3);} + + mode = CODES; + break; + case 2: // dynamic + + {b>>>=(3);k-=(3);} + + mode = TABLE; + break; + case 3: // illegal + + {b>>>=(3);k-=(3);} + mode = BAD; + z.msg = "invalid block type"; + r = Z_DATA_ERROR; + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(r); + } + break; + case LENS: + + while(k<(32)){ + if(n!=0){ + r=Z_OK; + } + else{ + bitb=b; bitk=k; + z.avail_in=n; + z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(r); + }; + n--; + b|=(z.next_in[p++]&0xff)<>> 16) & 0xffff) != (b & 0xffff)){ + mode = BAD; + z.msg = "invalid stored block lengths"; + r = Z_DATA_ERROR; + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(r); + } + left = (b & 0xffff); + b = k = 0; // dump bits + mode = left!=0 ? STORED : (last!=0 ? DRY : TYPE); + break; + case STORED: + if (n == 0){ + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(r); + } + + if(m==0){ + if(q==end&&read!=0){ + q=0; m=(int)(qn) t = n; + if(t>m) t = m; + System.arraycopy(z.next_in, p, window, q, t); + p += t; n -= t; + q += t; m -= t; + if ((left -= t) != 0) + break; + mode = last!=0 ? DRY : TYPE; + break; + case TABLE: + + while(k<(14)){ + if(n!=0){ + r=Z_OK; + } + else{ + bitb=b; bitk=k; + z.avail_in=n; + z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(r); + }; + n--; + b|=(z.next_in[p++]&0xff)< 29 || ((t >> 5) & 0x1f) > 29) + { + mode = BAD; + z.msg = "too many length or distance symbols"; + r = Z_DATA_ERROR; + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(r); + } + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if(blens==null || blens.length>>=(14);k-=(14);} + + index = 0; + mode = BTREE; + case BTREE: + while (index < 4 + (table >>> 10)){ + while(k<(3)){ + if(n!=0){ + r=Z_OK; + } + else{ + bitb=b; bitk=k; + z.avail_in=n; + z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(r); + }; + n--; + b|=(z.next_in[p++]&0xff)<>>=(3);k-=(3);} + } + + while(index < 19){ + blens[border[index++]] = 0; + } + + bb[0] = 7; + t = inftree.inflate_trees_bits(blens, bb, tb, hufts, z); + if (t != Z_OK){ + r = t; + if (r == Z_DATA_ERROR){ + blens=null; + mode = BAD; + } + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(r); + } + + index = 0; + mode = DTREE; + case DTREE: + while (true){ + t = table; + if(!(index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))){ + break; + } + + int[] h; + int i, j, c; + + t = bb[0]; + + while(k<(t)){ + if(n!=0){ + r=Z_OK; + } + else{ + bitb=b; bitk=k; + z.avail_in=n; + z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(r); + }; + n--; + b|=(z.next_in[p++]&0xff)<>>=(t);k-=(t); + blens[index++] = c; + } + else { // c == 16..18 + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + + while(k<(t+i)){ + if(n!=0){ + r=Z_OK; + } + else{ + bitb=b; bitk=k; + z.avail_in=n; + z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(r); + }; + n--; + b|=(z.next_in[p++]&0xff)<>>=(t);k-=(t); + + j += (b & inflate_mask[i]); + + b>>>=(i);k-=(i); + + i = index; + t = table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)){ + blens=null; + mode = BAD; + z.msg = "invalid bit length repeat"; + r = Z_DATA_ERROR; + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(r); + } + + c = c == 16 ? blens[i-1] : 0; + do{ + blens[i++] = c; + } + while (--j!=0); + index = i; + } + } + + tb[0]=-1; + { + bl[0] = 9; // must be <= 9 for lookahead assumptions + bd[0] = 6; // must be <= 9 for lookahead assumptions + t = table; + t = inftree.inflate_trees_dynamic(257 + (t & 0x1f), + 1 + ((t >> 5) & 0x1f), + blens, bl, bd, tli, tdi, hufts, z); + + if (t != Z_OK){ + if (t == Z_DATA_ERROR){ + blens=null; + mode = BAD; + } + r = t; + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(r); + } + codes.init(bl[0], bd[0], hufts, tli[0], hufts, tdi[0]); + } + mode = CODES; + case CODES: + bitb=b; bitk=k; + z.avail_in=n; z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + + if ((r = codes.proc(r)) != Z_STREAM_END){ + return inflate_flush(r); + } + r = Z_OK; + codes.free(z); + + p=z.next_in_index; n=z.avail_in;b=bitb;k=bitk; + q=write;m=(int)(q z.avail_out) n = z.avail_out; + if(n!=0 && r == Z_BUF_ERROR) r = Z_OK; + + // update counters + z.avail_out -= n; + z.total_out += n; + + // update check information + if(check && n>0){ + z.adler.update(window, q, n); + } + + // copy as far as end of window + System.arraycopy(window, q, z.next_out, p, n); + p += n; + q += n; + + // see if more to copy at beginning of window + if (q == end){ + // wrap pointers + q = 0; + if (write == end) + write = 0; + + // compute bytes to copy + n = write - q; + if (n > z.avail_out) n = z.avail_out; + if (n!=0 && r == Z_BUF_ERROR) r = Z_OK; + + // update counters + z.avail_out -= n; + z.total_out += n; + + // update check information + if(check && n>0){ + z.adler.update(window, q, n); + } + + // copy + System.arraycopy(window, q, z.next_out, p, n); + p += n; + q += n; + } + + // update pointers + z.next_out_index = p; + read = q; + + // done + return r; + } +} diff --git a/src/lwjgl/java/com/jcraft/jzlib/InfCodes.java b/src/lwjgl/java/com/jcraft/jzlib/InfCodes.java new file mode 100644 index 0000000..aaf69cd --- /dev/null +++ b/src/lwjgl/java/com/jcraft/jzlib/InfCodes.java @@ -0,0 +1,610 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package com.jcraft.jzlib; + +final class InfCodes{ + + static final private int[] inflate_mask = { + 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, + 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, + 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, + 0x00007fff, 0x0000ffff + }; + + static final private int Z_OK=0; + static final private int Z_STREAM_END=1; + static final private int Z_NEED_DICT=2; + static final private int Z_ERRNO=-1; + static final private int Z_STREAM_ERROR=-2; + static final private int Z_DATA_ERROR=-3; + static final private int Z_MEM_ERROR=-4; + static final private int Z_BUF_ERROR=-5; + static final private int Z_VERSION_ERROR=-6; + + // waiting for "i:"=input, + // "o:"=output, + // "x:"=nothing + static final private int START=0; // x: set up for LEN + static final private int LEN=1; // i: get length/literal/eob next + static final private int LENEXT=2; // i: getting length extra (have base) + static final private int DIST=3; // i: get distance next + static final private int DISTEXT=4;// i: getting distance extra + static final private int COPY=5; // o: copying bytes in window, waiting for space + static final private int LIT=6; // o: got literal, waiting for output space + static final private int WASH=7; // o: got eob, possibly still output waiting + static final private int END=8; // x: got eob and all data flushed + static final private int BADCODE=9;// x: got error + + int mode; // current inflate_codes mode + + // mode dependent information + int len; + + int[] tree; // pointer into tree + int tree_index=0; + int need; // bits needed + + int lit; + + // if EXT or COPY, where and how much + int get; // bits to get for extra + int dist; // distance back to copy from + + byte lbits; // ltree bits decoded per branch + byte dbits; // dtree bits decoder per branch + int[] ltree; // literal/length/eob tree + int ltree_index; // literal/length/eob tree + int[] dtree; // distance tree + int dtree_index; // distance tree + + private final ZStream z; + private final InfBlocks s; + InfCodes(ZStream z, InfBlocks s){ + this.z=z; + this.s=s; + } + + void init(int bl, int bd, + int[] tl, int tl_index, + int[] td, int td_index){ + mode=START; + lbits=(byte)bl; + dbits=(byte)bd; + ltree=tl; + ltree_index=tl_index; + dtree = td; + dtree_index=td_index; + tree=null; + } + + int proc(int r){ + int j; // temporary storage + int[] t; // temporary pointer + int tindex; // temporary pointer + int e; // extra bits or operation + int b=0; // bit buffer + int k=0; // bits in bit buffer + int p=0; // input data pointer + int n; // bytes available there + int q; // output window write pointer + int m; // bytes to end of window or read pointer + int f; // pointer to copy strings from + + // copy input/output information to locals (UPDATE macro restores) + p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk; + q=s.write;m=q= 258 && n >= 10){ + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + r = inflate_fast(lbits, dbits, + ltree, ltree_index, + dtree, dtree_index, + s, z); + + p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk; + q=s.write;m=q>>=(tree[tindex+1]); + k-=(tree[tindex+1]); + + e=tree[tindex]; + + if(e == 0){ // literal + lit = tree[tindex+2]; + mode = LIT; + break; + } + if((e & 16)!=0 ){ // length + get = e & 15; + len = tree[tindex+2]; + mode = LENEXT; + break; + } + if ((e & 64) == 0){ // next table + need = e; + tree_index = tindex/3+tree[tindex+2]; + break; + } + if ((e & 32)!=0){ // end of block + mode = WASH; + break; + } + mode = BADCODE; // invalid code + z.msg = "invalid literal/length code"; + r = Z_DATA_ERROR; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + return s.inflate_flush(r); + + case LENEXT: // i: getting length extra (have base) + j = get; + + while(k<(j)){ + if(n!=0)r=Z_OK; + else{ + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + return s.inflate_flush(r); + } + n--; b|=(z.next_in[p++]&0xff)<>=j; + k-=j; + + need = dbits; + tree = dtree; + tree_index=dtree_index; + mode = DIST; + case DIST: // i: get distance next + j = need; + + while(k<(j)){ + if(n!=0)r=Z_OK; + else{ + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + return s.inflate_flush(r); + } + n--; b|=(z.next_in[p++]&0xff)<>=tree[tindex+1]; + k-=tree[tindex+1]; + + e = (tree[tindex]); + if((e & 16)!=0){ // distance + get = e & 15; + dist = tree[tindex+2]; + mode = DISTEXT; + break; + } + if ((e & 64) == 0){ // next table + need = e; + tree_index = tindex/3 + tree[tindex+2]; + break; + } + mode = BADCODE; // invalid code + z.msg = "invalid distance code"; + r = Z_DATA_ERROR; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + return s.inflate_flush(r); + + case DISTEXT: // i: getting distance extra + j = get; + + while(k<(j)){ + if(n!=0)r=Z_OK; + else{ + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + return s.inflate_flush(r); + } + n--; b|=(z.next_in[p++]&0xff)<>=j; + k-=j; + + mode = COPY; + case COPY: // o: copying bytes in window, waiting for space + f = q - dist; + while(f < 0){ // modulo window size-"while" instead + f += s.end; // of "if" handles invalid distances + } + while (len!=0){ + + if(m==0){ + if(q==s.end&&s.read!=0){q=0;m=q 7){ // return unused byte, if any + k -= 8; + n++; + p--; // can always return one + } + + s.write=q; r=s.inflate_flush(r); + q=s.write;m=q= 258 && n >= 10 + // get literal/length code + while(k<(20)){ // max bits for literal/length code + n--; + b|=(z.next_in[p++]&0xff)<>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); + + s.window[q++] = (byte)tp[tp_index_t_3+2]; + m--; + continue; + } + do { + + b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); + + if((e&16)!=0){ + e &= 15; + c = tp[tp_index_t_3+2] + ((int)b & inflate_mask[e]); + + b>>=e; k-=e; + + // decode distance base of block to copy + while(k<(15)){ // max bits for distance code + n--; + b|=(z.next_in[p++]&0xff)<>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); + + if((e&16)!=0){ + // get extra bits to add to distance base + e &= 15; + while(k<(e)){ // get extra bits (up to 13) + n--; + b|=(z.next_in[p++]&0xff)<>=(e); k-=(e); + + // do the copy + m -= c; + if (q >= d){ // offset before dest + // just copy + r=q-d; + if(q-r>0 && 2>(q-r)){ + s.window[q++]=s.window[r++]; // minimum count is three, + s.window[q++]=s.window[r++]; // so unroll loop a little + c-=2; + } + else{ + System.arraycopy(s.window, r, s.window, q, 2); + q+=2; r+=2; c-=2; + } + } + else{ // else offset after destination + r=q-d; + do{ + r+=s.end; // force pointer in window + }while(r<0); // covers invalid distances + e=s.end-r; + if(c>e){ // if source crosses, + c-=e; // wrapped copy + if(q-r>0 && e>(q-r)){ + do{s.window[q++] = s.window[r++];} + while(--e!=0); + } + else{ + System.arraycopy(s.window, r, s.window, q, e); + q+=e; r+=e; e=0; + } + r = 0; // copy rest from start of window + } + + } + + // copy all or what's left + if(q-r>0 && c>(q-r)){ + do{s.window[q++] = s.window[r++];} + while(--c!=0); + } + else{ + System.arraycopy(s.window, r, s.window, q, c); + q+=c; r+=c; c=0; + } + break; + } + else if((e&64)==0){ + t+=tp[tp_index_t_3+2]; + t+=(b&inflate_mask[e]); + tp_index_t_3=(tp_index+t)*3; + e=tp[tp_index_t_3]; + } + else{ + z.msg = "invalid distance code"; + + c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + + return Z_DATA_ERROR; + } + } + while(true); + break; + } + + if((e&64)==0){ + t+=tp[tp_index_t_3+2]; + t+=(b&inflate_mask[e]); + tp_index_t_3=(tp_index+t)*3; + if((e=tp[tp_index_t_3])==0){ + + b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); + + s.window[q++]=(byte)tp[tp_index_t_3+2]; + m--; + break; + } + } + else if((e&32)!=0){ + + c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + + return Z_STREAM_END; + } + else{ + z.msg="invalid literal/length code"; + + c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + + return Z_DATA_ERROR; + } + } + while(true); + } + while(m>=258 && n>= 10); + + // not enough input or output--restore pointers and return + c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + + return Z_OK; + } +} diff --git a/src/lwjgl/java/com/jcraft/jzlib/InfTree.java b/src/lwjgl/java/com/jcraft/jzlib/InfTree.java new file mode 100644 index 0000000..80a2b7b --- /dev/null +++ b/src/lwjgl/java/com/jcraft/jzlib/InfTree.java @@ -0,0 +1,518 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package com.jcraft.jzlib; + +final class InfTree{ + + static final private int MANY=1440; + + static final private int Z_OK=0; + static final private int Z_STREAM_END=1; + static final private int Z_NEED_DICT=2; + static final private int Z_ERRNO=-1; + static final private int Z_STREAM_ERROR=-2; + static final private int Z_DATA_ERROR=-3; + static final private int Z_MEM_ERROR=-4; + static final private int Z_BUF_ERROR=-5; + static final private int Z_VERSION_ERROR=-6; + + static final int fixed_bl = 9; + static final int fixed_bd = 5; + + static final int[] fixed_tl = { + 96,7,256, 0,8,80, 0,8,16, 84,8,115, + 82,7,31, 0,8,112, 0,8,48, 0,9,192, + 80,7,10, 0,8,96, 0,8,32, 0,9,160, + 0,8,0, 0,8,128, 0,8,64, 0,9,224, + 80,7,6, 0,8,88, 0,8,24, 0,9,144, + 83,7,59, 0,8,120, 0,8,56, 0,9,208, + 81,7,17, 0,8,104, 0,8,40, 0,9,176, + 0,8,8, 0,8,136, 0,8,72, 0,9,240, + 80,7,4, 0,8,84, 0,8,20, 85,8,227, + 83,7,43, 0,8,116, 0,8,52, 0,9,200, + 81,7,13, 0,8,100, 0,8,36, 0,9,168, + 0,8,4, 0,8,132, 0,8,68, 0,9,232, + 80,7,8, 0,8,92, 0,8,28, 0,9,152, + 84,7,83, 0,8,124, 0,8,60, 0,9,216, + 82,7,23, 0,8,108, 0,8,44, 0,9,184, + 0,8,12, 0,8,140, 0,8,76, 0,9,248, + 80,7,3, 0,8,82, 0,8,18, 85,8,163, + 83,7,35, 0,8,114, 0,8,50, 0,9,196, + 81,7,11, 0,8,98, 0,8,34, 0,9,164, + 0,8,2, 0,8,130, 0,8,66, 0,9,228, + 80,7,7, 0,8,90, 0,8,26, 0,9,148, + 84,7,67, 0,8,122, 0,8,58, 0,9,212, + 82,7,19, 0,8,106, 0,8,42, 0,9,180, + 0,8,10, 0,8,138, 0,8,74, 0,9,244, + 80,7,5, 0,8,86, 0,8,22, 192,8,0, + 83,7,51, 0,8,118, 0,8,54, 0,9,204, + 81,7,15, 0,8,102, 0,8,38, 0,9,172, + 0,8,6, 0,8,134, 0,8,70, 0,9,236, + 80,7,9, 0,8,94, 0,8,30, 0,9,156, + 84,7,99, 0,8,126, 0,8,62, 0,9,220, + 82,7,27, 0,8,110, 0,8,46, 0,9,188, + 0,8,14, 0,8,142, 0,8,78, 0,9,252, + 96,7,256, 0,8,81, 0,8,17, 85,8,131, + 82,7,31, 0,8,113, 0,8,49, 0,9,194, + 80,7,10, 0,8,97, 0,8,33, 0,9,162, + 0,8,1, 0,8,129, 0,8,65, 0,9,226, + 80,7,6, 0,8,89, 0,8,25, 0,9,146, + 83,7,59, 0,8,121, 0,8,57, 0,9,210, + 81,7,17, 0,8,105, 0,8,41, 0,9,178, + 0,8,9, 0,8,137, 0,8,73, 0,9,242, + 80,7,4, 0,8,85, 0,8,21, 80,8,258, + 83,7,43, 0,8,117, 0,8,53, 0,9,202, + 81,7,13, 0,8,101, 0,8,37, 0,9,170, + 0,8,5, 0,8,133, 0,8,69, 0,9,234, + 80,7,8, 0,8,93, 0,8,29, 0,9,154, + 84,7,83, 0,8,125, 0,8,61, 0,9,218, + 82,7,23, 0,8,109, 0,8,45, 0,9,186, + 0,8,13, 0,8,141, 0,8,77, 0,9,250, + 80,7,3, 0,8,83, 0,8,19, 85,8,195, + 83,7,35, 0,8,115, 0,8,51, 0,9,198, + 81,7,11, 0,8,99, 0,8,35, 0,9,166, + 0,8,3, 0,8,131, 0,8,67, 0,9,230, + 80,7,7, 0,8,91, 0,8,27, 0,9,150, + 84,7,67, 0,8,123, 0,8,59, 0,9,214, + 82,7,19, 0,8,107, 0,8,43, 0,9,182, + 0,8,11, 0,8,139, 0,8,75, 0,9,246, + 80,7,5, 0,8,87, 0,8,23, 192,8,0, + 83,7,51, 0,8,119, 0,8,55, 0,9,206, + 81,7,15, 0,8,103, 0,8,39, 0,9,174, + 0,8,7, 0,8,135, 0,8,71, 0,9,238, + 80,7,9, 0,8,95, 0,8,31, 0,9,158, + 84,7,99, 0,8,127, 0,8,63, 0,9,222, + 82,7,27, 0,8,111, 0,8,47, 0,9,190, + 0,8,15, 0,8,143, 0,8,79, 0,9,254, + 96,7,256, 0,8,80, 0,8,16, 84,8,115, + 82,7,31, 0,8,112, 0,8,48, 0,9,193, + + 80,7,10, 0,8,96, 0,8,32, 0,9,161, + 0,8,0, 0,8,128, 0,8,64, 0,9,225, + 80,7,6, 0,8,88, 0,8,24, 0,9,145, + 83,7,59, 0,8,120, 0,8,56, 0,9,209, + 81,7,17, 0,8,104, 0,8,40, 0,9,177, + 0,8,8, 0,8,136, 0,8,72, 0,9,241, + 80,7,4, 0,8,84, 0,8,20, 85,8,227, + 83,7,43, 0,8,116, 0,8,52, 0,9,201, + 81,7,13, 0,8,100, 0,8,36, 0,9,169, + 0,8,4, 0,8,132, 0,8,68, 0,9,233, + 80,7,8, 0,8,92, 0,8,28, 0,9,153, + 84,7,83, 0,8,124, 0,8,60, 0,9,217, + 82,7,23, 0,8,108, 0,8,44, 0,9,185, + 0,8,12, 0,8,140, 0,8,76, 0,9,249, + 80,7,3, 0,8,82, 0,8,18, 85,8,163, + 83,7,35, 0,8,114, 0,8,50, 0,9,197, + 81,7,11, 0,8,98, 0,8,34, 0,9,165, + 0,8,2, 0,8,130, 0,8,66, 0,9,229, + 80,7,7, 0,8,90, 0,8,26, 0,9,149, + 84,7,67, 0,8,122, 0,8,58, 0,9,213, + 82,7,19, 0,8,106, 0,8,42, 0,9,181, + 0,8,10, 0,8,138, 0,8,74, 0,9,245, + 80,7,5, 0,8,86, 0,8,22, 192,8,0, + 83,7,51, 0,8,118, 0,8,54, 0,9,205, + 81,7,15, 0,8,102, 0,8,38, 0,9,173, + 0,8,6, 0,8,134, 0,8,70, 0,9,237, + 80,7,9, 0,8,94, 0,8,30, 0,9,157, + 84,7,99, 0,8,126, 0,8,62, 0,9,221, + 82,7,27, 0,8,110, 0,8,46, 0,9,189, + 0,8,14, 0,8,142, 0,8,78, 0,9,253, + 96,7,256, 0,8,81, 0,8,17, 85,8,131, + 82,7,31, 0,8,113, 0,8,49, 0,9,195, + 80,7,10, 0,8,97, 0,8,33, 0,9,163, + 0,8,1, 0,8,129, 0,8,65, 0,9,227, + 80,7,6, 0,8,89, 0,8,25, 0,9,147, + 83,7,59, 0,8,121, 0,8,57, 0,9,211, + 81,7,17, 0,8,105, 0,8,41, 0,9,179, + 0,8,9, 0,8,137, 0,8,73, 0,9,243, + 80,7,4, 0,8,85, 0,8,21, 80,8,258, + 83,7,43, 0,8,117, 0,8,53, 0,9,203, + 81,7,13, 0,8,101, 0,8,37, 0,9,171, + 0,8,5, 0,8,133, 0,8,69, 0,9,235, + 80,7,8, 0,8,93, 0,8,29, 0,9,155, + 84,7,83, 0,8,125, 0,8,61, 0,9,219, + 82,7,23, 0,8,109, 0,8,45, 0,9,187, + 0,8,13, 0,8,141, 0,8,77, 0,9,251, + 80,7,3, 0,8,83, 0,8,19, 85,8,195, + 83,7,35, 0,8,115, 0,8,51, 0,9,199, + 81,7,11, 0,8,99, 0,8,35, 0,9,167, + 0,8,3, 0,8,131, 0,8,67, 0,9,231, + 80,7,7, 0,8,91, 0,8,27, 0,9,151, + 84,7,67, 0,8,123, 0,8,59, 0,9,215, + 82,7,19, 0,8,107, 0,8,43, 0,9,183, + 0,8,11, 0,8,139, 0,8,75, 0,9,247, + 80,7,5, 0,8,87, 0,8,23, 192,8,0, + 83,7,51, 0,8,119, 0,8,55, 0,9,207, + 81,7,15, 0,8,103, 0,8,39, 0,9,175, + 0,8,7, 0,8,135, 0,8,71, 0,9,239, + 80,7,9, 0,8,95, 0,8,31, 0,9,159, + 84,7,99, 0,8,127, 0,8,63, 0,9,223, + 82,7,27, 0,8,111, 0,8,47, 0,9,191, + 0,8,15, 0,8,143, 0,8,79, 0,9,255 + }; + static final int[] fixed_td = { + 80,5,1, 87,5,257, 83,5,17, 91,5,4097, + 81,5,5, 89,5,1025, 85,5,65, 93,5,16385, + 80,5,3, 88,5,513, 84,5,33, 92,5,8193, + 82,5,9, 90,5,2049, 86,5,129, 192,5,24577, + 80,5,2, 87,5,385, 83,5,25, 91,5,6145, + 81,5,7, 89,5,1537, 85,5,97, 93,5,24577, + 80,5,4, 88,5,769, 84,5,49, 92,5,12289, + 82,5,13, 90,5,3073, 86,5,193, 192,5,24577 + }; + + // Tables for deflate from PKZIP's appnote.txt. + static final int[] cplens = { // Copy lengths for literal codes 257..285 + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 + }; + + // see note #13 above about 258 + static final int[] cplext = { // Extra bits for literal codes 257..285 + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112 // 112==invalid + }; + + static final int[] cpdist = { // Copy offsets for distance codes 0..29 + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577 + }; + + static final int[] cpdext = { // Extra bits for distance codes + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + // If BMAX needs to be larger than 16, then h and x[] should be uLong. + static final int BMAX=15; // maximum bit length of any code + + int[] hn = null; // hufts used in space + int[] v = null; // work area for huft_build + int[] c = null; // bit length count table + int[] r = null; // table entry for structure assignment + int[] u = null; // table stack + int[] x = null; // bit offsets, then code stack + + private int huft_build(int[] b, // code lengths in bits (all assumed <= BMAX) + int bindex, + int n, // number of codes (assumed <= 288) + int s, // number of simple-valued codes (0..s-1) + int[] d, // list of base values for non-simple codes + int[] e, // list of extra bits for non-simple codes + int[] t, // result: starting table + int[] m, // maximum lookup bits, returns actual + int[] hp,// space for trees + int[] hn,// hufts used in space + int[] v // working area: values in order of bit length + ){ + // Given a list of code lengths and a maximum table size, make a set of + // tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + // if the given code set is incomplete (the tables are still built in this + // case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of + // lengths), or Z_MEM_ERROR if not enough memory. + + int a; // counter for codes of length k + int f; // i repeats in table every f entries + int g; // maximum code length + int h; // table level + int i; // counter, current code + int j; // counter + int k; // number of bits in current code + int l; // bits per table (returned in m) + int mask; // (1 << w) - 1, to avoid cc -O bug on HP + int p; // pointer into c[], b[], or v[] + int q; // points to current table + int w; // bits before this table == (l * h) + int xp; // pointer into x + int y; // number of dummy codes added + int z; // number of entries in current table + + // Generate counts for each bit length + + p = 0; i = n; + do { + c[b[bindex+p]]++; p++; i--; // assume all entries <= BMAX + }while(i!=0); + + if(c[0] == n){ // null input--all zero length codes + t[0] = -1; + m[0] = 0; + return Z_OK; + } + + // Find minimum and maximum length, bound *m by those + l = m[0]; + for (j = 1; j <= BMAX; j++) + if(c[j]!=0) break; + k = j; // minimum code length + if(l < j){ + l = j; + } + for (i = BMAX; i!=0; i--){ + if(c[i]!=0) break; + } + g = i; // maximum code length + if(l > i){ + l = i; + } + m[0] = l; + + // Adjust last length count to fill out codes, if needed + for (y = 1 << j; j < i; j++, y <<= 1){ + if ((y -= c[j]) < 0){ + return Z_DATA_ERROR; + } + } + if ((y -= c[i]) < 0){ + return Z_DATA_ERROR; + } + c[i] += y; + + // Generate starting offsets into the value table for each length + x[1] = j = 0; + p = 1; xp = 2; + while (--i!=0) { // note that i == g from above + x[xp] = (j += c[p]); + xp++; + p++; + } + + // Make a table of values in order of bit lengths + i = 0; p = 0; + do { + if ((j = b[bindex+p]) != 0){ + v[x[j]++] = i; + } + p++; + } + while (++i < n); + n = x[g]; // set n to length of v + + // Generate the Huffman codes and for each, make the table entries + x[0] = i = 0; // first Huffman code is zero + p = 0; // grab values in bit order + h = -1; // no tables yet--level -1 + w = -l; // bits decoded == (l * h) + u[0] = 0; // just to keep compilers happy + q = 0; // ditto + z = 0; // ditto + + // go through the bit lengths (k already is bits in shortest code) + for (; k <= g; k++){ + a = c[k]; + while (a--!=0){ + // here i is the Huffman code of length k bits for value *p + // make tables up to required level + while (k > w + l){ + h++; + w += l; // previous table always l bits + // compute minimum size table less than or equal to l bits + z = g - w; + z = (z > l) ? l : z; // table size upper limit + if((f=1<<(j=k-w))>a+1){ // try a k-w bit table + // too few codes for k-w bit table + f -= a + 1; // deduct codes from patterns left + xp = k; + if(j < z){ + while (++j < z){ // try smaller tables up to z bits + if((f <<= 1) <= c[++xp]) + break; // enough codes to use up j bits + f -= c[xp]; // else deduct codes from patterns + } + } + } + z = 1 << j; // table entries for j-bit table + + // allocate new table + if (hn[0] + z > MANY){ // (note: doesn't matter for fixed) + return Z_DATA_ERROR; // overflow of MANY + } + u[h] = q = /*hp+*/ hn[0]; // DEBUG + hn[0] += z; + + // connect to last table, if there is one + if(h!=0){ + x[h]=i; // save pattern for backing up + r[0]=(byte)j; // bits in this table + r[1]=(byte)l; // bits to dump before this table + j=i>>>(w - l); + r[2] = (int)(q - u[h-1] - j); // offset to this table + System.arraycopy(r, 0, hp, (u[h-1]+j)*3, 3); // connect to last table + } + else{ + t[0] = q; // first table is returned result + } + } + + // set up table entry in r + r[1] = (byte)(k - w); + if (p >= n){ + r[0] = 128 + 64; // out of values--invalid code + } + else if (v[p] < s){ + r[0] = (byte)(v[p] < 256 ? 0 : 32 + 64); // 256 is end-of-block + r[2] = v[p++]; // simple code is just the value + } + else{ + r[0]=(byte)(e[v[p]-s]+16+64); // non-simple--look up in lists + r[2]=d[v[p++] - s]; + } + + // fill code-like entries with r + f=1<<(k-w); + for (j=i>>>w;j>>= 1){ + i ^= j; + } + i ^= j; + + // backup over finished tables + mask = (1 << w) - 1; // needed on HP, cc -O bug + while ((i & mask) != x[h]){ + h--; // don't need to update q + w -= l; + mask = (1 << w) - 1; + } + } + } + // Return Z_BUF_ERROR if we were given an incomplete table + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; + } + + int inflate_trees_bits(int[] c, // 19 code lengths + int[] bb, // bits tree desired/actual depth + int[] tb, // bits tree result + int[] hp, // space for trees + ZStream z // for messages + ){ + int result; + initWorkArea(19); + hn[0]=0; + result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v); + + if(result == Z_DATA_ERROR){ + z.msg = "oversubscribed dynamic bit lengths tree"; + } + else if(result == Z_BUF_ERROR || bb[0] == 0){ + z.msg = "incomplete dynamic bit lengths tree"; + result = Z_DATA_ERROR; + } + return result; + } + + int inflate_trees_dynamic(int nl, // number of literal/length codes + int nd, // number of distance codes + int[] c, // that many (total) code lengths + int[] bl, // literal desired/actual bit depth + int[] bd, // distance desired/actual bit depth + int[] tl, // literal/length tree result + int[] td, // distance tree result + int[] hp, // space for trees + ZStream z // for messages + ){ + int result; + + // build literal/length tree + initWorkArea(288); + hn[0]=0; + result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v); + if (result != Z_OK || bl[0] == 0){ + if(result == Z_DATA_ERROR){ + z.msg = "oversubscribed literal/length tree"; + } + else if (result != Z_MEM_ERROR){ + z.msg = "incomplete literal/length tree"; + result = Z_DATA_ERROR; + } + return result; + } + + // build distance tree + initWorkArea(288); + result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v); + + if (result != Z_OK || (bd[0] == 0 && nl > 257)){ + if (result == Z_DATA_ERROR){ + z.msg = "oversubscribed distance tree"; + } + else if (result == Z_BUF_ERROR) { + z.msg = "incomplete distance tree"; + result = Z_DATA_ERROR; + } + else if (result != Z_MEM_ERROR){ + z.msg = "empty distance tree with lengths"; + result = Z_DATA_ERROR; + } + return result; + } + + return Z_OK; + } + + static int inflate_trees_fixed(int[] bl, //literal desired/actual bit depth + int[] bd, //distance desired/actual bit depth + int[][] tl,//literal/length tree result + int[][] td,//distance tree result + ZStream z //for memory allocation + ){ + bl[0]=fixed_bl; + bd[0]=fixed_bd; + tl[0]=fixed_tl; + td[0]=fixed_td; + return Z_OK; + } + + private void initWorkArea(int vsize){ + if(hn==null){ + hn=new int[1]; + v=new int[vsize]; + c=new int[BMAX+1]; + r=new int[3]; + u=new int[BMAX]; + x=new int[BMAX+1]; + } + if(v.length> 4) + 1; + if(w < 48) + w &= 15; + } + + if(w<8 ||w>15){ + inflateEnd(); + return Z_STREAM_ERROR; + } + if(blocks != null && wbits != w){ + blocks.free(); + blocks=null; + } + + // set window size + wbits=w; + + this.blocks=new InfBlocks(z, 1<>8))&0xff; + + if(((wrap&1)==0 || // check if zlib header allowed + (((this.method << 8)+b) % 31)!=0) && + (this.method&0xf)!=Z_DEFLATED){ + if(wrap == 4){ + z.next_in_index -= 2; + z.avail_in += 2; + z.total_in -= 2; + wrap = 0; + this.mode = BLOCKS; + break; + } + this.mode = BAD; + z.msg = "incorrect header check"; + // since zlib 1.2, it is allowted to inflateSync for this case. + /* + this.marker = 5; // can't try inflateSync + */ + break; + } + + if((this.method&0xf)!=Z_DEFLATED){ + this.mode = BAD; + z.msg="unknown compression method"; + // since zlib 1.2, it is allowted to inflateSync for this case. + /* + this.marker = 5; // can't try inflateSync + */ + break; + } + + if(wrap == 4){ + wrap = 1; + } + + if((this.method>>4)+8>this.wbits){ + this.mode = BAD; + z.msg="invalid window size"; + // since zlib 1.2, it is allowted to inflateSync for this case. + /* + this.marker = 5; // can't try inflateSync + */ + break; + } + + z.adler=new Adler32(); + + if((b&PRESET_DICT)==0){ + this.mode = BLOCKS; + break; + } + this.mode = DICT4; + case DICT4: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + this.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L; + this.mode=DICT3; + case DICT3: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + this.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L; + this.mode=DICT2; + case DICT2: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + this.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L; + this.mode=DICT1; + case DICT1: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + this.need += (z.next_in[z.next_in_index++]&0xffL); + z.adler.reset(this.need); + this.mode = DICT0; + return Z_NEED_DICT; + case DICT0: + this.mode = BAD; + z.msg = "need dictionary"; + this.marker = 0; // can try inflateSync + return Z_STREAM_ERROR; + case BLOCKS: + r = this.blocks.proc(r); + if(r == Z_DATA_ERROR){ + this.mode = BAD; + this.marker = 0; // can try inflateSync + break; + } + if(r == Z_OK){ + r = f; + } + if(r != Z_STREAM_END){ + return r; + } + r = f; + this.was=z.adler.getValue(); + this.blocks.reset(); + if(this.wrap==0){ + this.mode=DONE; + break; + } + this.mode=CHECK4; + case CHECK4: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + this.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L; + this.mode=CHECK3; + case CHECK3: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + this.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L; + this.mode = CHECK2; + case CHECK2: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + this.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L; + this.mode = CHECK1; + case CHECK1: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + this.need+=(z.next_in[z.next_in_index++]&0xffL); + + if(flags!=0){ // gzip + this.need = ((this.need&0xff000000)>>24 | + (this.need&0x00ff0000)>>8 | + (this.need&0x0000ff00)<<8 | + (this.need&0x0000ffff)<<24)&0xffffffffL; + } + + if(((int)(this.was)) != ((int)(this.need))){ + z.msg = "incorrect data check"; + // chack is delayed + /* + this.mode = BAD; + this.marker = 5; // can't try inflateSync + break; + */ + } + else if(flags!=0 && gheader!=null){ + gheader.crc = this.need; + } + + this.mode = LENGTH; + case LENGTH: + if (wrap!=0 && flags!=0) { + + try { r=readBytes(4, r, f); } + catch(Return e){ return e.r; } + + if(z.msg!=null && z.msg.equals("incorrect data check")){ + this.mode = BAD; + this.marker = 5; // can't try inflateSync + break; + } + + if (this.need != (z.total_out & 0xffffffffL)) { + z.msg = "incorrect length check"; + this.mode = BAD; + break; + } + z.msg = null; + } + else { + if(z.msg!=null && z.msg.equals("incorrect data check")){ + this.mode = BAD; + this.marker = 5; // can't try inflateSync + break; + } + } + + this.mode = DONE; + case DONE: + return Z_STREAM_END; + case BAD: + return Z_DATA_ERROR; + + case FLAGS: + + try { r=readBytes(2, r, f); } + catch(Return e){ return e.r; } + + flags = ((int)this.need)&0xffff; + + if ((flags & 0xff) != Z_DEFLATED) { + z.msg = "unknown compression method"; + this.mode = BAD; + break; + } + if ((flags & 0xe000)!=0) { + z.msg = "unknown header flags set"; + this.mode = BAD; + break; + } + + if ((flags & 0x0200)!=0){ + checksum(2, this.need); + } + + this.mode = TIME; + + case TIME: + try { r=readBytes(4, r, f); } + catch(Return e){ return e.r; } + if(gheader!=null) + gheader.time = this.need; + if ((flags & 0x0200)!=0){ + checksum(4, this.need); + } + this.mode = OS; + case OS: + try { r=readBytes(2, r, f); } + catch(Return e){ return e.r; } + if(gheader!=null){ + gheader.xflags = ((int)this.need)&0xff; + gheader.os = (((int)this.need)>>8)&0xff; + } + if ((flags & 0x0200)!=0){ + checksum(2, this.need); + } + this.mode = EXLEN; + case EXLEN: + if ((flags & 0x0400)!=0) { + try { r=readBytes(2, r, f); } + catch(Return e){ return e.r; } + if(gheader!=null){ + gheader.extra = new byte[((int)this.need)&0xffff]; + } + if ((flags & 0x0200)!=0){ + checksum(2, this.need); + } + } + else if(gheader!=null){ + gheader.extra=null; + } + this.mode = EXTRA; + + case EXTRA: + if ((flags & 0x0400)!=0) { + try { + r=readBytes(r, f); + if(gheader!=null){ + byte[] foo = tmp_string.toByteArray(); + tmp_string=null; + if(foo.length == gheader.extra.length){ + System.arraycopy(foo, 0, gheader.extra, 0, foo.length); + } + else{ + z.msg = "bad extra field length"; + this.mode = BAD; + break; + } + } + } + catch(Return e){ return e.r; } + } + else if(gheader!=null){ + gheader.extra=null; + } + this.mode = NAME; + case NAME: + if ((flags & 0x0800)!=0) { + try { + r=readString(r, f); + if(gheader!=null){ + gheader.name=tmp_string.toByteArray(); + } + tmp_string=null; + } + catch(Return e){ return e.r; } + } + else if(gheader!=null){ + gheader.name=null; + } + this.mode = COMMENT; + case COMMENT: + if ((flags & 0x1000)!=0) { + try { + r=readString(r, f); + if(gheader!=null){ + gheader.comment=tmp_string.toByteArray(); + } + tmp_string=null; + } + catch(Return e){ return e.r; } + } + else if(gheader!=null){ + gheader.comment=null; + } + this.mode = HCRC; + case HCRC: + if ((flags & 0x0200)!=0) { + try { r=readBytes(2, r, f); } + catch(Return e){ return e.r; } + if(gheader!=null){ + gheader.hcrc=(int)(this.need&0xffff); + } + if(this.need != (z.adler.getValue()&0xffffL)){ + this.mode = BAD; + z.msg = "header crc mismatch"; + this.marker = 5; // can't try inflateSync + break; + } + } + z.adler = new CRC32(); + + this.mode = BLOCKS; + break; + default: + return Z_STREAM_ERROR; + } + } + } + + int inflateSetDictionary(byte[] dictionary, int dictLength){ + if(z==null || (this.mode != DICT0 && this.wrap != 0)){ + return Z_STREAM_ERROR; + } + + int index=0; + int length = dictLength; + + if(this.mode==DICT0){ + long adler_need=z.adler.getValue(); + z.adler.reset(); + z.adler.update(dictionary, 0, dictLength); + if(z.adler.getValue()!=adler_need){ + return Z_DATA_ERROR; + } + } + + z.adler.reset(); + + if(length >= (1<0){ + if(z.avail_in==0){ throw new Return(r); }; r=f; + z.avail_in--; z.total_in++; + this.need = this.need | + ((z.next_in[z.next_in_index++]&0xff)<<((n-need_bytes)*8)); + need_bytes--; + } + if(n==2){ + this.need&=0xffffL; + } + else if(n==4) { + this.need&=0xffffffffL; + } + need_bytes=-1; + return r; + } + class Return extends Exception{ + int r; + Return(int r){this.r=r; } + } + + private java.io.ByteArrayOutputStream tmp_string = null; + private int readString(int r, int f) throws Return{ + if(tmp_string == null){ + tmp_string=new java.io.ByteArrayOutputStream(); + } + int b=0; + do { + if(z.avail_in==0){ throw new Return(r); }; r=f; + z.avail_in--; z.total_in++; + b = z.next_in[z.next_in_index]; + if(b!=0) tmp_string.write(z.next_in, z.next_in_index, 1); + z.adler.update(z.next_in, z.next_in_index, 1); + z.next_in_index++; + }while(b!=0); + return r; + } + + private int readBytes(int r, int f) throws Return{ + if(tmp_string == null){ + tmp_string=new java.io.ByteArrayOutputStream(); + } + int b=0; + while(this.need>0){ + if(z.avail_in==0){ throw new Return(r); }; r=f; + z.avail_in--; z.total_in++; + b = z.next_in[z.next_in_index]; + tmp_string.write(z.next_in, z.next_in_index, 1); + z.adler.update(z.next_in, z.next_in_index, 1); + z.next_in_index++; + this.need--; + } + return r; + } + + private void checksum(int n, long v){ + for(int i=0; i>=8; + } + z.adler.update(crcbuf, 0, n); + } + + public GZIPHeader getGZIPHeader(){ + return gheader; + } + + boolean inParsingHeader(){ + switch(mode){ + case HEAD: + case DICT4: + case DICT3: + case DICT2: + case DICT1: + case FLAGS: + case TIME: + case OS: + case EXLEN: + case EXTRA: + case NAME: + case COMMENT: + case HCRC: + return true; + default: + return false; + } + } +} diff --git a/src/lwjgl/java/com/jcraft/jzlib/Inflater.java b/src/lwjgl/java/com/jcraft/jzlib/Inflater.java new file mode 100644 index 0000000..0fb0b09 --- /dev/null +++ b/src/lwjgl/java/com/jcraft/jzlib/Inflater.java @@ -0,0 +1,168 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package com.jcraft.jzlib; + +final public class Inflater extends ZStream{ + + static final private int MAX_WBITS=15; // 32K LZ77 window + static final private int DEF_WBITS=MAX_WBITS; + + static final private int Z_NO_FLUSH=0; + static final private int Z_PARTIAL_FLUSH=1; + static final private int Z_SYNC_FLUSH=2; + static final private int Z_FULL_FLUSH=3; + static final private int Z_FINISH=4; + + static final private int MAX_MEM_LEVEL=9; + + static final private int Z_OK=0; + static final private int Z_STREAM_END=1; + static final private int Z_NEED_DICT=2; + static final private int Z_ERRNO=-1; + static final private int Z_STREAM_ERROR=-2; + static final private int Z_DATA_ERROR=-3; + static final private int Z_MEM_ERROR=-4; + static final private int Z_BUF_ERROR=-5; + static final private int Z_VERSION_ERROR=-6; + + public Inflater() { + super(); + init(); + } + + public Inflater(JZlib.WrapperType wrapperType) throws GZIPException { + this(DEF_WBITS, wrapperType); + } + + public Inflater(int w, JZlib.WrapperType wrapperType) throws GZIPException { + super(); + int ret = init(w, wrapperType); + if(ret!=Z_OK) + throw new GZIPException(ret+": "+msg); + } + + public Inflater(int w) throws GZIPException { + this(w, false); + } + + public Inflater(boolean nowrap) throws GZIPException { + this(DEF_WBITS, nowrap); + } + + public Inflater(int w, boolean nowrap) throws GZIPException { + super(); + int ret = init(w, nowrap); + if(ret!=Z_OK) + throw new GZIPException(ret+": "+msg); + } + + private boolean finished = false; + + public int init(){ + return init(DEF_WBITS); + } + + public int init(JZlib.WrapperType wrapperType){ + return init(DEF_WBITS, wrapperType); + } + + public int init(int w, JZlib.WrapperType wrapperType) { + boolean nowrap = false; + if(wrapperType == JZlib.W_NONE){ + nowrap = true; + } + else if(wrapperType == JZlib.W_GZIP) { + w += 16; + } + else if(wrapperType == JZlib.W_ANY) { + w |= Inflate.INFLATE_ANY; + } + else if(wrapperType == JZlib.W_ZLIB) { + } + return init(w, nowrap); + } + + public int init(boolean nowrap){ + return init(DEF_WBITS, nowrap); + } + + public int init(int w){ + return init(w, false); + } + + public int init(int w, boolean nowrap){ + finished = false; + istate=new Inflate(this); + return istate.inflateInit(nowrap?-w:w); + } + + public int inflate(int f){ + if(istate==null) return Z_STREAM_ERROR; + int ret = istate.inflate(f); + if(ret == Z_STREAM_END) + finished = true; + return ret; + } + + public int end(){ + finished = true; + if(istate==null) return Z_STREAM_ERROR; + int ret=istate.inflateEnd(); +// istate = null; + return ret; + } + + public int sync(){ + if(istate == null) + return Z_STREAM_ERROR; + return istate.inflateSync(); + } + + public int syncPoint(){ + if(istate == null) + return Z_STREAM_ERROR; + return istate.inflateSyncPoint(); + } + + public int setDictionary(byte[] dictionary, int dictLength){ + if(istate == null) + return Z_STREAM_ERROR; + return istate.inflateSetDictionary(dictionary, dictLength); + } + + public boolean finished(){ + return istate.mode==12 /*DONE*/; + } +} diff --git a/src/lwjgl/java/com/jcraft/jzlib/InflaterInputStream.java b/src/lwjgl/java/com/jcraft/jzlib/InflaterInputStream.java new file mode 100644 index 0000000..0420582 --- /dev/null +++ b/src/lwjgl/java/com/jcraft/jzlib/InflaterInputStream.java @@ -0,0 +1,247 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jcraft.jzlib; +import java.io.*; + +public class InflaterInputStream extends FilterInputStream { + protected final Inflater inflater; + protected byte[] buf; + + private boolean closed = false; + + private boolean eof = false; + + private boolean close_in = true; + + protected static final int DEFAULT_BUFSIZE = 512; + + public InflaterInputStream(InputStream in) throws IOException { + this(in, false); + } + + public InflaterInputStream(InputStream in, boolean nowrap) throws IOException { + this(in, new Inflater(nowrap)); + myinflater = true; + } + + public InflaterInputStream(InputStream in, Inflater inflater) throws IOException { + this(in, inflater, DEFAULT_BUFSIZE); + } + + public InflaterInputStream(InputStream in, + Inflater inflater, int size) throws IOException { + this(in, inflater, size, true); + } + + public InflaterInputStream(InputStream in, + Inflater inflater, + int size, boolean close_in) throws IOException { + super(in); + if (in == null || inflater == null) { + throw new NullPointerException(); + } + else if (size <= 0) { + throw new IllegalArgumentException("buffer size must be greater than 0"); + } + this.inflater = inflater; + buf = new byte[size]; + this.close_in = close_in; + } + + protected boolean myinflater = false; + + private byte[] byte1 = new byte[1]; + + public int read() throws IOException { + if (closed) { throw new IOException("Stream closed"); } + return read(byte1, 0, 1) == -1 ? -1 : byte1[0] & 0xff; + } + + public int read(byte[] b, int off, int len) throws IOException { + if (closed) { throw new IOException("Stream closed"); } + if (b == null) { + throw new NullPointerException(); + } + else if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } + else if (len == 0) { + return 0; + } + else if (eof) { + return -1; + } + + int n = 0; + inflater.setOutput(b, off, len); + while(!eof) { + if(inflater.avail_in==0) + fill(); + int err = inflater.inflate(JZlib.Z_NO_FLUSH); + n += inflater.next_out_index - off; + off = inflater.next_out_index; + switch(err) { + case JZlib.Z_DATA_ERROR: + throw new IOException(inflater.msg); + case JZlib.Z_STREAM_END: + case JZlib.Z_NEED_DICT: + eof = true; + if(err == JZlib.Z_NEED_DICT) + return -1; + break; + default: + } + if(inflater.avail_out==0) + break; + } + return n; + } + + public int available() throws IOException { + if (closed) { throw new IOException("Stream closed"); } + if (eof) { + return 0; + } + else { + return 1; + } + } + + private byte[] b = new byte[512]; + + public long skip(long n) throws IOException { + if (n < 0) { + throw new IllegalArgumentException("negative skip length"); + } + + if (closed) { throw new IOException("Stream closed"); } + + int max = (int)Math.min(n, Integer.MAX_VALUE); + int total = 0; + while (total < max) { + int len = max - total; + if (len > b.length) { + len = b.length; + } + len = read(b, 0, len); + if (len == -1) { + eof = true; + break; + } + total += len; + } + return total; + } + + public void close() throws IOException { + if (!closed) { + if (myinflater) + inflater.end(); + if(close_in) + in.close(); + closed = true; + } + } + + protected void fill() throws IOException { + if (closed) { throw new IOException("Stream closed"); } + int len = in.read(buf, 0, buf.length); + if (len == -1) { + if(inflater.istate.wrap == 0 && + !inflater.finished()){ + buf[0]=0; + len=1; + } + else if(inflater.istate.was != -1){ // in reading trailer + throw new IOException("footer is not found"); + } + else{ + throw new EOFException("Unexpected end of ZLIB input stream"); + } + } + inflater.setInput(buf, 0, len, true); + } + + public boolean markSupported() { + return false; + } + + public synchronized void mark(int readlimit) { + } + + public synchronized void reset() throws IOException { + throw new IOException("mark/reset not supported"); + } + + public long getTotalIn() { + return inflater.getTotalIn(); + } + + public long getTotalOut() { + return inflater.getTotalOut(); + } + + public byte[] getAvailIn() { + if(inflater.avail_in<=0) + return null; + byte[] tmp = new byte[inflater.avail_in]; + System.arraycopy(inflater.next_in, inflater.next_in_index, + tmp, 0, inflater.avail_in); + return tmp; + } + + public void readHeader() throws IOException { + + byte[] empty = "".getBytes(); + inflater.setInput(empty, 0, 0, false); + inflater.setOutput(empty, 0, 0); + + int err = inflater.inflate(JZlib.Z_NO_FLUSH); + if(!inflater.istate.inParsingHeader()){ + return; + } + + byte[] b1 = new byte[1]; + do{ + int i = in.read(b1); + if(i<=0) + throw new IOException("no input"); + inflater.setInput(b1); + err = inflater.inflate(JZlib.Z_NO_FLUSH); + if(err!=0/*Z_OK*/) + throw new IOException(inflater.msg); + } + while(inflater.istate.inParsingHeader()); + } + + public Inflater getInflater(){ + return inflater; + } +} \ No newline at end of file diff --git a/src/lwjgl/java/com/jcraft/jzlib/JZlib.java b/src/lwjgl/java/com/jcraft/jzlib/JZlib.java new file mode 100644 index 0000000..a4bb341 --- /dev/null +++ b/src/lwjgl/java/com/jcraft/jzlib/JZlib.java @@ -0,0 +1,92 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package com.jcraft.jzlib; + +final public class JZlib{ + private static final String version="1.1.0"; + public static String version(){return version;} + + static final public int MAX_WBITS=15; // 32K LZ77 window + static final public int DEF_WBITS=MAX_WBITS; + + public enum WrapperType { + NONE, ZLIB, GZIP, ANY + } + + public static final WrapperType W_NONE = WrapperType.NONE; + public static final WrapperType W_ZLIB = WrapperType.ZLIB; + public static final WrapperType W_GZIP = WrapperType.GZIP; + public static final WrapperType W_ANY = WrapperType.ANY; + + // compression levels + static final public int Z_NO_COMPRESSION=0; + static final public int Z_BEST_SPEED=1; + static final public int Z_BEST_COMPRESSION=9; + static final public int Z_DEFAULT_COMPRESSION=(-1); + + // compression strategy + static final public int Z_FILTERED=1; + static final public int Z_HUFFMAN_ONLY=2; + static final public int Z_DEFAULT_STRATEGY=0; + + static final public int Z_NO_FLUSH=0; + static final public int Z_PARTIAL_FLUSH=1; + static final public int Z_SYNC_FLUSH=2; + static final public int Z_FULL_FLUSH=3; + static final public int Z_FINISH=4; + + static final public int Z_OK=0; + static final public int Z_STREAM_END=1; + static final public int Z_NEED_DICT=2; + static final public int Z_ERRNO=-1; + static final public int Z_STREAM_ERROR=-2; + static final public int Z_DATA_ERROR=-3; + static final public int Z_MEM_ERROR=-4; + static final public int Z_BUF_ERROR=-5; + static final public int Z_VERSION_ERROR=-6; + + // The three kinds of block type + static final public byte Z_BINARY = 0; + static final public byte Z_ASCII = 1; + static final public byte Z_UNKNOWN = 2; + + public static long adler32_combine(long adler1, long adler2, long len2){ + return Adler32.combine(adler1, adler2, len2); + } + + public static long crc32_combine(long crc1, long crc2, long len2){ + return CRC32.combine(crc1, crc2, len2); + } +} diff --git a/src/lwjgl/java/com/jcraft/jzlib/StaticTree.java b/src/lwjgl/java/com/jcraft/jzlib/StaticTree.java new file mode 100644 index 0000000..e35931c --- /dev/null +++ b/src/lwjgl/java/com/jcraft/jzlib/StaticTree.java @@ -0,0 +1,148 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package com.jcraft.jzlib; + +final class StaticTree{ + static final private int MAX_BITS=15; + + static final private int BL_CODES=19; + static final private int D_CODES=30; + static final private int LITERALS=256; + static final private int LENGTH_CODES=29; + static final private int L_CODES=(LITERALS+1+LENGTH_CODES); + + // Bit length codes must not exceed MAX_BL_BITS bits + static final int MAX_BL_BITS=7; + + static final short[] static_ltree = { + 12, 8, 140, 8, 76, 8, 204, 8, 44, 8, + 172, 8, 108, 8, 236, 8, 28, 8, 156, 8, + 92, 8, 220, 8, 60, 8, 188, 8, 124, 8, + 252, 8, 2, 8, 130, 8, 66, 8, 194, 8, + 34, 8, 162, 8, 98, 8, 226, 8, 18, 8, + 146, 8, 82, 8, 210, 8, 50, 8, 178, 8, + 114, 8, 242, 8, 10, 8, 138, 8, 74, 8, + 202, 8, 42, 8, 170, 8, 106, 8, 234, 8, + 26, 8, 154, 8, 90, 8, 218, 8, 58, 8, + 186, 8, 122, 8, 250, 8, 6, 8, 134, 8, + 70, 8, 198, 8, 38, 8, 166, 8, 102, 8, + 230, 8, 22, 8, 150, 8, 86, 8, 214, 8, + 54, 8, 182, 8, 118, 8, 246, 8, 14, 8, + 142, 8, 78, 8, 206, 8, 46, 8, 174, 8, + 110, 8, 238, 8, 30, 8, 158, 8, 94, 8, + 222, 8, 62, 8, 190, 8, 126, 8, 254, 8, + 1, 8, 129, 8, 65, 8, 193, 8, 33, 8, + 161, 8, 97, 8, 225, 8, 17, 8, 145, 8, + 81, 8, 209, 8, 49, 8, 177, 8, 113, 8, + 241, 8, 9, 8, 137, 8, 73, 8, 201, 8, + 41, 8, 169, 8, 105, 8, 233, 8, 25, 8, + 153, 8, 89, 8, 217, 8, 57, 8, 185, 8, + 121, 8, 249, 8, 5, 8, 133, 8, 69, 8, + 197, 8, 37, 8, 165, 8, 101, 8, 229, 8, + 21, 8, 149, 8, 85, 8, 213, 8, 53, 8, + 181, 8, 117, 8, 245, 8, 13, 8, 141, 8, + 77, 8, 205, 8, 45, 8, 173, 8, 109, 8, + 237, 8, 29, 8, 157, 8, 93, 8, 221, 8, + 61, 8, 189, 8, 125, 8, 253, 8, 19, 9, + 275, 9, 147, 9, 403, 9, 83, 9, 339, 9, + 211, 9, 467, 9, 51, 9, 307, 9, 179, 9, + 435, 9, 115, 9, 371, 9, 243, 9, 499, 9, + 11, 9, 267, 9, 139, 9, 395, 9, 75, 9, + 331, 9, 203, 9, 459, 9, 43, 9, 299, 9, + 171, 9, 427, 9, 107, 9, 363, 9, 235, 9, + 491, 9, 27, 9, 283, 9, 155, 9, 411, 9, + 91, 9, 347, 9, 219, 9, 475, 9, 59, 9, + 315, 9, 187, 9, 443, 9, 123, 9, 379, 9, + 251, 9, 507, 9, 7, 9, 263, 9, 135, 9, + 391, 9, 71, 9, 327, 9, 199, 9, 455, 9, + 39, 9, 295, 9, 167, 9, 423, 9, 103, 9, + 359, 9, 231, 9, 487, 9, 23, 9, 279, 9, + 151, 9, 407, 9, 87, 9, 343, 9, 215, 9, + 471, 9, 55, 9, 311, 9, 183, 9, 439, 9, + 119, 9, 375, 9, 247, 9, 503, 9, 15, 9, + 271, 9, 143, 9, 399, 9, 79, 9, 335, 9, + 207, 9, 463, 9, 47, 9, 303, 9, 175, 9, + 431, 9, 111, 9, 367, 9, 239, 9, 495, 9, + 31, 9, 287, 9, 159, 9, 415, 9, 95, 9, + 351, 9, 223, 9, 479, 9, 63, 9, 319, 9, + 191, 9, 447, 9, 127, 9, 383, 9, 255, 9, + 511, 9, 0, 7, 64, 7, 32, 7, 96, 7, + 16, 7, 80, 7, 48, 7, 112, 7, 8, 7, + 72, 7, 40, 7, 104, 7, 24, 7, 88, 7, + 56, 7, 120, 7, 4, 7, 68, 7, 36, 7, + 100, 7, 20, 7, 84, 7, 52, 7, 116, 7, + 3, 8, 131, 8, 67, 8, 195, 8, 35, 8, + 163, 8, 99, 8, 227, 8 + }; + + static final short[] static_dtree = { + 0, 5, 16, 5, 8, 5, 24, 5, 4, 5, + 20, 5, 12, 5, 28, 5, 2, 5, 18, 5, + 10, 5, 26, 5, 6, 5, 22, 5, 14, 5, + 30, 5, 1, 5, 17, 5, 9, 5, 25, 5, + 5, 5, 21, 5, 13, 5, 29, 5, 3, 5, + 19, 5, 11, 5, 27, 5, 7, 5, 23, 5 + }; + + static StaticTree static_l_desc = + new StaticTree(static_ltree, Tree.extra_lbits, + LITERALS+1, L_CODES, MAX_BITS); + + static StaticTree static_d_desc = + new StaticTree(static_dtree, Tree.extra_dbits, + 0, D_CODES, MAX_BITS); + + static StaticTree static_bl_desc = + new StaticTree(null, Tree.extra_blbits, + 0, BL_CODES, MAX_BL_BITS); + + short[] static_tree; // static tree or null + int[] extra_bits; // extra bits for each code or null + int extra_base; // base index for extra_bits + int elems; // max number of elements in the tree + int max_length; // max bit length for the codes + + private StaticTree(short[] static_tree, + int[] extra_bits, + int extra_base, + int elems, + int max_length){ + this.static_tree=static_tree; + this.extra_bits=extra_bits; + this.extra_base=extra_base; + this.elems=elems; + this.max_length=max_length; + } +} diff --git a/src/lwjgl/java/com/jcraft/jzlib/Tree.java b/src/lwjgl/java/com/jcraft/jzlib/Tree.java new file mode 100644 index 0000000..38cb40f --- /dev/null +++ b/src/lwjgl/java/com/jcraft/jzlib/Tree.java @@ -0,0 +1,367 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package com.jcraft.jzlib; + +final class Tree{ + static final private int MAX_BITS=15; + static final private int BL_CODES=19; + static final private int D_CODES=30; + static final private int LITERALS=256; + static final private int LENGTH_CODES=29; + static final private int L_CODES=(LITERALS+1+LENGTH_CODES); + static final private int HEAP_SIZE=(2*L_CODES+1); + + // Bit length codes must not exceed MAX_BL_BITS bits + static final int MAX_BL_BITS=7; + + // end of block literal code + static final int END_BLOCK=256; + + // repeat previous bit length 3-6 times (2 bits of repeat count) + static final int REP_3_6=16; + + // repeat a zero length 3-10 times (3 bits of repeat count) + static final int REPZ_3_10=17; + + // repeat a zero length 11-138 times (7 bits of repeat count) + static final int REPZ_11_138=18; + + // extra bits for each length code + static final int[] extra_lbits={ + 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0 + }; + + // extra bits for each distance code + static final int[] extra_dbits={ + 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 + }; + + // extra bits for each bit length code + static final int[] extra_blbits={ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7 + }; + + static final byte[] bl_order={ + 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; + + + // The lengths of the bit length codes are sent in order of decreasing + // probability, to avoid transmitting the lengths for unused bit + // length codes. + + static final int Buf_size=8*2; + + // see definition of array dist_code below + static final int DIST_CODE_LEN=512; + + static final byte[] _dist_code = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, + 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, + 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 + }; + + static final byte[] _length_code={ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, + 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, + 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, + 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 + }; + + static final int[] base_length = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, + 64, 80, 96, 112, 128, 160, 192, 224, 0 + }; + + static final int[] base_dist = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 + }; + + // Mapping from a distance to a distance code. dist is the distance - 1 and + // must not have side effects. _dist_code[256] and _dist_code[257] are never + // used. + static int d_code(int dist){ + return ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>>7)]); + } + + short[] dyn_tree; // the dynamic tree + int max_code; // largest code with non zero frequency + StaticTree stat_desc; // the corresponding static tree + + // Compute the optimal bit lengths for a tree and update the total bit length + // for the current block. + // IN assertion: the fields freq and dad are set, heap[heap_max] and + // above are the tree nodes sorted by increasing frequency. + // OUT assertions: the field len is set to the optimal bit length, the + // array bl_count contains the frequencies for each bit length. + // The length opt_len is updated; static_len is also updated if stree is + // not null. + void gen_bitlen(Deflate s){ + short[] tree = dyn_tree; + short[] stree = stat_desc.static_tree; + int[] extra = stat_desc.extra_bits; + int base = stat_desc.extra_base; + int max_length = stat_desc.max_length; + int h; // heap index + int n, m; // iterate over the tree elements + int bits; // bit length + int xbits; // extra bits + short f; // frequency + int overflow = 0; // number of elements with bit length too large + + for (bits = 0; bits <= MAX_BITS; bits++) s.bl_count[bits] = 0; + + // In a first pass, compute the optimal bit lengths (which may + // overflow in the case of the bit length tree). + tree[s.heap[s.heap_max]*2+1] = 0; // root of the heap + + for(h=s.heap_max+1; h max_length){ bits = max_length; overflow++; } + tree[n*2+1] = (short)bits; + // We overwrite tree[n*2+1] which is no longer needed + + if (n > max_code) continue; // not a leaf node + + s.bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n*2]; + s.opt_len += f * (bits + xbits); + if (stree!=null) s.static_len += f * (stree[n*2+1] + xbits); + } + if (overflow == 0) return; + + // This happens for example on obj2 and pic of the Calgary corpus + // Find the first bit length which could increase: + do { + bits = max_length-1; + while(s.bl_count[bits]==0) bits--; + s.bl_count[bits]--; // move one leaf down the tree + s.bl_count[bits+1]+=2; // move one overflow item as its brother + s.bl_count[max_length]--; + // The brother of the overflow item also moves one step up, + // but this does not affect bl_count[max_length] + overflow -= 2; + } + while (overflow > 0); + + for (bits = max_length; bits != 0; bits--) { + n = s.bl_count[bits]; + while (n != 0) { + m = s.heap[--h]; + if (m > max_code) continue; + if (tree[m*2+1] != bits) { + s.opt_len += ((long)bits - (long)tree[m*2+1])*(long)tree[m*2]; + tree[m*2+1] = (short)bits; + } + n--; + } + } + } + + // Construct one Huffman tree and assigns the code bit strings and lengths. + // Update the total bit length for the current block. + // IN assertion: the field freq is set for all tree elements. + // OUT assertions: the fields len and code are set to the optimal bit length + // and corresponding code. The length opt_len is updated; static_len is + // also updated if stree is not null. The field max_code is set. + void build_tree(Deflate s){ + short[] tree=dyn_tree; + short[] stree=stat_desc.static_tree; + int elems=stat_desc.elems; + int n, m; // iterate over heap elements + int max_code=-1; // largest code with non zero frequency + int node; // new node being created + + // Construct the initial heap, with least frequent element in + // heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + // heap[0] is not used. + s.heap_len = 0; + s.heap_max = HEAP_SIZE; + + for(n=0; n=1; n--) + s.pqdownheap(tree, n); + + // Construct the Huffman tree by repeatedly combining the least two + // frequent nodes. + + node=elems; // next internal node of the tree + do{ + // n = node of least frequency + n=s.heap[1]; + s.heap[1]=s.heap[s.heap_len--]; + s.pqdownheap(tree, 1); + m=s.heap[1]; // m = node of next least frequency + + s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency + s.heap[--s.heap_max] = m; + + // Create a new node father of n and m + tree[node*2] = (short)(tree[n*2] + tree[m*2]); + s.depth[node] = (byte)(Math.max(s.depth[n],s.depth[m])+1); + tree[n*2+1] = tree[m*2+1] = (short)node; + + // and insert the new node in the heap + s.heap[1] = node++; + s.pqdownheap(tree, 1); + } + while(s.heap_len>=2); + + s.heap[--s.heap_max] = s.heap[1]; + + // At this point, the fields freq and dad are set. We can now + // generate the bit lengths. + + gen_bitlen(s); + + // The field len is now set, we can generate the bit codes + gen_codes(tree, max_code, s.bl_count, s.next_code); + } + + // Generate the codes for a given tree and bit counts (which need not be + // optimal). + // IN assertion: the array bl_count contains the bit length statistics for + // the given tree and the field len is set for all tree elements. + // OUT assertion: the field code is set for all tree elements of non + // zero code length. + private final static void gen_codes( + short[] tree, // the tree to decorate + int max_code, // largest code with non zero frequency + short[] bl_count, // number of codes at each bit length + short[] next_code){ + short code = 0; // running code value + int bits; // bit index + int n; // code index + + // The distribution counts are first used to generate the code values + // without bit reversal. + next_code[0]=0; + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (short)((code + bl_count[bits-1]) << 1); + } + + // Check that the bit counts in bl_count are consistent. The last code + // must be all ones. + //Assert (code + bl_count[MAX_BITS]-1 == (1<>>=1; + res<<=1; + } + while(--len>0); + return res>>>1; + } +} + diff --git a/src/lwjgl/java/com/jcraft/jzlib/ZInputStream.java b/src/lwjgl/java/com/jcraft/jzlib/ZInputStream.java new file mode 100644 index 0000000..cbd38e1 --- /dev/null +++ b/src/lwjgl/java/com/jcraft/jzlib/ZInputStream.java @@ -0,0 +1,126 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jcraft.jzlib; +import java.io.*; + +/** + * ZInputStream + * + * @deprecated use DeflaterOutputStream or InflaterInputStream + */ +@Deprecated +public class ZInputStream extends FilterInputStream { + + protected int flush=JZlib.Z_NO_FLUSH; + protected boolean compress; + protected InputStream in=null; + + protected Deflater deflater; + protected InflaterInputStream iis; + + public ZInputStream(InputStream in) throws IOException { + this(in, false); + } + public ZInputStream(InputStream in, boolean nowrap) throws IOException { + super(in); + iis = new InflaterInputStream(in, nowrap); + compress=false; + } + + public ZInputStream(InputStream in, int level) throws IOException { + super(in); + this.in=in; + deflater = new Deflater(); + deflater.init(level); + compress=true; + } + + private byte[] buf1 = new byte[1]; + public int read() throws IOException { + if(read(buf1, 0, 1)==-1) return -1; + return(buf1[0]&0xFF); + } + + private byte[] buf = new byte[512]; + + public int read(byte[] b, int off, int len) throws IOException { + if(compress){ + deflater.setOutput(b, off, len); + while(true){ + int datalen = in.read(buf, 0, buf.length); + if(datalen == -1) return -1; + deflater.setInput(buf, 0, datalen, true); + int err = deflater.deflate(flush); + if(deflater.next_out_index>0) + return deflater.next_out_index; + if(err == JZlib.Z_STREAM_END) + return 0; + if(err == JZlib.Z_STREAM_ERROR || + err == JZlib.Z_DATA_ERROR){ + throw new ZStreamException("deflating: "+deflater.msg); + } + } + } + else{ + return iis.read(b, off, len); + } + } + + public long skip(long n) throws IOException { + int len=512; + if(n0){ + inflater.setOutput(buf, 0, buf.length); + err = inflater.inflate(flush); + if(inflater.next_out_index>0) + out.write(buf, 0, inflater.next_out_index); + if(err != JZlib.Z_OK) + break; + } + if(err != JZlib.Z_OK) + throw new ZStreamException("inflating: "+inflater.msg); + return; + } + } + + public int getFlushMode() { + return flush; + } + + public void setFlushMode(int flush) { + this.flush=flush; + } + + public void finish() throws IOException { + int err; + if(compress){ + int tmp = flush; + int flush = JZlib.Z_FINISH; + try{ + write("".getBytes(), 0, 0); + } + finally { flush = tmp; } + } + else{ + dos.finish(); + } + flush(); + } + public synchronized void end() { + if(end) return; + if(compress){ + try { dos.finish(); } catch(Exception e){} + } + else{ + inflater.end(); + } + end=true; + } + public void close() throws IOException { + try{ + try{finish();} + catch (IOException ignored) {} + } + finally{ + end(); + out.close(); + out=null; + } + } + + public long getTotalIn() { + if(compress) return dos.getTotalIn(); + else return inflater.total_in; + } + + public long getTotalOut() { + if(compress) return dos.getTotalOut(); + else return inflater.total_out; + } + + public void flush() throws IOException { + out.flush(); + } + +} diff --git a/src/lwjgl/java/com/jcraft/jzlib/ZStream.java b/src/lwjgl/java/com/jcraft/jzlib/ZStream.java new file mode 100644 index 0000000..0afa4fd --- /dev/null +++ b/src/lwjgl/java/com/jcraft/jzlib/ZStream.java @@ -0,0 +1,377 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2000-2011 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package com.jcraft.jzlib; + +/** + * ZStream + * + * @deprecated Not for public use in the future. + */ +@Deprecated +public class ZStream{ + + static final private int MAX_WBITS=15; // 32K LZ77 window + static final private int DEF_WBITS=MAX_WBITS; + + static final private int Z_NO_FLUSH=0; + static final private int Z_PARTIAL_FLUSH=1; + static final private int Z_SYNC_FLUSH=2; + static final private int Z_FULL_FLUSH=3; + static final private int Z_FINISH=4; + + static final private int MAX_MEM_LEVEL=9; + + static final private int Z_OK=0; + static final private int Z_STREAM_END=1; + static final private int Z_NEED_DICT=2; + static final private int Z_ERRNO=-1; + static final private int Z_STREAM_ERROR=-2; + static final private int Z_DATA_ERROR=-3; + static final private int Z_MEM_ERROR=-4; + static final private int Z_BUF_ERROR=-5; + static final private int Z_VERSION_ERROR=-6; + + public byte[] next_in; // next input byte + public int next_in_index; + public int avail_in; // number of bytes available at next_in + public long total_in; // total nb of input bytes read so far + + public byte[] next_out; // next output byte should be put there + public int next_out_index; + public int avail_out; // remaining free space at next_out + public long total_out; // total nb of bytes output so far + + public String msg; + + Deflate dstate; + Inflate istate; + + int data_type; // best guess about the data type: ascii or binary + + Checksum adler; + + public ZStream(){ + this(new Adler32()); + } + + public ZStream(Checksum adler){ + this.adler=adler; + } + + public int inflateInit(){ + return inflateInit(DEF_WBITS); + } + public int inflateInit(boolean nowrap){ + return inflateInit(DEF_WBITS, nowrap); + } + public int inflateInit(int w){ + return inflateInit(w, false); + } + public int inflateInit(JZlib.WrapperType wrapperType) { + return inflateInit(DEF_WBITS, wrapperType); + } + public int inflateInit(int w, JZlib.WrapperType wrapperType) { + boolean nowrap = false; + if(wrapperType == JZlib.W_NONE){ + nowrap = true; + } + else if(wrapperType == JZlib.W_GZIP) { + w += 16; + } + else if(wrapperType == JZlib.W_ANY) { + w |= Inflate.INFLATE_ANY; + } + else if(wrapperType == JZlib.W_ZLIB) { + } + return inflateInit(w, nowrap); + } + public int inflateInit(int w, boolean nowrap){ + istate=new Inflate(this); + return istate.inflateInit(nowrap?-w:w); + } + + public int inflate(int f){ + if(istate==null) return Z_STREAM_ERROR; + return istate.inflate(f); + } + public int inflateEnd(){ + if(istate==null) return Z_STREAM_ERROR; + int ret=istate.inflateEnd(); +// istate = null; + return ret; + } + public int inflateSync(){ + if(istate == null) + return Z_STREAM_ERROR; + return istate.inflateSync(); + } + public int inflateSyncPoint(){ + if(istate == null) + return Z_STREAM_ERROR; + return istate.inflateSyncPoint(); + } + public int inflateSetDictionary(byte[] dictionary, int dictLength){ + if(istate == null) + return Z_STREAM_ERROR; + return istate.inflateSetDictionary(dictionary, dictLength); + } + public boolean inflateFinished(){ + return istate.mode==12 /*DONE*/; + } + + public int deflateInit(int level){ + return deflateInit(level, MAX_WBITS); + } + public int deflateInit(int level, boolean nowrap){ + return deflateInit(level, MAX_WBITS, nowrap); + } + public int deflateInit(int level, int bits){ + return deflateInit(level, bits, false); + } + public int deflateInit(int level, int bits, int memlevel, JZlib.WrapperType wrapperType){ + if(bits < 9 || bits > 15){ + return Z_STREAM_ERROR; + } + if(wrapperType == JZlib.W_NONE) { + bits *= -1; + } + else if(wrapperType == JZlib.W_GZIP) { + bits += 16; + } + else if(wrapperType == JZlib.W_ANY) { + return Z_STREAM_ERROR; + } + else if(wrapperType == JZlib.W_ZLIB) { + } + return this.deflateInit(level, bits, memlevel); + } + public int deflateInit(int level, int bits, int memlevel){ + dstate=new Deflate(this); + return dstate.deflateInit(level, bits, memlevel); + } + public int deflateInit(int level, int bits, boolean nowrap){ + dstate=new Deflate(this); + return dstate.deflateInit(level, nowrap?-bits:bits); + } + public int deflate(int flush){ + if(dstate==null){ + return Z_STREAM_ERROR; + } + return dstate.deflate(flush); + } + public int deflateEnd(){ + if(dstate==null) return Z_STREAM_ERROR; + int ret=dstate.deflateEnd(); + dstate=null; + return ret; + } + public int deflateParams(int level, int strategy){ + if(dstate==null) return Z_STREAM_ERROR; + return dstate.deflateParams(level, strategy); + } + public int deflateSetDictionary (byte[] dictionary, int dictLength){ + if(dstate == null) + return Z_STREAM_ERROR; + return dstate.deflateSetDictionary(dictionary, dictLength); + } + + // Flush as much pending output as possible. All deflate() output goes + // through this function so some applications may wish to modify it + // to avoid allocating a large strm->next_out buffer and copying into it. + // (See also read_buf()). + void flush_pending(){ + int len=dstate.pending; + + if(len>avail_out) len=avail_out; + if(len==0) return; + + if(dstate.pending_buf.length<=dstate.pending_out || + next_out.length<=next_out_index || + dstate.pending_buf.length<(dstate.pending_out+len) || + next_out.length<(next_out_index+len)){ + //System.out.println(dstate.pending_buf.length+", "+dstate.pending_out+ + // ", "+next_out.length+", "+next_out_index+", "+len); + //System.out.println("avail_out="+avail_out); + } + + System.arraycopy(dstate.pending_buf, dstate.pending_out, + next_out, next_out_index, len); + + next_out_index+=len; + dstate.pending_out+=len; + total_out+=len; + avail_out-=len; + dstate.pending-=len; + if(dstate.pending==0){ + dstate.pending_out=0; + } + } + + // Read a new buffer from the current input stream, update the adler32 + // and total number of bytes read. All deflate() input goes through + // this function so some applications may wish to modify it to avoid + // allocating a large strm->next_in buffer and copying from it. + // (See also flush_pending()). + int read_buf(byte[] buf, int start, int size) { + int len=avail_in; + + if(len>size) len=size; + if(len==0) return 0; + + avail_in-=len; + + if(dstate.wrap!=0) { + adler.update(next_in, next_in_index, len); + } + System.arraycopy(next_in, next_in_index, buf, start, len); + next_in_index += len; + total_in += len; + return len; + } + + public long getAdler(){ + return adler.getValue(); + } + + public void free(){ + next_in=null; + next_out=null; + msg=null; + } + + public void setOutput(byte[] buf){ + setOutput(buf, 0, buf.length); + } + + public void setOutput(byte[] buf, int off, int len){ + next_out = buf; + next_out_index = off; + avail_out = len; + } + + public void setInput(byte[] buf){ + setInput(buf, 0, buf.length, false); + } + + public void setInput(byte[] buf, boolean append){ + setInput(buf, 0, buf.length, append); + } + + public void setInput(byte[] buf, int off, int len, boolean append){ + if(len<=0 && append && next_in!=null) return; + + if(avail_in>0 && append){ + byte[] tmp = new byte[avail_in+len]; + System.arraycopy(next_in, next_in_index, tmp, 0, avail_in); + System.arraycopy(buf, off, tmp, avail_in, len); + next_in=tmp; + next_in_index=0; + avail_in+=len; + } + else{ + next_in=buf; + next_in_index=off; + avail_in=len; + } + } + + public byte[] getNextIn(){ + return next_in; + } + + public void setNextIn(byte[] next_in){ + this.next_in = next_in; + } + + public int getNextInIndex(){ + return next_in_index; + } + + public void setNextInIndex(int next_in_index){ + this.next_in_index = next_in_index; + } + + public int getAvailIn(){ + return avail_in; + } + + public void setAvailIn(int avail_in){ + this.avail_in = avail_in; + } + + public byte[] getNextOut(){ + return next_out; + } + + public void setNextOut(byte[] next_out){ + this.next_out = next_out; + } + + public int getNextOutIndex(){ + return next_out_index; + } + + public void setNextOutIndex(int next_out_index){ + this.next_out_index = next_out_index; + } + + public int getAvailOut(){ + return avail_out; + + } + + public void setAvailOut(int avail_out){ + this.avail_out = avail_out; + } + + public long getTotalOut(){ + return total_out; + } + + public long getTotalIn(){ + return total_in; + } + + public String getMessage(){ + return msg; + } + + /** + * Those methods are expected to be override by Inflater and Deflater. + * In the future, they will become abstract methods. + */ + public int end(){ return Z_OK; } + public boolean finished(){ return false; } +} diff --git a/src/lwjgl/java/com/jcraft/jzlib/ZStreamException.java b/src/lwjgl/java/com/jcraft/jzlib/ZStreamException.java new file mode 100644 index 0000000..424b74b --- /dev/null +++ b/src/lwjgl/java/com/jcraft/jzlib/ZStreamException.java @@ -0,0 +1,44 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package com.jcraft.jzlib; + +public class ZStreamException extends java.io.IOException { + public ZStreamException() { + super(); + } + public ZStreamException(String s) { + super(s); + } +} diff --git a/src/lwjgl/java/de/cuina/fireandfuel/CodecJLayerMP3.java b/src/lwjgl/java/de/cuina/fireandfuel/CodecJLayerMP3.java new file mode 100644 index 0000000..3049639 --- /dev/null +++ b/src/lwjgl/java/de/cuina/fireandfuel/CodecJLayerMP3.java @@ -0,0 +1,586 @@ +package de.cuina.fireandfuel; + +/* + * CodecJLayerMP3 - an ICodec interface for Paulscode Sound System + * Copyright (C) 2012 by fireandfuel from Cuina Team (http://www.cuina.byethost12.com/) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see http://www.gnu.org/licenses/lgpl.txt + */ + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.net.URL; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; + +import javazoom.jl.decoder.Bitstream; +import javazoom.jl.decoder.Decoder; +import javazoom.jl.decoder.Header; +import javazoom.jl.decoder.Obuffer; +import javazoom.mp3spi.DecodedMpegAudioInputStream; + +import paulscode.sound.ICodec; +import paulscode.sound.SoundBuffer; +import paulscode.sound.SoundSystemConfig; +import paulscode.sound.SoundSystemLogger; + +/** + * The CodecJLayer class provides an ICodec interface to the external JLayer + * library. + * + *
+ *
+ * This software is based on or using the JLayer and mp3spi library from + * http://www.javazoom.net/javalayer/javalayer.html and Tritonus library from + * http://www.tritonus.org/. + * + * JLayer, mp3spi and Tritonus library are released under the conditions of + * GNU Library General Public License version 2 or (at your option) + * any later version of the License. + *

+ */ + +public class CodecJLayerMP3 implements ICodec +{ + /** + * Used to return a current value from one of the synchronized + * boolean-interface methods. + */ + private static final boolean GET = false; + + /** + * Used to set the value in one of the synchronized boolean-interface + * methods. + */ + private static final boolean SET = true; + + /** + * Used when a parameter for one of the synchronized boolean-interface + * methods is not applicable. + */ + private static final boolean XXX = false; + + /** + * True if there is no more data to read in. + */ + private boolean endOfStream = false; + + /** + * True if the stream has finished initializing. + */ + private boolean initialized = false; + + private Decoder decoder; + private Bitstream bitstream; + private DMAISObuffer buffer; + + private Header mainHeader; + + /** + * Audio format to use when playing back the wave data. + */ + private AudioFormat myAudioFormat = null; + + /** + * Input stream to use for reading in pcm data. + */ + private DecodedMpegAudioInputStream myAudioInputStream = null; + + /** + * Processes status messages, warnings, and error messages. + */ + private SoundSystemLogger logger; + + public CodecJLayerMP3() + { + logger = SoundSystemConfig.getLogger(); + } + + @Override + public void reverseByteOrder(boolean b) + { + } + + @Override + public boolean initialize(URL url) + { + initialized(SET, false); + cleanup(); + if(url == null) + { + errorMessage("url null in method 'initialize'"); + cleanup(); + return false; + } + + try + { + bitstream = new Bitstream(new BufferedInputStream(url.openStream())); + decoder = new Decoder(); + + mainHeader = bitstream.readFrame(); + + buffer = new DMAISObuffer(2); + decoder.setOutputBuffer(buffer); + + int channels; + if(mainHeader.mode() < 3) + channels = 2; + else channels = 1; + + bitstream.closeFrame(); + bitstream.close(); + + myAudioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, + mainHeader.frequency(), 16, channels, channels * 2, mainHeader.frequency(), + false); + + AudioFormat mpegAudioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, -1.0f, + 16, channels, channels * 2, -1.0f, false); + + myAudioInputStream = new DecodedMpegAudioInputStream(myAudioFormat, + new AudioInputStream(new BufferedInputStream(url.openStream()), + mpegAudioFormat, -1)); + myAudioInputStream.skip((int)(myAudioInputStream.getFormat().getFrameRate() * 0.018f) * myAudioInputStream.getFormat().getFrameSize()); + } catch (Exception e) + { + errorMessage("Unable to set up input streams in method " + "'initialize'"); + printStackTrace(e); + cleanup(); + return false; + } + + if(myAudioInputStream == null) + { + errorMessage("Unable to set up audio input stream in method " + "'initialize'"); + cleanup(); + return false; + } + + endOfStream(SET, false); + initialized(SET, true); + return true; + } + + @Override + public boolean initialized() + { + return initialized(GET, XXX); + } + + @Override + public SoundBuffer read() + { + if(myAudioInputStream == null) + { + endOfStream(SET, true); + return null; + } + + // Get the format for the audio data: + AudioFormat audioFormat = myAudioInputStream.getFormat(); + + // Check to make sure there is an audio format: + if(audioFormat == null) + { + errorMessage("Audio Format null in method 'read'"); + endOfStream(SET, true); + return null; + } + + // Variables used when reading from the audio input stream: + int bytesRead = 0, cnt = 0; + + // Allocate memory for the audio data: + byte[] streamBuffer = new byte[SoundSystemConfig.getStreamingBufferSize()]; + + try + { + // Read until buffer is full or end of stream is reached: + while((!endOfStream(GET, XXX)) && (bytesRead < streamBuffer.length)) + { + myAudioInputStream.execute(); + if((cnt = myAudioInputStream.read(streamBuffer, bytesRead, streamBuffer.length + - bytesRead)) < 0) + { + endOfStream(SET, true); + break; + } + // keep track of how many bytes were read: + bytesRead += cnt; + } + } catch (IOException ioe) + { + + /* + * errorMessage( "Exception thrown while reading from the " + + * "AudioInputStream (location #3)." ); printStackTrace( e ); return + * null; + */// TODO: Figure out why this exceptions is being thrown at end of + // MP3 files! + endOfStream(SET, true); + return null; + } catch (ArrayIndexOutOfBoundsException e) + { + //this exception is thrown at the end of the mp3's + endOfStream(SET, true); + return null; + } + + // Return null if no data was read: + if(bytesRead <= 0) + { + endOfStream(SET, true); + return null; + } + + // Insert the converted data into a ByteBuffer: + // byte[] data = convertAudioBytes(streamBuffer, + // audioFormat.getSampleSizeInBits() == 16); + + // Wrap the data into a SoundBuffer: + SoundBuffer buffer = new SoundBuffer(streamBuffer, audioFormat); + + // Return the result: + return buffer; + } + + @Override + public SoundBuffer readAll() + { + // Check to make sure there is an audio format: + if(myAudioFormat == null) + { + errorMessage("Audio Format null in method 'readAll'"); + return null; + } + + // Array to contain the audio data: + byte[] fullBuffer = null; + + // Determine how much data will be read in: + int fileSize = myAudioFormat.getChannels() * (int) myAudioInputStream.getFrameLength() + * myAudioFormat.getSampleSizeInBits() / 8; + if(fileSize > 0) + { + // Allocate memory for the audio data: + fullBuffer = new byte[myAudioFormat.getChannels() + * (int) myAudioInputStream.getFrameLength() + * myAudioFormat.getSampleSizeInBits() / 8]; + int read = 0, total = 0; + try + { + // Read until the end of the stream is reached: + while((read = myAudioInputStream.read(fullBuffer, total, fullBuffer.length - total)) != -1 + && total < fullBuffer.length) + { + total += read; + } + } catch (IOException e) + { + errorMessage("Exception thrown while reading from the " + + "AudioInputStream (location #1)."); + printStackTrace(e); + return null; + } + } else + { + // Total file size unknown. + + // Variables used when reading from the audio input stream: + int totalBytes = 0, bytesRead = 0, cnt = 0; + byte[] smallBuffer = null; + + // Allocate memory for a chunk of data: + smallBuffer = new byte[SoundSystemConfig.getFileChunkSize()]; + + // Read until end of file or maximum file size is reached: + while((!endOfStream(GET, XXX)) && (totalBytes < SoundSystemConfig.getMaxFileSize())) + { + bytesRead = 0; + cnt = 0; + + try + { + // Read until small buffer is filled or end of file reached: + while(bytesRead < smallBuffer.length) + { + myAudioInputStream.execute(); + if((cnt = myAudioInputStream.read(smallBuffer, bytesRead, + smallBuffer.length - bytesRead)) < 0) + { + endOfStream(SET, true); + break; + } + bytesRead += cnt; + } + } catch (IOException e) + { + errorMessage("Exception thrown while reading from the " + + "AudioInputStream (location #2)."); + printStackTrace(e); + return null; + } + + // Reverse byte order if necessary: + // if( reverseBytes ) + // reverseBytes( smallBuffer, 0, bytesRead ); + + // Keep track of the total number of bytes read: + totalBytes += bytesRead; + + // Append the small buffer to the full buffer: + fullBuffer = appendByteArrays(fullBuffer, smallBuffer, bytesRead); + } + } + + // Insert the converted data into a ByteBuffer + // byte[] data = convertAudioBytes( fullBuffer, + // myAudioFormat.getSampleSizeInBits() == 16 ); + + // Wrap the data into an SoundBuffer: + SoundBuffer soundBuffer = new SoundBuffer(fullBuffer, myAudioFormat); + + // Close the audio input stream + try + { + myAudioInputStream.close(); + } catch (IOException e) + { + } + + // Return the result: + return soundBuffer; + } + + @Override + public boolean endOfStream() + { + return endOfStream(GET, XXX); + } + + @Override + public void cleanup() + { + if(myAudioInputStream != null) + try + { + myAudioInputStream.close(); + } catch (Exception e) + { + } + } + + @Override + public AudioFormat getAudioFormat() + { + return myAudioFormat; + } + + /** + * Internal method for synchronizing access to the boolean 'initialized'. + * + * @param action + * GET or SET. + * @param value + * New value if action == SET, or XXX if action == GET. + * @return True if steam is initialized. + */ + private synchronized boolean initialized(boolean action, boolean value) + { + if(action == SET) + initialized = value; + return initialized; + } + + /** + * Internal method for synchronizing access to the boolean 'endOfStream'. + * + * @param action + * GET or SET. + * @param value + * New value if action == SET, or XXX if action == GET. + * @return True if end of stream was reached. + */ + private synchronized boolean endOfStream(boolean action, boolean value) + { + if(action == SET) + endOfStream = value; + return endOfStream; + } + + /** + * Reverse-orders all bytes contained in the specified array. + * + * @param buffer + * Array containing audio data. + */ + public static void reverseBytes(byte[] buffer) + { + reverseBytes(buffer, 0, buffer.length); + } + + /** + * Reverse-orders the specified range of bytes contained in the specified + * array. + * + * @param buffer + * Array containing audio data. + * @param offset + * Array index to begin. + * @param size + * number of bytes to reverse-order. + */ + public static void reverseBytes(byte[] buffer, int offset, int size) + { + + byte b; + for(int i = offset; i < (offset + size); i += 2) + { + b = buffer[i]; + buffer[i] = buffer[i + 1]; + buffer[i + 1] = b; + } + } + + /** + * Prints an error message. + * + * @param message + * Message to print. + */ + private void errorMessage(String message) + { + logger.errorMessage("CodecJLayerMP3", message, 0); + } + + /** + * Prints an exception's error message followed by the stack trace. + * + * @param e + * Exception containing the information to print. + */ + private void printStackTrace(Exception e) + { + logger.printStackTrace(e, 1); + } + + /** + * Creates a new array with the second array appended to the end of the + * first array. + * + * @param arrayOne + * The first array. + * @param arrayTwo + * The second array. + * @param length + * How many bytes to append from the second array. + * @return Byte array containing information from both arrays. + */ + private static byte[] appendByteArrays(byte[] arrayOne, byte[] arrayTwo, int length) + { + byte[] newArray; + if(arrayOne == null && arrayTwo == null) + { + // no data, just return + return null; + } else if(arrayOne == null) + { + // create the new array, same length as arrayTwo: + newArray = new byte[length]; + // fill the new array with the contents of arrayTwo: + System.arraycopy(arrayTwo, 0, newArray, 0, length); + arrayTwo = null; + } else if(arrayTwo == null) + { + // create the new array, same length as arrayOne: + newArray = new byte[arrayOne.length]; + // fill the new array with the contents of arrayOne: + System.arraycopy(arrayOne, 0, newArray, 0, arrayOne.length); + arrayOne = null; + } else + { + // create the new array large enough to hold both arrays: + newArray = new byte[arrayOne.length + length]; + System.arraycopy(arrayOne, 0, newArray, 0, arrayOne.length); + // fill the new array with the contents of both arrays: + System.arraycopy(arrayTwo, 0, newArray, arrayOne.length, length); + arrayOne = null; + arrayTwo = null; + } + + return newArray; + } + + private static class DMAISObuffer extends Obuffer + { + private int m_nChannels; + private byte[] m_abBuffer; + private int[] m_anBufferPointers; + private boolean m_bIsBigEndian; + + public DMAISObuffer(int nChannels) + { + m_nChannels = nChannels; + m_abBuffer = new byte[OBUFFERSIZE * nChannels]; + m_anBufferPointers = new int[nChannels]; + reset(); + } + + public void append(int nChannel, short sValue) + { + byte bFirstByte; + byte bSecondByte; + if(m_bIsBigEndian) + { + bFirstByte = (byte) ((sValue >>> 8) & 0xFF); + bSecondByte = (byte) (sValue & 0xFF); + } else + // little endian + { + bFirstByte = (byte) (sValue & 0xFF); + bSecondByte = (byte) ((sValue >>> 8) & 0xFF); + } + m_abBuffer[m_anBufferPointers[nChannel]] = bFirstByte; + m_abBuffer[m_anBufferPointers[nChannel] + 1] = bSecondByte; + m_anBufferPointers[nChannel] += m_nChannels * 2; + } + + public void set_stop_flag() + { + } + + public void close() + { + } + + public void write_buffer(int nValue) + { + } + + public void clear_buffer() + { + } + + public void reset() + { + for(int i = 0; i < m_nChannels; i++) + { + /* + * Points to byte location, implicitly assuming 16 bit samples. + */ + m_anBufferPointers[i] = i * 2; + } + } + } +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/BitReserve.java b/src/lwjgl/java/javazoom/jl/decoder/BitReserve.java new file mode 100644 index 0000000..fa3deab --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/BitReserve.java @@ -0,0 +1,224 @@ +/* + * 11/19/04 1.0 moved to LGPL. + * + * 12/12/99 0.0.7 Implementation stores single bits + * as ints for better performance. mdm@techie.com. + * + * 02/28/99 0.0 Java Conversion by E.B, javalayer@javazoom.net + * + * Adapted from the public c code by Jeff Tsay. + * + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + +package javazoom.jl.decoder; + +/** + * Implementation of Bit Reservoir for Layer III. + *

+ * The implementation stores single bits as a word in the buffer. If + * a bit is set, the corresponding word in the buffer will be non-zero. + * If a bit is clear, the corresponding word is zero. Although this + * may seem wasteful, this can be a factor of two quicker than + * packing 8 bits to a byte and extracting. + *

+ */ + +// REVIEW: there is no range checking, so buffer underflow or overflow +// can silently occur. +final class BitReserve +{ + /** + * Size of the internal buffer to store the reserved bits. + * Must be a power of 2. And x8, as each bit is stored as a single + * entry. + */ + private static final int BUFSIZE = 4096*8; + + /** + * Mask that can be used to quickly implement the + * modulus operation on BUFSIZE. + */ + private static final int BUFSIZE_MASK = BUFSIZE-1; + + private int offset, totbit, buf_byte_idx; + private final int[] buf = new int[BUFSIZE]; + private int buf_bit_idx; + + BitReserve() + { + + offset = 0; + totbit = 0; + buf_byte_idx = 0; + } + + + /** + * Return totbit Field. + */ + public int hsstell() + { + return(totbit); + } + + /** + * Read a number bits from the bit stream. + * @param N the number of + */ + public int hgetbits(int N) + { + totbit += N; + + int val = 0; + + int pos = buf_byte_idx; + if (pos+N < BUFSIZE) + { + while (N-- > 0) + { + val <<= 1; + val |= ((buf[pos++]!=0) ? 1 : 0); + } + } + else + { + while (N-- > 0) + { + val <<= 1; + val |= ((buf[pos]!=0) ? 1 : 0); + pos = (pos+1) & BUFSIZE_MASK; + } + } + buf_byte_idx = pos; + return val; + } + + + + /** + * Read 1 bit from the bit stream. + */ +/* + public int hget1bit_old() + { + int val; + totbit++; + if (buf_bit_idx == 0) + { + buf_bit_idx = 8; + buf_byte_idx++; + } + // BUFSIZE = 4096 = 2^12, so + // buf_byte_idx%BUFSIZE == buf_byte_idx & 0xfff + val = buf[buf_byte_idx & BUFSIZE_MASK] & putmask[buf_bit_idx]; + buf_bit_idx--; + val = val >>> buf_bit_idx; + return val; + } + */ + /** + * Returns next bit from reserve. + * + * @return 0 if next bit is reset, or 1 if next bit is set. + */ + public int hget1bit() + { + totbit++; + int val = buf[buf_byte_idx]; + buf_byte_idx = (buf_byte_idx+1) & BUFSIZE_MASK; + return val; + } + + /** + * Retrieves bits from the reserve. + */ +/* + public int readBits(int[] out, int len) + { + if (buf_bit_idx == 0) + { + buf_bit_idx = 8; + buf_byte_idx++; + current = buf[buf_byte_idx & BUFSIZE_MASK]; + } + + + + // save total number of bits returned + len = buf_bit_idx; + buf_bit_idx = 0; + + int b = current; + int count = len-1; + + while (count >= 0) + { + out[count--] = (b & 0x1); + b >>>= 1; + } + + totbit += len; + return len; + } + */ + + /** + * Write 8 bits into the bit stream. + */ + public void hputbuf(int val) + { + int ofs = offset; + buf[ofs++] = val & 0x80; + buf[ofs++] = val & 0x40; + buf[ofs++] = val & 0x20; + buf[ofs++] = val & 0x10; + buf[ofs++] = val & 0x08; + buf[ofs++] = val & 0x04; + buf[ofs++] = val & 0x02; + buf[ofs++] = val & 0x01; + + if (ofs==BUFSIZE) + offset = 0; + else + offset = ofs; + + } + + /** + * Rewind N bits in Stream. + */ + public void rewindNbits(int N) + { + totbit -= N; + buf_byte_idx -= N; + if (buf_byte_idx<0) + buf_byte_idx += BUFSIZE; + } + + /** + * Rewind N bytes in Stream. + */ + public void rewindNbytes(int N) + { + int bits = (N << 3); + totbit -= bits; + buf_byte_idx -= bits; + if (buf_byte_idx<0) + buf_byte_idx += BUFSIZE; + } +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/Bitstream.java b/src/lwjgl/java/javazoom/jl/decoder/Bitstream.java new file mode 100644 index 0000000..6286160 --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/Bitstream.java @@ -0,0 +1,659 @@ +/* + * 11/19/04 1.0 moved to LGPL. + * + * 11/17/04 Uncomplete frames discarded. E.B, javalayer@javazoom.net + * + * 12/05/03 ID3v2 tag returned. E.B, javalayer@javazoom.net + * + * 12/12/99 Based on Ibitstream. Exceptions thrown on errors, + * Temporary removed seek functionality. mdm@techie.com + * + * 02/12/99 : Java Conversion by E.B , javalayer@javazoom.net + * + * 04/14/97 : Added function prototypes for new syncing and seeking + * mechanisms. Also made this file portable. Changes made by Jeff Tsay + * + * @(#) ibitstream.h 1.5, last edit: 6/15/94 16:55:34 + * @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de) + * @(#) Berlin University of Technology + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + +package javazoom.jl.decoder; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PushbackInputStream; + + +/** + * The Bistream class is responsible for parsing + * an MPEG audio bitstream. + * + * REVIEW: much of the parsing currently occurs in the + * various decoders. This should be moved into this class and associated + * inner classes. + */ +public final class Bitstream implements BitstreamErrors +{ + /** + * Synchronization control constant for the initial + * synchronization to the start of a frame. + */ + static byte INITIAL_SYNC = 0; + + /** + * Synchronization control constant for non-initial frame + * synchronizations. + */ + static byte STRICT_SYNC = 1; + + // max. 1730 bytes per frame: 144 * 384kbit/s / 32000 Hz + 2 Bytes CRC + /** + * Maximum size of the frame buffer. + */ + private static final int BUFFER_INT_SIZE = 433; + + /** + * The frame buffer that holds the data for the current frame. + */ + private final int[] framebuffer = new int[BUFFER_INT_SIZE]; + + /** + * Number of valid bytes in the frame buffer. + */ + private int framesize; + + /** + * The bytes read from the stream. + */ + private byte[] frame_bytes = new byte[BUFFER_INT_SIZE*4]; + + /** + * Index into framebuffer where the next bits are + * retrieved. + */ + private int wordpointer; + + /** + * Number (0-31, from MSB to LSB) of next bit for get_bits() + */ + private int bitindex; + + /** + * The current specified syncword + */ + private int syncword; + + /** + * Audio header position in stream. + */ + private int header_pos = 0; + + /** + * + */ + private boolean single_ch_mode; + //private int current_frame_number; + //private int last_frame_number; + + private final int bitmask[] = {0, // dummy + 0x00000001, 0x00000003, 0x00000007, 0x0000000F, + 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF, + 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF, + 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, + 0x0001FFFF }; + + private final PushbackInputStream source; + + private final Header header = new Header(); + + private final byte syncbuf[] = new byte[4]; + + private Crc16[] crc = new Crc16[1]; + + private byte[] rawid3v2 = null; + + private boolean firstframe = true; + + + /** + * Construct a IBitstream that reads data from a + * given InputStream. + * + * @param in The InputStream to read from. + */ + public Bitstream(InputStream in) + { + if (in==null) throw new NullPointerException("in"); + in = new BufferedInputStream(in); + loadID3v2(in); + firstframe = true; + //source = new PushbackInputStream(in, 1024); + source = new PushbackInputStream(in, BUFFER_INT_SIZE*4); + + closeFrame(); + //current_frame_number = -1; + //last_frame_number = -1; + } + + /** + * Return position of the first audio header. + * @return size of ID3v2 tag frames. + */ + public int header_pos() + { + return header_pos; + } + + /** + * Load ID3v2 frames. + * @param in MP3 InputStream. + * @author JavaZOOM + */ + private void loadID3v2(InputStream in) + { + int size = -1; + try + { + // Read ID3v2 header (10 bytes). + in.mark(10); + size = readID3v2Header(in); + header_pos = size; + } + catch (IOException e) + {} + finally + { + try + { + // Unread ID3v2 header (10 bytes). + in.reset(); + } + catch (IOException e) + {} + } + // Load ID3v2 tags. + try + { + if (size > 0) + { + rawid3v2 = new byte[size]; + in.read(rawid3v2,0,rawid3v2.length); + } + } + catch (IOException e) + {} + } + + /** + * Parse ID3v2 tag header to find out size of ID3v2 frames. + * @param in MP3 InputStream + * @return size of ID3v2 frames + header + * @throws IOException + * @author JavaZOOM + */ + private int readID3v2Header(InputStream in) throws IOException + { + byte[] id3header = new byte[4]; + int size = -10; + in.read(id3header,0,3); + // Look for ID3v2 + if ( (id3header[0]=='I') && (id3header[1]=='D') && (id3header[2]=='3')) + { + in.read(id3header,0,3); + int majorVersion = id3header[0]; + int revision = id3header[1]; + in.read(id3header,0,4); + size = (int) (id3header[0] << 21) + (id3header[1] << 14) + (id3header[2] << 7) + (id3header[3]); + } + return (size+10); + } + + /** + * Return raw ID3v2 frames + header. + * @return ID3v2 InputStream or null if ID3v2 frames are not available. + */ + public InputStream getRawID3v2() + { + if (rawid3v2 == null) return null; + else + { + ByteArrayInputStream bain = new ByteArrayInputStream(rawid3v2); + return bain; + } + } + + /** + * Close the Bitstream. + * @throws BitstreamException + */ + public void close() throws BitstreamException + { + try + { + source.close(); + } + catch (IOException ex) + { + throw newBitstreamException(STREAM_ERROR, ex); + } + } + + /** + * Reads and parses the next frame from the input source. + * + * @return the Header describing details of the frame read, + * or null if the end of the stream has been reached. + */ + public Header readFrame() throws BitstreamException + { + Header result = null; + try + { + result = readNextFrame(); + // E.B, Parse VBR (if any) first frame. + if (firstframe == true) + { + result.parseVBR(frame_bytes); + firstframe = false; + } + } + catch (BitstreamException ex) + { + if ((ex.getErrorCode()==INVALIDFRAME)) + { + // Try to skip this frame. + //System.out.println("INVALIDFRAME"); + try + { + closeFrame(); + result = readNextFrame(); + } + catch (BitstreamException e) + { + if ((e.getErrorCode()!=STREAM_EOF)) + { + // wrap original exception so stack trace is maintained. + throw newBitstreamException(e.getErrorCode(), e); + } + } + } + else if ((ex.getErrorCode()!=STREAM_EOF)) + { + // wrap original exception so stack trace is maintained. + throw newBitstreamException(ex.getErrorCode(), ex); + } + } + return result; + } + + /** + * Read next MP3 frame. + * + * @return MP3 frame header. + * @throws BitstreamException + */ + private Header readNextFrame() throws BitstreamException + { + if (framesize == -1) + { + nextFrame(); + } + return header; + } + + + /** + * Read next MP3 frame. + * + * @throws BitstreamException + */ + private void nextFrame() throws BitstreamException + { + // entire frame is read by the header class. + header.read_header(this, crc); + } + + /** + * Unreads the bytes read from the frame. + * + * @throws BitstreamException + */ + // REVIEW: add new error codes for this. + public void unreadFrame() throws BitstreamException + { + if (wordpointer==-1 && bitindex==-1 && (framesize>0)) + { + try + { + source.unread(frame_bytes, 0, framesize); + } + catch (IOException ex) + { + throw newBitstreamException(STREAM_ERROR); + } + } + } + + /** + * Close MP3 frame. + */ + public void closeFrame() + { + framesize = -1; + wordpointer = -1; + bitindex = -1; + } + + /** + * Determines if the next 4 bytes of the stream represent a + * frame header. + */ + public boolean isSyncCurrentPosition(int syncmode) throws BitstreamException + { + int read = readBytes(syncbuf, 0, 4); + int headerstring = ((syncbuf[0] << 24) & 0xFF000000) | ((syncbuf[1] << 16) & 0x00FF0000) | ((syncbuf[2] << 8) & 0x0000FF00) | ((syncbuf[3] << 0) & 0x000000FF); + + try + { + source.unread(syncbuf, 0, read); + } + catch (IOException ex) + { + } + + boolean sync = false; + switch (read) + { + case 0: + sync = true; + break; + case 4: + sync = isSyncMark(headerstring, syncmode, syncword); + break; + } + + return sync; + } + + + // REVIEW: this class should provide inner classes to + // parse the frame contents. Eventually, readBits will + // be removed. + public int readBits(int n) + { + return get_bits(n); + } + + public int readCheckedBits(int n) + { + // REVIEW: implement CRC check. + return get_bits(n); + } + + protected BitstreamException newBitstreamException(int errorcode) + { + return new BitstreamException(errorcode, null); + } + protected BitstreamException newBitstreamException(int errorcode, Throwable throwable) + { + return new BitstreamException(errorcode, throwable); + } + + /** + * Get next 32 bits from bitstream. + * They are stored in the headerstring. + * syncmod allows Synchro flag ID + * The returned value is False at the end of stream. + */ + + int syncHeader(byte syncmode) throws BitstreamException + { + boolean sync; + int headerstring; + // read additional 2 bytes + int bytesRead = readBytes(syncbuf, 0, 3); + + if (bytesRead!=3) throw newBitstreamException(STREAM_EOF, null); + + headerstring = ((syncbuf[0] << 16) & 0x00FF0000) | ((syncbuf[1] << 8) & 0x0000FF00) | ((syncbuf[2] << 0) & 0x000000FF); + + do + { + headerstring <<= 8; + + if (readBytes(syncbuf, 3, 1)!=1) + throw newBitstreamException(STREAM_EOF, null); + + headerstring |= (syncbuf[3] & 0x000000FF); + + sync = isSyncMark(headerstring, syncmode, syncword); + } + while (!sync); + + //current_frame_number++; + //if (last_frame_number < current_frame_number) last_frame_number = current_frame_number; + + return headerstring; + } + + public boolean isSyncMark(int headerstring, int syncmode, int word) + { + boolean sync = false; + + if (syncmode == INITIAL_SYNC) + { + //sync = ((headerstring & 0xFFF00000) == 0xFFF00000); + sync = ((headerstring & 0xFFE00000) == 0xFFE00000); // SZD: MPEG 2.5 + } + else + { + sync = ((headerstring & 0xFFF80C00) == word) && + (((headerstring & 0x000000C0) == 0x000000C0) == single_ch_mode); + } + + // filter out invalid sample rate + if (sync) + sync = (((headerstring >>> 10) & 3)!=3); + // filter out invalid layer + if (sync) + sync = (((headerstring >>> 17) & 3)!=0); + // filter out invalid version + if (sync) + sync = (((headerstring >>> 19) & 3)!=1); + + return sync; + } + + /** + * Reads the data for the next frame. The frame is not parsed + * until parse frame is called. + */ + int read_frame_data(int bytesize) throws BitstreamException + { + int numread = 0; + numread = readFully(frame_bytes, 0, bytesize); + framesize = bytesize; + wordpointer = -1; + bitindex = -1; + return numread; + } + + /** + * Parses the data previously read with read_frame_data(). + */ + void parse_frame() throws BitstreamException + { + // Convert Bytes read to int + int b=0; + byte[] byteread = frame_bytes; + int bytesize = framesize; + + // Check ID3v1 TAG (True only if last frame). + //for (int t=0;t<(byteread.length)-2;t++) + //{ + // if ((byteread[t]=='T') && (byteread[t+1]=='A') && (byteread[t+2]=='G')) + // { + // System.out.println("ID3v1 detected at offset "+t); + // throw newBitstreamException(INVALIDFRAME, null); + // } + //} + + for (int k=0;k>> (32 - sum)) & bitmask[number_of_bits]; + // returnvalue = (wordpointer[0] >> (32 - sum)) & bitmask[number_of_bits]; + if ((bitindex += number_of_bits) == 32) + { + bitindex = 0; + wordpointer++; // added by me! + } + return returnvalue; + } + + // E.B : Check that ? + //((short[])&returnvalue)[0] = ((short[])wordpointer + 1)[0]; + //wordpointer++; // Added by me! + //((short[])&returnvalue + 1)[0] = ((short[])wordpointer)[0]; + int Right = (framebuffer[wordpointer] & 0x0000FFFF); + wordpointer++; + int Left = (framebuffer[wordpointer] & 0xFFFF0000); + returnvalue = ((Right << 16) & 0xFFFF0000) | ((Left >>> 16)& 0x0000FFFF); + + returnvalue >>>= 48 - sum; // returnvalue >>= 16 - (number_of_bits - (32 - bitindex)) + returnvalue &= bitmask[number_of_bits]; + bitindex = sum - 32; + return returnvalue; +} + + /** + * Set the word we want to sync the header to. + * In Big-Endian byte order + */ + void set_syncword(int syncword0) + { + syncword = syncword0 & 0xFFFFFF3F; + single_ch_mode = ((syncword0 & 0x000000C0) == 0x000000C0); + } + /** + * Reads the exact number of bytes from the source + * input stream into a byte array. + * + * @param b The byte array to read the specified number + * of bytes into. + * @param offs The index in the array where the first byte + * read should be stored. + * @param len the number of bytes to read. + * + * @exception BitstreamException is thrown if the specified + * number of bytes could not be read from the stream. + */ + private int readFully(byte[] b, int offs, int len) + throws BitstreamException + { + int nRead = 0; + try + { + while (len > 0) + { + int bytesread = source.read(b, offs, len); + if (bytesread == -1) + { + while (len-->0) + { + b[offs++] = 0; + } + break; + //throw newBitstreamException(UNEXPECTED_EOF, new EOFException()); + } + nRead = nRead + bytesread; + offs += bytesread; + len -= bytesread; + } + } + catch (IOException ex) + { + throw newBitstreamException(STREAM_ERROR, ex); + } + return nRead; + } + + /** + * Similar to readFully, but doesn't throw exception when + * EOF is reached. + */ + private int readBytes(byte[] b, int offs, int len) + throws BitstreamException + { + int totalBytesRead = 0; + try + { + while (len > 0) + { + int bytesread = source.read(b, offs, len); + if (bytesread == -1) + { + break; + } + totalBytesRead += bytesread; + offs += bytesread; + len -= bytesread; + } + } + catch (IOException ex) + { + throw newBitstreamException(STREAM_ERROR, ex); + } + return totalBytesRead; + } +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/BitstreamErrors.java b/src/lwjgl/java/javazoom/jl/decoder/BitstreamErrors.java new file mode 100644 index 0000000..b5c3c93 --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/BitstreamErrors.java @@ -0,0 +1,72 @@ +/* + * 11/19/04 1.0 moved to LGPL. + * 11/17/04 INVALIDFRAME code added. javalayer@javazoom.net + * 12/12/99 Initial version. mdm@techie.com + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + +package javazoom.jl.decoder; + +/** + * This interface describes all error codes that can be thrown + * in BistreamExceptions. + * + * @see BitstreamException + * + * @author MDM 12/12/99 + * @since 0.0.6 + */ + +public interface BitstreamErrors extends JavaLayerErrors +{ + + /** + * An undetermined error occurred. + */ + public static final int UNKNOWN_ERROR = BITSTREAM_ERROR + 0; + + /** + * The header describes an unknown sample rate. + */ + public static final int UNKNOWN_SAMPLE_RATE = BITSTREAM_ERROR + 1; + + /** + * A problem occurred reading from the stream. + */ + public static final int STREAM_ERROR = BITSTREAM_ERROR + 2; + + /** + * The end of the stream was reached prematurely. + */ + public static final int UNEXPECTED_EOF = BITSTREAM_ERROR + 3; + + /** + * The end of the stream was reached. + */ + public static final int STREAM_EOF = BITSTREAM_ERROR + 4; + + /** + * Frame data are missing. + */ + public static final int INVALIDFRAME = BITSTREAM_ERROR + 5; + + /** + * + */ + public static final int BITSTREAM_LAST = 0x1ff; + +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/BitstreamException.java b/src/lwjgl/java/javazoom/jl/decoder/BitstreamException.java new file mode 100644 index 0000000..7aa0d6d --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/BitstreamException.java @@ -0,0 +1,71 @@ +/* + * 11/19/04 1.0 moved to LGPL. + * 12/12/99 Initial version. mdm@techie.com + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + +package javazoom.jl.decoder; + +/** + * Instances of BitstreamException are thrown + * when operations on a Bitstream fail. + *

+ * The exception provides details of the exception condition + * in two ways: + *

  1. + * as an error-code describing the nature of the error + *


  2. + * as the Throwable instance, if any, that was thrown + * indicating that an exceptional condition has occurred. + *

+ * + * @since 0.0.6 + * @author MDM 12/12/99 + */ + +public class BitstreamException extends JavaLayerException + implements BitstreamErrors +{ + private int errorcode = UNKNOWN_ERROR; + + public BitstreamException(String msg, Throwable t) + { + super(msg, t); + } + + public BitstreamException(int errorcode, Throwable t) + { + this(getErrorString(errorcode), t); + this.errorcode = errorcode; + } + + public int getErrorCode() + { + return errorcode; + } + + + public static String getErrorString(int errorcode) + { + // REVIEW: use resource bundle to map error codes + // to locale-sensitive strings. + + return "Bitstream errorcode "+Integer.toHexString(errorcode); + } + + +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/Control.java b/src/lwjgl/java/javazoom/jl/decoder/Control.java new file mode 100644 index 0000000..080ed52 --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/Control.java @@ -0,0 +1,57 @@ +/* + * 11/19/04 1.0 moved to LGPL. + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + +package javazoom.jl.decoder; + +/** + * Work in progress. + */ + +public interface Control +{ + + /** + * Starts playback of the media presented by this control. + */ + public void start(); + + /** + * Stops playback of the media presented by this control. + */ + public void stop(); + + public boolean isPlaying(); + + public void pause(); + + + public boolean isRandomAccess(); + + /** + * Retrieves the current position. + */ + public double getPosition(); + + /** + * + */ + public void setPosition(double d); + + +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/Crc16.java b/src/lwjgl/java/javazoom/jl/decoder/Crc16.java new file mode 100644 index 0000000..84760f2 --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/Crc16.java @@ -0,0 +1,70 @@ +/* + * 11/19/04 : 1.0 moved to LGPL. + * + * 02/12/99 : Java Conversion by E.B , javalayer@javazoom.net + * + * @(#) crc.h 1.5, last edit: 6/15/94 16:55:32 + * @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de) + * @(#) Berlin University of Technology + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ +package javazoom.jl.decoder; + +/** + * 16-Bit CRC checksum + */ +public final class Crc16 +{ + private static short polynomial=(short)0x8005; + private short crc; + + /** + * Dummy Constructor + */ + public Crc16() + { + crc = (short) 0xFFFF; + } + + /** + * Feed a bitstring to the CRC calculation (0 < length <= 32). + */ + public void add_bits (int bitstring, int length) + { + int bitmask = 1 << (length - 1); + do + if (((crc & 0x8000) == 0) ^ ((bitstring & bitmask) == 0 )) + { + crc <<= 1; + crc ^= polynomial; + } + else + crc <<= 1; + while ((bitmask >>>= 1) != 0); + } + + /** + * Return the calculated checksum. + * Erase it for next calls to add_bits(). + */ + public short checksum() + { + short sum = crc; + crc = (short) 0xFFFF; + return sum; + } +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/Decoder.java b/src/lwjgl/java/javazoom/jl/decoder/Decoder.java new file mode 100644 index 0000000..dcd893b --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/Decoder.java @@ -0,0 +1,356 @@ +/* + * 11/19/04 1.0 moved to LGPL. + * 01/12/99 Initial version. mdm@techie.com + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + +package javazoom.jl.decoder; + +/** + * The Decoder class encapsulates the details of + * decoding an MPEG audio frame. + * + * @author MDM + * @version 0.0.7 12/12/99 + * @since 0.0.5 + */ +public class Decoder implements DecoderErrors +{ + private static final Params DEFAULT_PARAMS = new Params(); + + /** + * The Bitstream from which the MPEG audio frames are read. + */ + //private Bitstream stream; + + /** + * The Obuffer instance that will receive the decoded + * PCM samples. + */ + private Obuffer output; + + /** + * Synthesis filter for the left channel. + */ + private SynthesisFilter filter1; + + /** + * Synthesis filter for the right channel. + */ + private SynthesisFilter filter2; + + /** + * The decoder used to decode layer III frames. + */ + private LayerIIIDecoder l3decoder; + private LayerIIDecoder l2decoder; + private LayerIDecoder l1decoder; + + private int outputFrequency; + private int outputChannels; + + private Equalizer equalizer = new Equalizer(); + + private Params params; + + private boolean initialized; + + + /** + * Creates a new Decoder instance with default + * parameters. + */ + + public Decoder() + { + this(null); + } + + /** + * Creates a new Decoder instance with default + * parameters. + * + * @param params The Params instance that describes + * the customizable aspects of the decoder. + */ + public Decoder(Params params0) + { + if (params0==null) + params0 = DEFAULT_PARAMS; + + params = params0; + + Equalizer eq = params.getInitialEqualizerSettings(); + if (eq!=null) + { + equalizer.setFrom(eq); + } + } + + public static Params getDefaultParams() throws CloneNotSupportedException + { + return (Params)DEFAULT_PARAMS.clone(); + } + + public void setEqualizer(Equalizer eq) + { + if (eq==null) + eq = Equalizer.PASS_THRU_EQ; + + equalizer.setFrom(eq); + + float[] factors = equalizer.getBandFactors(); + + if (filter1!=null) + filter1.setEQ(factors); + + if (filter2!=null) + filter2.setEQ(factors); + } + + /** + * Decodes one frame from an MPEG audio bitstream. + * + * @param header The header describing the frame to decode. + * @param bitstream The bitstream that provides the bits for te body of the frame. + * + * @return A SampleBuffer containing the decoded samples. + */ + public Obuffer decodeFrame(Header header, Bitstream stream) + throws DecoderException + { + if (!initialized) + { + initialize(header); + } + + int layer = header.layer(); + + output.clear_buffer(); + + FrameDecoder decoder = retrieveDecoder(header, stream, layer); + + decoder.decodeFrame(); + + output.write_buffer(1); + + return output; + } + + /** + * Changes the output buffer. This will take effect the next time + * decodeFrame() is called. + */ + public void setOutputBuffer(Obuffer out) + { + output = out; + } + + /** + * Retrieves the sample frequency of the PCM samples output + * by this decoder. This typically corresponds to the sample + * rate encoded in the MPEG audio stream. + * + * @param the sample rate (in Hz) of the samples written to the + * output buffer when decoding. + */ + public int getOutputFrequency() + { + return outputFrequency; + } + + /** + * Retrieves the number of channels of PCM samples output by + * this decoder. This usually corresponds to the number of + * channels in the MPEG audio stream, although it may differ. + * + * @return The number of output channels in the decoded samples: 1 + * for mono, or 2 for stereo. + * + */ + public int getOutputChannels() + { + return outputChannels; + } + + /** + * Retrieves the maximum number of samples that will be written to + * the output buffer when one frame is decoded. This can be used to + * help calculate the size of other buffers whose size is based upon + * the number of samples written to the output buffer. NB: this is + * an upper bound and fewer samples may actually be written, depending + * upon the sample rate and number of channels. + * + * @return The maximum number of samples that are written to the + * output buffer when decoding a single frame of MPEG audio. + */ + public int getOutputBlockSize() + { + return Obuffer.OBUFFERSIZE; + } + + + protected DecoderException newDecoderException(int errorcode) + { + return new DecoderException(errorcode, null); + } + + protected DecoderException newDecoderException(int errorcode, Throwable throwable) + { + return new DecoderException(errorcode, throwable); + } + + protected FrameDecoder retrieveDecoder(Header header, Bitstream stream, int layer) + throws DecoderException + { + FrameDecoder decoder = null; + + // REVIEW: allow channel output selection type + // (LEFT, RIGHT, BOTH, DOWNMIX) + switch (layer) + { + case 3: + if (l3decoder==null) + { + l3decoder = new LayerIIIDecoder(stream, + header, filter1, filter2, + output, OutputChannels.BOTH_CHANNELS); + } + + decoder = l3decoder; + break; + case 2: + if (l2decoder==null) + { + l2decoder = new LayerIIDecoder(); + l2decoder.create(stream, + header, filter1, filter2, + output, OutputChannels.BOTH_CHANNELS); + } + decoder = l2decoder; + break; + case 1: + if (l1decoder==null) + { + l1decoder = new LayerIDecoder(); + l1decoder.create(stream, + header, filter1, filter2, + output, OutputChannels.BOTH_CHANNELS); + } + decoder = l1decoder; + break; + } + + if (decoder==null) + { + throw newDecoderException(UNSUPPORTED_LAYER, null); + } + + return decoder; + } + + private void initialize(Header header) + throws DecoderException + { + + // REVIEW: allow customizable scale factor + float scalefactor = 32700.0f; + + int mode = header.mode(); + int layer = header.layer(); + int channels = mode==Header.SINGLE_CHANNEL ? 1 : 2; + + + // set up output buffer if not set up by client. + if (output==null) + output = new SampleBuffer(header.frequency(), channels); + + float[] factors = equalizer.getBandFactors(); + filter1 = new SynthesisFilter(0, scalefactor, factors); + + // REVIEW: allow mono output for stereo + if (channels==2) + filter2 = new SynthesisFilter(1, scalefactor, factors); + + outputChannels = channels; + outputFrequency = header.frequency(); + + initialized = true; + } + + /** + * The Params class presents the customizable + * aspects of the decoder. + *

+ * Instances of this class are not thread safe. + */ + public static class Params implements Cloneable + { + private OutputChannels outputChannels = OutputChannels.BOTH; + + private Equalizer equalizer = new Equalizer(); + + public Params() + { + } + + public Object clone() throws CloneNotSupportedException { + try + { + return super.clone(); + } + catch (CloneNotSupportedException ex) + { + throw new InternalError(this+": "+ex); + } + } + + public void setOutputChannels(OutputChannels out) + { + if (out==null) + throw new NullPointerException("out"); + + outputChannels = out; + } + + public OutputChannels getOutputChannels() + { + return outputChannels; + } + + /** + * Retrieves the equalizer settings that the decoder's equalizer + * will be initialized from. + *

+ * The Equalizer instance returned + * cannot be changed in real time to affect the + * decoder output as it is used only to initialize the decoders + * EQ settings. To affect the decoder's output in realtime, + * use the Equalizer returned from the getEqualizer() method on + * the decoder. + * + * @return The Equalizer used to initialize the + * EQ settings of the decoder. + */ + public Equalizer getInitialEqualizerSettings() + { + return equalizer; + } + + }; +} + diff --git a/src/lwjgl/java/javazoom/jl/decoder/DecoderErrors.java b/src/lwjgl/java/javazoom/jl/decoder/DecoderErrors.java new file mode 100644 index 0000000..4cbbc81 --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/DecoderErrors.java @@ -0,0 +1,45 @@ +/* + * 09/26/08 throw exception on subbband alloc error: Christopher G. Jennings (cjennings@acm.org) + * 11/19/04 1.0 moved to LGPL. + * 01/12/99 Initial version. mdm@techie.com + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + +package javazoom.jl.decoder; + +/** + * This interface provides constants describing the error + * codes used by the Decoder to indicate errors. + * + * @author MDM + */ +public interface DecoderErrors extends JavaLayerErrors +{ + + public static final int UNKNOWN_ERROR = DECODER_ERROR + 0; + + /** + * Layer not supported by the decoder. + */ + public static final int UNSUPPORTED_LAYER = DECODER_ERROR + 1; + + /** + * Illegal allocation in subband layer. Indicates a corrupt stream. + */ + public static final int ILLEGAL_SUBBAND_ALLOCATION = DECODER_ERROR + 2; + +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/DecoderException.java b/src/lwjgl/java/javazoom/jl/decoder/DecoderException.java new file mode 100644 index 0000000..ce15c3d --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/DecoderException.java @@ -0,0 +1,59 @@ +/* + * 11/19/04 1.0 moved to LGPL. + * 01/12/99 Initial version. mdm@techie.com + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + +package javazoom.jl.decoder; + +/** + * The DecoderException represents the class of + * errors that can occur when decoding MPEG audio. + * + * @author MDM + */ +public class DecoderException extends JavaLayerException + implements DecoderErrors +{ + private int errorcode = UNKNOWN_ERROR; + + public DecoderException(String msg, Throwable t) + { + super(msg, t); + } + + public DecoderException(int errorcode, Throwable t) + { + this(getErrorString(errorcode), t); + this.errorcode = errorcode; + } + + public int getErrorCode() + { + return errorcode; + } + + + public static String getErrorString(int errorcode) + { + // REVIEW: use resource file to map error codes + // to locale-sensitive strings. + + return "Decoder errorcode "+Integer.toHexString(errorcode); + } +} + diff --git a/src/lwjgl/java/javazoom/jl/decoder/Equalizer.java b/src/lwjgl/java/javazoom/jl/decoder/Equalizer.java new file mode 100644 index 0000000..9d41047 --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/Equalizer.java @@ -0,0 +1,227 @@ +/* + * 11/19/04 1.0 moved to LGPL. + * 12/12/99 Initial version. mdm@techie.com + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + + +package javazoom.jl.decoder; + +/** + * The Equalizer class can be used to specify + * equalization settings for the MPEG audio decoder. + *

+ * The equalizer consists of 32 band-pass filters. + * Each band of the equalizer can take on a fractional value between + * -1.0 and +1.0. + * At -1.0, the input signal is attenuated by 6dB, at +1.0 the signal is + * amplified by 6dB. + * + * @see Decoder + * + * @author MDM + */ +public final class Equalizer +{ + /** + * Equalizer setting to denote that a given band will not be + * present in the output signal. + */ + public static final float BAND_NOT_PRESENT = Float.NEGATIVE_INFINITY; + + public static final Equalizer PASS_THRU_EQ = new Equalizer(); + + private static final int BANDS = 32; + + private final float[] settings = new float[BANDS]; + + /** + * Creates a new Equalizer instance. + */ + public Equalizer() + { + } + +// private Equalizer(float b1, float b2, float b3, float b4, float b5, +// float b6, float b7, float b8, float b9, float b10, float b11, +// float b12, float b13, float b14, float b15, float b16, +// float b17, float b18, float b19, float b20); + + public Equalizer(float[] settings) + { + setFrom(settings); + } + + public Equalizer(EQFunction eq) + { + setFrom(eq); + } + + public void setFrom(float[] eq) + { + reset(); + int max = (eq.length > BANDS) ? BANDS : eq.length; + + for (int i=0; i=0) && (band=0) && (band 1.0f) + return 1.0f; + if (eq < -1.0f) + return -1.0f; + + return eq; + } + + /** + * Retrieves an array of floats whose values represent a + * scaling factor that can be applied to linear samples + * in each band to provide the equalization represented by + * this instance. + * + * @return an array of factors that can be applied to the + * subbands. + */ + float[] getBandFactors() + { + float[] factors = new float[BANDS]; + for (int i=0, maxCount=BANDS; i>> 19) & 1); + if (((headerstring >>> 20) & 1) == 0) // SZD: MPEG2.5 detection + if (h_version == MPEG2_LSF) + h_version = MPEG25_LSF; + else + throw stream.newBitstreamException(Bitstream.UNKNOWN_ERROR); + if ((h_sample_frequency = ((headerstring >>> 10) & 3)) == 3) + { + throw stream.newBitstreamException(Bitstream.UNKNOWN_ERROR); + } + } + h_layer = 4 - (headerstring >>> 17) & 3; + h_protection_bit = (headerstring >>> 16) & 1; + h_bitrate_index = (headerstring >>> 12) & 0xF; + h_padding_bit = (headerstring >>> 9) & 1; + h_mode = ((headerstring >>> 6) & 3); + h_mode_extension = (headerstring >>> 4) & 3; + if (h_mode == JOINT_STEREO) + h_intensity_stereo_bound = (h_mode_extension << 2) + 4; + else + h_intensity_stereo_bound = 0; // should never be used + if (((headerstring >>> 3) & 1) == 1) + h_copyright = true; + if (((headerstring >>> 2) & 1) == 1) + h_original = true; + // calculate number of subbands: + if (h_layer == 1) + h_number_of_subbands = 32; + else + { + channel_bitrate = h_bitrate_index; + // calculate bitrate per channel: + if (h_mode != SINGLE_CHANNEL) + if (channel_bitrate == 4) + channel_bitrate = 1; + else + channel_bitrate -= 4; + if ((channel_bitrate == 1) || (channel_bitrate == 2)) + if (h_sample_frequency == THIRTYTWO) + h_number_of_subbands = 12; + else + h_number_of_subbands = 8; + else if ((h_sample_frequency == FOURTYEIGHT) || ((channel_bitrate >= 3) && (channel_bitrate <= 5))) + h_number_of_subbands = 27; + else + h_number_of_subbands = 30; + } + if (h_intensity_stereo_bound > h_number_of_subbands) + h_intensity_stereo_bound = h_number_of_subbands; + // calculate framesize and nSlots + calculate_framesize(); + // read framedata: + int framesizeloaded = stream.read_frame_data(framesize); + if ((framesize >=0) && (framesizeloaded != framesize)) + { + // Data loaded does not match to expected framesize, + // it might be an ID3v1 TAG. (Fix 11/17/04). + throw stream.newBitstreamException(Bitstream.INVALIDFRAME); + } + if (stream.isSyncCurrentPosition(syncmode)) + { + if (syncmode == Bitstream.INITIAL_SYNC) + { + syncmode = Bitstream.STRICT_SYNC; + stream.set_syncword(headerstring & 0xFFF80CC0); + } + sync = true; + } + else + { + stream.unreadFrame(); + } + } + while (!sync); + stream.parse_frame(); + if (h_protection_bit == 0) + { + // frame contains a crc checksum + checksum = (short) stream.get_bits(16); + if (crc == null) + crc = new Crc16(); + crc.add_bits(headerstring, 16); + crcp[0] = crc; + } + else + crcp[0] = null; + if (h_sample_frequency == FOURTYFOUR_POINT_ONE) + { + /* + if (offset == null) + { + int max = max_number_of_frames(stream); + offset = new int[max]; + for(int i=0; i 0) && (cf == lf)) + { + offset[cf] = offset[cf-1] + h_padding_bit; + } + else + { + offset[0] = h_padding_bit; + } + */ + } + } + + /** + * Parse frame to extract optional VBR frame. + * + * @param firstframe + * @author E.B (javalayer@javazoom.net) + */ + void parseVBR(byte[] firstframe) throws BitstreamException + { + // Trying Xing header. + String xing = "Xing"; + byte tmp[] = new byte[4]; + int offset = 0; + // Compute "Xing" offset depending on MPEG version and channels. + if (h_version == MPEG1) + { + if (h_mode == SINGLE_CHANNEL) offset=21-4; + else offset=36-4; + } + else + { + if (h_mode == SINGLE_CHANNEL) offset=13-4; + else offset = 21-4; + } + try + { + System.arraycopy(firstframe, offset, tmp, 0, 4); + // Is "Xing" ? + if (xing.equals(new String(tmp))) + { + //Yes. + h_vbr = true; + h_vbr_frames = -1; + h_vbr_bytes = -1; + h_vbr_scale = -1; + h_vbr_toc = new byte[100]; + + int length = 4; + // Read flags. + byte flags[] = new byte[4]; + System.arraycopy(firstframe, offset + length, flags, 0, flags.length); + length += flags.length; + // Read number of frames (if available). + if ((flags[3] & (byte) (1 << 0)) != 0) + { + System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length); + h_vbr_frames = (tmp[0] << 24)&0xFF000000 | (tmp[1] << 16)&0x00FF0000 | (tmp[2] << 8)&0x0000FF00 | tmp[3]&0x000000FF; + length += 4; + } + // Read size (if available). + if ((flags[3] & (byte) (1 << 1)) != 0) + { + System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length); + h_vbr_bytes = (tmp[0] << 24)&0xFF000000 | (tmp[1] << 16)&0x00FF0000 | (tmp[2] << 8)&0x0000FF00 | tmp[3]&0x000000FF; + length += 4; + } + // Read TOC (if available). + if ((flags[3] & (byte) (1 << 2)) != 0) + { + System.arraycopy(firstframe, offset + length, h_vbr_toc, 0, h_vbr_toc.length); + length += h_vbr_toc.length; + } + // Read scale (if available). + if ((flags[3] & (byte) (1 << 3)) != 0) + { + System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length); + h_vbr_scale = (tmp[0] << 24)&0xFF000000 | (tmp[1] << 16)&0x00FF0000 | (tmp[2] << 8)&0x0000FF00 | tmp[3]&0x000000FF; + length += 4; + } + //System.out.println("VBR:"+xing+" Frames:"+ h_vbr_frames +" Size:"+h_vbr_bytes); + } + } + catch (ArrayIndexOutOfBoundsException e) + { + throw new BitstreamException("XingVBRHeader Corrupted",e); + } + + // Trying VBRI header. + String vbri = "VBRI"; + offset = 36-4; + try + { + System.arraycopy(firstframe, offset, tmp, 0, 4); + // Is "VBRI" ? + if (vbri.equals(new String(tmp))) + { + //Yes. + h_vbr = true; + h_vbr_frames = -1; + h_vbr_bytes = -1; + h_vbr_scale = -1; + h_vbr_toc = new byte[100]; + // Bytes. + int length = 4 + 6; + System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length); + h_vbr_bytes = (tmp[0] << 24)&0xFF000000 | (tmp[1] << 16)&0x00FF0000 | (tmp[2] << 8)&0x0000FF00 | tmp[3]&0x000000FF; + length += 4; + // Frames. + System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length); + h_vbr_frames = (tmp[0] << 24)&0xFF000000 | (tmp[1] << 16)&0x00FF0000 | (tmp[2] << 8)&0x0000FF00 | tmp[3]&0x000000FF; + length += 4; + //System.out.println("VBR:"+vbri+" Frames:"+ h_vbr_frames +" Size:"+h_vbr_bytes); + // TOC + // TODO + } + } + catch (ArrayIndexOutOfBoundsException e) + { + throw new BitstreamException("VBRIVBRHeader Corrupted",e); + } + } + + // Functions to query header contents: + /** + * Returns version. + */ + public int version() { return h_version; } + + /** + * Returns Layer ID. + */ + public int layer() { return h_layer; } + + /** + * Returns bitrate index. + */ + public int bitrate_index() { return h_bitrate_index; } + + /** + * Returns Sample Frequency. + */ + public int sample_frequency() { return h_sample_frequency; } + + /** + * Returns Frequency. + */ + public int frequency() {return frequencies[h_version][h_sample_frequency];} + + /** + * Returns Mode. + */ + public int mode() { return h_mode; } + + /** + * Returns Protection bit. + */ + public boolean checksums() + { + if (h_protection_bit == 0) return true; + else return false; + } + + /** + * Returns Copyright. + */ + public boolean copyright() { return h_copyright; } + + /** + * Returns Original. + */ + public boolean original() { return h_original; } + + /** + * Return VBR. + * + * @return true if VBR header is found + */ + public boolean vbr() { return h_vbr; } + + /** + * Return VBR scale. + * + * @return scale of -1 if not available + */ + public int vbr_scale() { return h_vbr_scale; } + + /** + * Return VBR TOC. + * + * @return vbr toc ot null if not available + */ + public byte[] vbr_toc() { return h_vbr_toc; } + + /** + * Returns Checksum flag. + * Compares computed checksum with stream checksum. + */ + public boolean checksum_ok () { return (checksum == crc.checksum()); } + + // Seeking and layer III stuff + /** + * Returns Layer III Padding bit. + */ + public boolean padding() + { + if (h_padding_bit == 0) return false; + else return true; + } + + /** + * Returns Slots. + */ + public int slots() { return nSlots; } + + /** + * Returns Mode Extension. + */ + public int mode_extension() { return h_mode_extension; } + + // E.B -> private to public + public static final int bitrates[][][] = { + {{0 /*free format*/, 32000, 48000, 56000, 64000, 80000, 96000, + 112000, 128000, 144000, 160000, 176000, 192000 ,224000, 256000, 0}, + {0 /*free format*/, 8000, 16000, 24000, 32000, 40000, 48000, + 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 0}, + {0 /*free format*/, 8000, 16000, 24000, 32000, 40000, 48000, + 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 0}}, + + {{0 /*free format*/, 32000, 64000, 96000, 128000, 160000, 192000, + 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000, 0}, + {0 /*free format*/, 32000, 48000, 56000, 64000, 80000, 96000, + 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000, 0}, + {0 /*free format*/, 32000, 40000, 48000, 56000, 64000, 80000, + 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 0}}, + // SZD: MPEG2.5 + {{0 /*free format*/, 32000, 48000, 56000, 64000, 80000, 96000, + 112000, 128000, 144000, 160000, 176000, 192000 ,224000, 256000, 0}, + {0 /*free format*/, 8000, 16000, 24000, 32000, 40000, 48000, + 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 0}, + {0 /*free format*/, 8000, 16000, 24000, 32000, 40000, 48000, + 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 0}}, + + }; + + // E.B -> private to public + /** + * Calculate Frame size. + * + * Calculates framesize in bytes excluding header size. + */ + public int calculate_framesize() + { + + if (h_layer == 1) + { + framesize = (12 * bitrates[h_version][0][h_bitrate_index]) / + frequencies[h_version][h_sample_frequency]; + if (h_padding_bit != 0 ) framesize++; + framesize <<= 2; // one slot is 4 bytes long + nSlots = 0; + } + else + { + framesize = (144 * bitrates[h_version][h_layer - 1][h_bitrate_index]) / + frequencies[h_version][h_sample_frequency]; + if (h_version == MPEG2_LSF || h_version == MPEG25_LSF) framesize >>= 1; // SZD + if (h_padding_bit != 0) framesize++; + // Layer III slots + if (h_layer == 3) + { + if (h_version == MPEG1) + { + nSlots = framesize - ((h_mode == SINGLE_CHANNEL) ? 17 : 32) // side info size + - ((h_protection_bit!=0) ? 0 : 2) // CRC size + - 4; // header size + } + else + { // MPEG-2 LSF, SZD: MPEG-2.5 LSF + nSlots = framesize - ((h_mode == SINGLE_CHANNEL) ? 9 : 17) // side info size + - ((h_protection_bit!=0) ? 0 : 2) // CRC size + - 4; // header size + } + } + else + { + nSlots = 0; + } + } + framesize -= 4; // subtract header size + return framesize; + } + + /** + * Returns the maximum number of frames in the stream. + * + * @param streamsize + * @return number of frames + */ + public int max_number_of_frames(int streamsize) // E.B + { + if (h_vbr == true) return h_vbr_frames; + else + { + if ((framesize + 4 - h_padding_bit) == 0) return 0; + else return(streamsize / (framesize + 4 - h_padding_bit)); + } + } + + /** + * Returns the maximum number of frames in the stream. + * + * @param streamsize + * @return number of frames + */ + public int min_number_of_frames(int streamsize) // E.B + { + if (h_vbr == true) return h_vbr_frames; + else + { + if ((framesize + 5 - h_padding_bit) == 0) return 0; + else return(streamsize / (framesize + 5 - h_padding_bit)); + } + } + + + /** + * Returns ms/frame. + * + * @return milliseconds per frame + */ + public float ms_per_frame() // E.B + { + if (h_vbr == true) + { + double tpf = h_vbr_time_per_frame[layer()] / frequency(); + if ((h_version == MPEG2_LSF) || (h_version == MPEG25_LSF)) tpf /= 2; + return ((float) (tpf * 1000)); + } + else + { + float ms_per_frame_array[][] = {{8.707483f, 8.0f, 12.0f}, + {26.12245f, 24.0f, 36.0f}, + {26.12245f, 24.0f, 36.0f}}; + return(ms_per_frame_array[h_layer-1][h_sample_frequency]); + } + } + + /** + * Returns total ms. + * + * @param streamsize + * @return total milliseconds + */ + public float total_ms(int streamsize) // E.B + { + return(max_number_of_frames(streamsize) * ms_per_frame()); + } + + /** + * Returns synchronized header. + */ + public int getSyncHeader() // E.B + { + return _headerstring; + } + + // functions which return header informations as strings: + /** + * Return Layer version. + */ + public String layer_string() + { + switch (h_layer) + { + case 1: + return "I"; + case 2: + return "II"; + case 3: + return "III"; + } + return null; + } + + // E.B -> private to public + public static final String bitrate_str[][][] = { + {{"free format", "32 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", + "80 kbit/s", "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", + "160 kbit/s", "176 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s", + "forbidden"}, + {"free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s", + "40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s", + "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s", + "forbidden"}, + {"free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s", + "40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s", + "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s", + "forbidden"}}, + + {{"free format", "32 kbit/s", "64 kbit/s", "96 kbit/s", "128 kbit/s", + "160 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s", "288 kbit/s", + "320 kbit/s", "352 kbit/s", "384 kbit/s", "416 kbit/s", "448 kbit/s", + "forbidden"}, + {"free format", "32 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", + "80 kbit/s", "96 kbit/s", "112 kbit/s", "128 kbit/s", "160 kbit/s", + "192 kbit/s", "224 kbit/s", "256 kbit/s", "320 kbit/s", "384 kbit/s", + "forbidden"}, + {"free format", "32 kbit/s", "40 kbit/s", "48 kbit/s", "56 kbit/s", + "64 kbit/s", "80 kbit/s" , "96 kbit/s", "112 kbit/s", "128 kbit/s", + "160 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s", "320 kbit/s", + "forbidden"}}, + // SZD: MPEG2.5 + {{"free format", "32 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", + "80 kbit/s", "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", + "160 kbit/s", "176 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s", + "forbidden"}, + {"free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s", + "40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s", + "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s", + "forbidden"}, + {"free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s", + "40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s", + "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s", + "forbidden"}}, + }; + + /** + * Return Bitrate. + * + * @return bitrate in bps + */ + public String bitrate_string() + { + if (h_vbr == true) + { + return Integer.toString(bitrate()/1000)+" kb/s"; + } + else return bitrate_str[h_version][h_layer - 1][h_bitrate_index]; + } + + /** + * Return Bitrate. + * + * @return bitrate in bps and average bitrate for VBR header + */ + public int bitrate() + { + if (h_vbr == true) + { + return ((int) ((h_vbr_bytes * 8) / (ms_per_frame() * h_vbr_frames)))*1000; + } + else return bitrates[h_version][h_layer - 1][h_bitrate_index]; + } + + /** + * Return Instant Bitrate. + * Bitrate for VBR is not constant. + * + * @return bitrate in bps + */ + public int bitrate_instant() + { + return bitrates[h_version][h_layer - 1][h_bitrate_index]; + } + + /** + * Returns Frequency + * + * @return frequency string in kHz + */ + public String sample_frequency_string() + { + switch (h_sample_frequency) + { + case THIRTYTWO: + if (h_version == MPEG1) + return "32 kHz"; + else if (h_version == MPEG2_LSF) + return "16 kHz"; + else // SZD + return "8 kHz"; + case FOURTYFOUR_POINT_ONE: + if (h_version == MPEG1) + return "44.1 kHz"; + else if (h_version == MPEG2_LSF) + return "22.05 kHz"; + else // SZD + return "11.025 kHz"; + case FOURTYEIGHT: + if (h_version == MPEG1) + return "48 kHz"; + else if (h_version == MPEG2_LSF) + return "24 kHz"; + else // SZD + return "12 kHz"; + } + return(null); + } + + /** + * Returns Mode. + */ + public String mode_string() + { + switch (h_mode) + { + case STEREO: + return "Stereo"; + case JOINT_STEREO: + return "Joint stereo"; + case DUAL_CHANNEL: + return "Dual channel"; + case SINGLE_CHANNEL: + return "Single channel"; + } + return null; + } + + /** + * Returns Version. + * + * @return MPEG-1 or MPEG-2 LSF or MPEG-2.5 LSF + */ + public String version_string() + { + switch (h_version) + { + case MPEG1: + return "MPEG-1"; + case MPEG2_LSF: + return "MPEG-2 LSF"; + case MPEG25_LSF: // SZD + return "MPEG-2.5 LSF"; + } + return(null); + } + + /** + * Returns the number of subbands in the current frame. + * + * @return number of subbands + */ + public int number_of_subbands() {return h_number_of_subbands;} + + /** + * Returns Intensity Stereo. + * (Layer II joint stereo only). + * Returns the number of subbands which are in stereo mode, + * subbands above that limit are in intensity stereo mode. + * + * @return intensity + */ + public int intensity_stereo_bound() {return h_intensity_stereo_bound;} +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/InputStreamSource.java b/src/lwjgl/java/javazoom/jl/decoder/InputStreamSource.java new file mode 100644 index 0000000..5c62947 --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/InputStreamSource.java @@ -0,0 +1,80 @@ +/* + * 11/19/04 1.0 moved to LGPL. + * 12/12/99 Initial version. mdm@techie.com + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + +package javazoom.jl.decoder; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Work In Progress. + * + * An instance of InputStreamSource implements a + * Source that provides data from an InputStream + * . Seeking functionality is not supported. + * + * @author MDM + */ +public class InputStreamSource implements Source +{ + private final InputStream in; + + public InputStreamSource(InputStream in) + { + if (in==null) + throw new NullPointerException("in"); + + this.in = in; + } + + public int read(byte[] b, int offs, int len) + throws IOException + { + int read = in.read(b, offs, len); + return read; + } + + public boolean willReadBlock() + { + return true; + //boolean block = (in.available()==0); + //return block; + } + + public boolean isSeekable() + { + return false; + } + + public long tell() + { + return -1; + } + + public long seek(long to) + { + return -1; + } + + public long length() + { + return -1; + } +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/JavaLayerError.java b/src/lwjgl/java/javazoom/jl/decoder/JavaLayerError.java new file mode 100644 index 0000000..d9910bc --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/JavaLayerError.java @@ -0,0 +1,31 @@ +/* + * 11/19/04 1.0 moved to LGPL. + * 12/12/99 Initial version. mdm@techie.com + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + +package javazoom.jl.decoder; + +/** + * Work in progress. + * + * API usage errors may be handled by throwing an instance of this + * class, as per JMF 2.0. + */ +public class JavaLayerError extends Error +{ +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/JavaLayerErrors.java b/src/lwjgl/java/javazoom/jl/decoder/JavaLayerErrors.java new file mode 100644 index 0000000..9050610 --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/JavaLayerErrors.java @@ -0,0 +1,40 @@ +/* + * 11/19/04 1.0 moved to LGPL. + * 12/12/99 Initial version. mdm@techie.com + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + +package javazoom.jl.decoder; + +/** + * Exception error codes for components of the JavaLayer API. + */ +public interface JavaLayerErrors +{ + /** + * The first bitstream error code. See the {@link DecoderErrors DecoderErrors} + * interface for other bitstream error codes. + */ + public static final int BITSTREAM_ERROR = 0x100; + + /** + * The first decoder error code. See the {@link DecoderErrors DecoderErrors} + * interface for other decoder error codes. + */ + public static final int DECODER_ERROR = 0x200; + +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/JavaLayerException.java b/src/lwjgl/java/javazoom/jl/decoder/JavaLayerException.java new file mode 100644 index 0000000..e432a68 --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/JavaLayerException.java @@ -0,0 +1,78 @@ +/* + * 11/19/04 1.0 moved to LGPL. + * 12/12/99 Initial version. mdm@techie.com + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + +package javazoom.jl.decoder; + +import java.io.PrintStream; + + +/** + * The JavaLayerException is the base class for all API-level + * exceptions thrown by JavaLayer. To facilitate conversion and + * common handling of exceptions from other domains, the class + * can delegate some functionality to a contained Throwable instance. + *

+ * + * @author MDM + */ +public class JavaLayerException extends Exception +{ + + private Throwable exception; + + + public JavaLayerException() + { + } + + public JavaLayerException(String msg) + { + super(msg); + } + + public JavaLayerException(String msg, Throwable t) + { + super(msg); + exception = t; + } + + public Throwable getException() + { + return exception; + } + + + public void printStackTrace() + { + printStackTrace(System.err); + } + + public void printStackTrace(PrintStream ps) + { + if (this.exception==null) + { + super.printStackTrace(ps); + } + else + { + exception.printStackTrace(); + } + } +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/JavaLayerHook.java b/src/lwjgl/java/javazoom/jl/decoder/JavaLayerHook.java new file mode 100644 index 0000000..3520594 --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/JavaLayerHook.java @@ -0,0 +1,36 @@ +/* + * 11/19/04 1.0 moved to LGPL. + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + +package javazoom.jl.decoder; + +import java.io.InputStream; + +/** + * The JavaLayerHooks class allows developers to change + * the way the JavaLayer library uses Resources. + */ + +public interface JavaLayerHook +{ + /** + * Retrieves the named resource. This allows resources to be + * obtained without specifying how they are retrieved. + */ + public InputStream getResourceAsStream(String name); +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/JavaLayerUtils.java b/src/lwjgl/java/javazoom/jl/decoder/JavaLayerUtils.java new file mode 100644 index 0000000..5cfbd16 --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/JavaLayerUtils.java @@ -0,0 +1,208 @@ +/* + * 11/19/04 1.0 moved to LGPL. + * 12/12/99 Initial version. mdm@techie.com + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + +package javazoom.jl.decoder; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InvalidClassException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.lang.reflect.Array; + +/** + * The JavaLayerUtils class is not strictly part of the JavaLayer API. + * It serves to provide useful methods and system-wide hooks. + * + * @author MDM + */ +public class JavaLayerUtils +{ + private static JavaLayerHook hook = null; + + /** + * Deserializes the object contained in the given input stream. + * + * @param in The input stream to deserialize an object from. + * @param cls The expected class of the deserialized object. + */ + public static Object deserialize(InputStream in, Class cls) + throws IOException + { + if (cls==null) + throw new NullPointerException("cls"); + + Object obj = deserialize(in, cls); + if (!cls.isInstance(obj)) + { + throw new InvalidObjectException("type of deserialized instance not of required class."); + } + + return obj; + } + + /** + * Deserializes an object from the given InputStream. + * The deserialization is delegated to an + * ObjectInputStream instance. + * + * @param in The InputStream to deserialize an object + * from. + * + * @return The object deserialized from the stream. + * @exception IOException is thrown if there was a problem reading + * the underlying stream, or an object could not be deserialized + * from the stream. + * + * @see java.io.ObjectInputStream + */ + public static Object deserialize(InputStream in) + throws IOException + { + if (in==null) + throw new NullPointerException("in"); + + ObjectInputStream objIn = new ObjectInputStream(in); + + Object obj; + + try + { + obj = objIn.readObject(); + } + catch (ClassNotFoundException ex) + { + throw new InvalidClassException(ex.toString()); + } + + return obj; + } + + /** + * Deserializes an array from a given InputStream. + * + * @param in The InputStream to + * deserialize an object from. + * + * @param elemType The class denoting the type of the array + * elements. + * @param length The expected length of the array, or -1 if + * any length is expected. + */ + public static Object deserializeArray(InputStream in, Class elemType, int length) + throws IOException + { + if (elemType==null) + throw new NullPointerException("elemType"); + + if (length<-1) + throw new IllegalArgumentException("length"); + + Object obj = deserialize(in); + + Class cls = obj.getClass(); + + + if (!cls.isArray()) + throw new InvalidObjectException("object is not an array"); + + Class arrayElemType = cls.getComponentType(); + if (arrayElemType!=elemType) + throw new InvalidObjectException("unexpected array component type"); + + if (length != -1) + { + int arrayLength = Array.getLength(obj); + if (arrayLength!=length) + throw new InvalidObjectException("array length mismatch"); + } + + return obj; + } + + public static Object deserializeArrayResource(String name, Class elemType, int length) + throws IOException + { + InputStream str = getResourceAsStream(name); + if (str==null) + throw new IOException("unable to load resource '"+name+"'"); + + Object obj = deserializeArray(str, elemType, length); + + return obj; + } + + public static void serialize(OutputStream out, Object obj) + throws IOException + { + if (out==null) + throw new NullPointerException("out"); + + if (obj==null) + throw new NullPointerException("obj"); + + ObjectOutputStream objOut = new ObjectOutputStream(out); + objOut.writeObject(obj); + + } + + /** + * Sets the system-wide JavaLayer hook. + */ + public static synchronized void setHook(JavaLayerHook hook0) + { + hook = hook0; + } + + public static synchronized JavaLayerHook getHook() + { + return hook; + } + + /** + * Retrieves an InputStream for a named resource. + * + * @param name The name of the resource. This must be a simple + * name, and not a qualified package name. + * + * @return The InputStream for the named resource, or null if + * the resource has not been found. If a hook has been + * provided, its getResourceAsStream() method is called + * to retrieve the resource. + */ + public static synchronized InputStream getResourceAsStream(String name) + { + InputStream is = null; + + if (hook!=null) + { + is = hook.getResourceAsStream(name); + } + else + { + Class cls = JavaLayerUtils.class; + is = cls.getResourceAsStream(name); + } + + return is; + } +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/LayerIDecoder.java b/src/lwjgl/java/javazoom/jl/decoder/LayerIDecoder.java new file mode 100644 index 0000000..5e3232c --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/LayerIDecoder.java @@ -0,0 +1,448 @@ +/* + * 09/26/08 throw exception on subbband alloc error: Christopher G. Jennings (cjennings@acm.org) + * + * 11/19/04 1.0 moved to LGPL. + * + * 12/12/99 Initial version. Adapted from javalayer.java + * and Subband*.java. mdm@techie.com + * + * 02/28/99 Initial version : javalayer.java by E.B + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + +package javazoom.jl.decoder; + +/** + * Implements decoding of MPEG Audio Layer I frames. + */ +class LayerIDecoder implements FrameDecoder +{ + protected Bitstream stream; + protected Header header; + protected SynthesisFilter filter1, filter2; + protected Obuffer buffer; + protected int which_channels; + protected int mode; + + protected int num_subbands; + protected Subband[] subbands; + protected Crc16 crc = null; // new Crc16[1] to enable CRC checking. + + public LayerIDecoder() + { + crc = new Crc16(); + } + + public void create(Bitstream stream0, Header header0, + SynthesisFilter filtera, SynthesisFilter filterb, + Obuffer buffer0, int which_ch0) + { + stream = stream0; + header = header0; + filter1 = filtera; + filter2 = filterb; + buffer = buffer0; + which_channels = which_ch0; + + } + + public void decodeFrame() throws DecoderException + { + + num_subbands = header.number_of_subbands(); + subbands = new Subband[32]; + mode = header.mode(); + + createSubbands(); + + readAllocation(); + readScaleFactorSelection(); + + if ((crc != null) || header.checksum_ok()) + { + readScaleFactors(); + + readSampleData(); + } + + } + + protected void createSubbands() + { + int i; + if (mode == Header.SINGLE_CHANNEL) + for (i = 0; i < num_subbands; ++i) + subbands[i] = new SubbandLayer1(i); + else if (mode == Header.JOINT_STEREO) + { + for (i = 0; i < header.intensity_stereo_bound(); ++i) + subbands[i] = new SubbandLayer1Stereo(i); + for (; i < num_subbands; ++i) + subbands[i] = new SubbandLayer1IntensityStereo(i); + } + else + { + for (i = 0; i < num_subbands; ++i) + subbands[i] = new SubbandLayer1Stereo(i); + } + } + + protected void readAllocation() throws DecoderException + { + // start to read audio data: + for (int i = 0; i < num_subbands; ++i) + subbands[i].read_allocation(stream, header, crc); + + } + + protected void readScaleFactorSelection() + { + // scale factor selection not present for layer I. + } + + protected void readScaleFactors() + { + for (int i = 0; i < num_subbands; ++i) + subbands[i].read_scalefactor(stream, header); + } + + protected void readSampleData() + { + boolean read_ready = false; + boolean write_ready = false; + int mode = header.mode(); + int i; + do + { + for (i = 0; i < num_subbands; ++i) + read_ready = subbands[i].read_sampledata(stream); + do + { + for (i = 0; i < num_subbands; ++i) + write_ready = subbands[i].put_next_sample(which_channels,filter1, filter2); + + filter1.calculate_pcm_samples(buffer); + if ((which_channels == OutputChannels.BOTH_CHANNELS) && (mode != Header.SINGLE_CHANNEL)) + filter2.calculate_pcm_samples(buffer); + } while (!write_ready); + } while (!read_ready); + + } + + /** + * Abstract base class for subband classes of layer I and II + */ + abstract static class Subband + { + /* + * Changes from version 1.1 to 1.2: + * - array size increased by one, although a scalefactor with index 63 + * is illegal (to prevent segmentation faults) + */ + // Scalefactors for layer I and II, Annex 3-B.1 in ISO/IEC DIS 11172: + public static final float scalefactors[] = + { + 2.00000000000000f, 1.58740105196820f, 1.25992104989487f, 1.00000000000000f, + 0.79370052598410f, 0.62996052494744f, 0.50000000000000f, 0.39685026299205f, + 0.31498026247372f, 0.25000000000000f, 0.19842513149602f, 0.15749013123686f, + 0.12500000000000f, 0.09921256574801f, 0.07874506561843f, 0.06250000000000f, + 0.04960628287401f, 0.03937253280921f, 0.03125000000000f, 0.02480314143700f, + 0.01968626640461f, 0.01562500000000f, 0.01240157071850f, 0.00984313320230f, + 0.00781250000000f, 0.00620078535925f, 0.00492156660115f, 0.00390625000000f, + 0.00310039267963f, 0.00246078330058f, 0.00195312500000f, 0.00155019633981f, + 0.00123039165029f, 0.00097656250000f, 0.00077509816991f, 0.00061519582514f, + 0.00048828125000f, 0.00038754908495f, 0.00030759791257f, 0.00024414062500f, + 0.00019377454248f, 0.00015379895629f, 0.00012207031250f, 0.00009688727124f, + 0.00007689947814f, 0.00006103515625f, 0.00004844363562f, 0.00003844973907f, + 0.00003051757813f, 0.00002422181781f, 0.00001922486954f, 0.00001525878906f, + 0.00001211090890f, 0.00000961243477f, 0.00000762939453f, 0.00000605545445f, + 0.00000480621738f, 0.00000381469727f, 0.00000302772723f, 0.00000240310869f, + 0.00000190734863f, 0.00000151386361f, 0.00000120155435f, 0.00000000000000f /* illegal scalefactor */ + }; + + public abstract void read_allocation (Bitstream stream, Header header, Crc16 crc) throws DecoderException; + public abstract void read_scalefactor (Bitstream stream, Header header); + public abstract boolean read_sampledata (Bitstream stream); + public abstract boolean put_next_sample (int channels, SynthesisFilter filter1, SynthesisFilter filter2); + }; + + /** + * Class for layer I subbands in single channel mode. + * Used for single channel mode + * and in derived class for intensity stereo mode + */ + static class SubbandLayer1 extends Subband + { + + // Factors and offsets for sample re-quantization + public static final float table_factor[] = { + 0.0f, (1.0f/2.0f) * (4.0f/3.0f), (1.0f/4.0f) * (8.0f/7.0f), (1.0f/8.0f) * (16.0f/15.0f), + (1.0f/16.0f) * (32.0f/31.0f), (1.0f/32.0f) * (64.0f/63.0f), (1.0f/64.0f) * (128.0f/127.0f), + (1.0f/128.0f) * (256.0f/255.0f), (1.0f/256.0f) * (512.0f/511.0f), + (1.0f/512.0f) * (1024.0f/1023.0f), (1.0f/1024.0f) * (2048.0f/2047.0f), + (1.0f/2048.0f) * (4096.0f/4095.0f), (1.0f/4096.0f) * (8192.0f/8191.0f), + (1.0f/8192.0f) * (16384.0f/16383.0f), (1.0f/16384.0f) * (32768.0f/32767.0f) + }; + + public static final float table_offset[] = { + 0.0f, ((1.0f/2.0f)-1.0f) * (4.0f/3.0f), ((1.0f/4.0f)-1.0f) * (8.0f/7.0f), ((1.0f/8.0f)-1.0f) * (16.0f/15.0f), + ((1.0f/16.0f)-1.0f) * (32.0f/31.0f), ((1.0f/32.0f)-1.0f) * (64.0f/63.0f), ((1.0f/64.0f)-1.0f) * (128.0f/127.0f), + ((1.0f/128.0f)-1.0f) * (256.0f/255.0f), ((1.0f/256.0f)-1.0f) * (512.0f/511.0f), + ((1.0f/512.0f)-1.0f) * (1024.0f/1023.0f), ((1.0f/1024.0f)-1.0f) * (2048.0f/2047.0f), + ((1.0f/2048.0f)-1.0f) * (4096.0f/4095.0f), ((1.0f/4096.0f)-1.0f) * (8192.0f/8191.0f), + ((1.0f/8192.0f)-1.0f) * (16384.0f/16383.0f), ((1.0f/16384.0f)-1.0f) * (32768.0f/32767.0f) + }; + + protected int subbandnumber; + protected int samplenumber; + protected int allocation; + protected float scalefactor; + protected int samplelength; + protected float sample; + protected float factor, offset; + + /** + * Constructor. + */ + public SubbandLayer1(int subbandnumber) + { + this.subbandnumber = subbandnumber; + samplenumber = 0; + } + + /** + * + */ + public void read_allocation(Bitstream stream, Header header, Crc16 crc) throws DecoderException + { + if ((allocation = stream.get_bits (4)) == 15) + { + // CGJ: catch this condition and throw appropriate exception + throw new DecoderException(DecoderErrors.ILLEGAL_SUBBAND_ALLOCATION, null); + // cerr << "WARNING: stream contains an illegal allocation!\n"; + // MPEG-stream is corrupted! + } + + if (crc != null) crc.add_bits (allocation, 4); + if (allocation != 0) + { + samplelength = allocation + 1; + factor = table_factor[allocation]; + offset = table_offset[allocation]; + } + } + + /** + * + */ + public void read_scalefactor(Bitstream stream, Header header) + { + if (allocation != 0) scalefactor = scalefactors[stream.get_bits(6)]; + } + + /** + * + */ + public boolean read_sampledata(Bitstream stream) + { + if (allocation != 0) + { + sample = (float) (stream.get_bits(samplelength)); + } + if (++samplenumber == 12) + { + samplenumber = 0; + return true; + } + return false; + } + + /** + * + */ + public boolean put_next_sample(int channels, SynthesisFilter filter1, SynthesisFilter filter2) + { + if ((allocation !=0) && (channels != OutputChannels.RIGHT_CHANNEL)) + { + float scaled_sample = (sample * factor + offset) * scalefactor; + filter1.input_sample (scaled_sample, subbandnumber); + } + return true; + } + }; + + /** + * Class for layer I subbands in joint stereo mode. + */ + static class SubbandLayer1IntensityStereo extends SubbandLayer1 + { + protected float channel2_scalefactor; + + /** + * Constructor + */ + public SubbandLayer1IntensityStereo(int subbandnumber) + { + super(subbandnumber); + } + + /** + * + */ + public void read_allocation(Bitstream stream, Header header, Crc16 crc) throws DecoderException + { + super.read_allocation (stream, header, crc); + } + + /** + * + */ + public void read_scalefactor (Bitstream stream, Header header) + { + if (allocation != 0) + { + scalefactor = scalefactors[stream.get_bits(6)]; + channel2_scalefactor = scalefactors[stream.get_bits(6)]; + } + } + + /** + * + */ + public boolean read_sampledata(Bitstream stream) + { + return super.read_sampledata (stream); + } + + /** + * + */ + public boolean put_next_sample (int channels, SynthesisFilter filter1, SynthesisFilter filter2) + { + if (allocation !=0 ) + { + sample = sample * factor + offset; // re-quantization + if (channels == OutputChannels.BOTH_CHANNELS) + { + float sample1 = sample * scalefactor, + sample2 = sample * channel2_scalefactor; + filter1.input_sample(sample1, subbandnumber); + filter2.input_sample(sample2, subbandnumber); + } + else if (channels == OutputChannels.LEFT_CHANNEL) + { + float sample1 = sample * scalefactor; + filter1.input_sample(sample1, subbandnumber); + } + else + { + float sample2 = sample * channel2_scalefactor; + filter1.input_sample(sample2, subbandnumber); + } + } + return true; + } + }; + + /** + * Class for layer I subbands in stereo mode. + */ + static class SubbandLayer1Stereo extends SubbandLayer1 + { + protected int channel2_allocation; + protected float channel2_scalefactor; + protected int channel2_samplelength; + protected float channel2_sample; + protected float channel2_factor, channel2_offset; + + + /** + * Constructor + */ + public SubbandLayer1Stereo(int subbandnumber) + { + super(subbandnumber); + } + + /** + * + */ + public void read_allocation (Bitstream stream, Header header, Crc16 crc) throws DecoderException + { + allocation = stream.get_bits(4); + channel2_allocation = stream.get_bits(4); + if (crc != null) + { + crc.add_bits (allocation, 4); + crc.add_bits (channel2_allocation, 4); + } + if (allocation != 0) + { + samplelength = allocation + 1; + factor = table_factor[allocation]; + offset = table_offset[allocation]; + } + if (channel2_allocation != 0) + { + channel2_samplelength = channel2_allocation + 1; + channel2_factor = table_factor[channel2_allocation]; + channel2_offset = table_offset[channel2_allocation]; + } + } + + /** + * + */ + public void read_scalefactor(Bitstream stream, Header header) + { + if (allocation != 0) scalefactor = scalefactors[stream.get_bits(6)]; + if (channel2_allocation != 0) channel2_scalefactor = scalefactors[stream.get_bits(6)]; + } + + /** + * + */ + public boolean read_sampledata (Bitstream stream) + { + boolean returnvalue = super.read_sampledata(stream); + if (channel2_allocation != 0) + { + channel2_sample = (float) (stream.get_bits(channel2_samplelength)); + } + return(returnvalue); + } + + /** + * + */ + public boolean put_next_sample(int channels, SynthesisFilter filter1, SynthesisFilter filter2) + { + super.put_next_sample (channels, filter1, filter2); + if ((channel2_allocation != 0) && (channels != OutputChannels.LEFT_CHANNEL)) + { + float sample2 = (channel2_sample * channel2_factor + channel2_offset) * + channel2_scalefactor; + if (channels == OutputChannels.BOTH_CHANNELS) + filter2.input_sample (sample2, subbandnumber); + else + filter1.input_sample (sample2, subbandnumber); + } + return true; + } + }; + +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/LayerIIDecoder.java b/src/lwjgl/java/javazoom/jl/decoder/LayerIIDecoder.java new file mode 100644 index 0000000..7265b1f --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/LayerIIDecoder.java @@ -0,0 +1,1064 @@ +/* + * 11/19/04 1.0 moved to LGPL. + * + * 29/05/01 Michael Scheerer, Fixed some C++ to Java porting bugs. + * + * 16/07/01 Michael Scheerer, Catched a bug in method + * read_sampledata, which causes an outOfIndexException. + * + * 12/12/99 Initial version. Adapted from javalayer.java + * and Subband*.java. mdm@techie.com + * + * 02/28/99 Initial version : javalayer.java by E.B + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + +package javazoom.jl.decoder; + +/** + * Implements decoding of MPEG Audio Layer II frames. + */ +class LayerIIDecoder extends LayerIDecoder implements FrameDecoder +{ + + public LayerIIDecoder() + { + } + + + protected void createSubbands() + { + int i; + if (mode == Header.SINGLE_CHANNEL) + for (i = 0; i < num_subbands; ++i) + subbands[i] = new SubbandLayer2(i); + else if (mode == Header.JOINT_STEREO) + { + for (i = 0; i < header.intensity_stereo_bound(); ++i) + subbands[i] = new SubbandLayer2Stereo(i); + for (; i < num_subbands; ++i) + subbands[i] = new SubbandLayer2IntensityStereo(i); + } + else + { + for (i = 0; i < num_subbands; ++i) + subbands[i] = new SubbandLayer2Stereo(i); + } + + } + + protected void readScaleFactorSelection() + { + for (int i = 0; i < num_subbands; ++i) + ((SubbandLayer2)subbands[i]).read_scalefactor_selection(stream, crc); + } + + + + /** + * Class for layer II subbands in single channel mode. + */ + static class SubbandLayer2 extends Subband + { + // this table contains 3 requantized samples for each legal codeword + // when grouped in 5 bits, i.e. 3 quantizationsteps per sample + public static final float grouping_5bits[] = new float[] + { + -2.0f/3.0f, -2.0f/3.0f, -2.0f/3.0f, + 0.0f, -2.0f/3.0f, -2.0f/3.0f, + 2.0f/3.0f, -2.0f/3.0f, -2.0f/3.0f, + -2.0f/3.0f, 0.0f, -2.0f/3.0f, + 0.0f, 0.0f, -2.0f/3.0f, + 2.0f/3.0f, 0.0f, -2.0f/3.0f, + -2.0f/3.0f, 2.0f/3.0f, -2.0f/3.0f, + 0.0f, 2.0f/3.0f, -2.0f/3.0f, + 2.0f/3.0f, 2.0f/3.0f, -2.0f/3.0f, + -2.0f/3.0f, -2.0f/3.0f, 0.0f, + 0.0f, -2.0f/3.0f, 0.0f, + 2.0f/3.0f, -2.0f/3.0f, 0.0f, + -2.0f/3.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 2.0f/3.0f, 0.0f, 0.0f, + -2.0f/3.0f, 2.0f/3.0f, 0.0f, + 0.0f, 2.0f/3.0f, 0.0f, + 2.0f/3.0f, 2.0f/3.0f, 0.0f, + -2.0f/3.0f, -2.0f/3.0f, 2.0f/3.0f, + 0.0f, -2.0f/3.0f, 2.0f/3.0f, + 2.0f/3.0f, -2.0f/3.0f, 2.0f/3.0f, + -2.0f/3.0f, 0.0f, 2.0f/3.0f, + 0.0f, 0.0f, 2.0f/3.0f, + 2.0f/3.0f, 0.0f, 2.0f/3.0f, + -2.0f/3.0f, 2.0f/3.0f, 2.0f/3.0f, + 0.0f, 2.0f/3.0f, 2.0f/3.0f, + 2.0f/3.0f, 2.0f/3.0f, 2.0f/3.0f + }; + + // this table contains 3 requantized samples for each legal codeword + // when grouped in 7 bits, i.e. 5 quantizationsteps per sample + public static final float grouping_7bits[] = new float[] + { + -0.8f, -0.8f, -0.8f, -0.4f, -0.8f, -0.8f, 0.0f, -0.8f, -0.8f, 0.4f, -0.8f, -0.8f, 0.8f, -0.8f, -0.8f, + -0.8f, -0.4f, -0.8f, -0.4f, -0.4f, -0.8f, 0.0f, -0.4f, -0.8f, 0.4f, -0.4f, -0.8f, 0.8f, -0.4f, -0.8f, + -0.8f, 0.0f, -0.8f, -0.4f, 0.0f, -0.8f, 0.0f, 0.0f, -0.8f, 0.4f, 0.0f, -0.8f, 0.8f, 0.0f, -0.8f, + -0.8f, 0.4f, -0.8f, -0.4f, 0.4f, -0.8f, 0.0f, 0.4f, -0.8f, 0.4f, 0.4f, -0.8f, 0.8f, 0.4f, -0.8f, + -0.8f, 0.8f, -0.8f, -0.4f, 0.8f, -0.8f, 0.0f, 0.8f, -0.8f, 0.4f, 0.8f, -0.8f, 0.8f, 0.8f, -0.8f, + -0.8f, -0.8f, -0.4f, -0.4f, -0.8f, -0.4f, 0.0f, -0.8f, -0.4f, 0.4f, -0.8f, -0.4f, 0.8f, -0.8f, -0.4f, + -0.8f, -0.4f, -0.4f, -0.4f, -0.4f, -0.4f, 0.0f, -0.4f, -0.4f, 0.4f, -0.4f, -0.4f, 0.8f, -0.4f, -0.4f, + -0.8f, 0.0f, -0.4f, -0.4f, 0.0f, -0.4f, 0.0f, 0.0f, -0.4f, 0.4f, 0.0f, -0.4f, 0.8f, 0.0f, -0.4f, + -0.8f, 0.4f, -0.4f, -0.4f, 0.4f, -0.4f, 0.0f, 0.4f, -0.4f, 0.4f, 0.4f, -0.4f, 0.8f, 0.4f, -0.4f, + -0.8f, 0.8f, -0.4f, -0.4f, 0.8f, -0.4f, 0.0f, 0.8f, -0.4f, 0.4f, 0.8f, -0.4f, 0.8f, 0.8f, -0.4f, + -0.8f, -0.8f, 0.0f, -0.4f, -0.8f, 0.0f, 0.0f, -0.8f, 0.0f, 0.4f, -0.8f, 0.0f, 0.8f, -0.8f, 0.0f, + -0.8f, -0.4f, 0.0f, -0.4f, -0.4f, 0.0f, 0.0f, -0.4f, 0.0f, 0.4f, -0.4f, 0.0f, 0.8f, -0.4f, 0.0f, + -0.8f, 0.0f, 0.0f, -0.4f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.4f, 0.0f, 0.0f, 0.8f, 0.0f, 0.0f, + -0.8f, 0.4f, 0.0f, -0.4f, 0.4f, 0.0f, 0.0f, 0.4f, 0.0f, 0.4f, 0.4f, 0.0f, 0.8f, 0.4f, 0.0f, + -0.8f, 0.8f, 0.0f, -0.4f, 0.8f, 0.0f, 0.0f, 0.8f, 0.0f, 0.4f, 0.8f, 0.0f, 0.8f, 0.8f, 0.0f, + -0.8f, -0.8f, 0.4f, -0.4f, -0.8f, 0.4f, 0.0f, -0.8f, 0.4f, 0.4f, -0.8f, 0.4f, 0.8f, -0.8f, 0.4f, + -0.8f, -0.4f, 0.4f, -0.4f, -0.4f, 0.4f, 0.0f, -0.4f, 0.4f, 0.4f, -0.4f, 0.4f, 0.8f, -0.4f, 0.4f, + -0.8f, 0.0f, 0.4f, -0.4f, 0.0f, 0.4f, 0.0f, 0.0f, 0.4f, 0.4f, 0.0f, 0.4f, 0.8f, 0.0f, 0.4f, + -0.8f, 0.4f, 0.4f, -0.4f, 0.4f, 0.4f, 0.0f, 0.4f, 0.4f, 0.4f, 0.4f, 0.4f, 0.8f, 0.4f, 0.4f, + -0.8f, 0.8f, 0.4f, -0.4f, 0.8f, 0.4f, 0.0f, 0.8f, 0.4f, 0.4f, 0.8f, 0.4f, 0.8f, 0.8f, 0.4f, + -0.8f, -0.8f, 0.8f, -0.4f, -0.8f, 0.8f, 0.0f, -0.8f, 0.8f, 0.4f, -0.8f, 0.8f, 0.8f, -0.8f, 0.8f, + -0.8f, -0.4f, 0.8f, -0.4f, -0.4f, 0.8f, 0.0f, -0.4f, 0.8f, 0.4f, -0.4f, 0.8f, 0.8f, -0.4f, 0.8f, + -0.8f, 0.0f, 0.8f, -0.4f, 0.0f, 0.8f, 0.0f, 0.0f, 0.8f, 0.4f, 0.0f, 0.8f, 0.8f, 0.0f, 0.8f, + -0.8f, 0.4f, 0.8f, -0.4f, 0.4f, 0.8f, 0.0f, 0.4f, 0.8f, 0.4f, 0.4f, 0.8f, 0.8f, 0.4f, 0.8f, + -0.8f, 0.8f, 0.8f, -0.4f, 0.8f, 0.8f, 0.0f, 0.8f, 0.8f, 0.4f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f + }; + + // this table contains 3 requantized samples for each legal codeword + // when grouped in 10 bits, i.e. 9 quantizationsteps per sample + public static final float grouping_10bits[] = + { + -8.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f, + -2.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f, 0.0f, -8.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f, + 4.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f, + -8.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, + -2.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, 0.0f, -6.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, + 4.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, + -8.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, + -2.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, 0.0f, -4.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, + 4.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, + -8.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f, + -2.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f, 0.0f, -2.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f, + 4.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f, + -8.0f/9.0f, 0.0f, -8.0f/9.0f, -6.0f/9.0f, 0.0f, -8.0f/9.0f, -4.0f/9.0f, 0.0f, -8.0f/9.0f, + -2.0f/9.0f, 0.0f, -8.0f/9.0f, 0.0f, 0.0f, -8.0f/9.0f, 2.0f/9.0f, 0.0f, -8.0f/9.0f, + 4.0f/9.0f, 0.0f, -8.0f/9.0f, 6.0f/9.0f, 0.0f, -8.0f/9.0f, 8.0f/9.0f, 0.0f, -8.0f/9.0f, + -8.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, + -2.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, 0.0f, 2.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, + 4.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, + -8.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f, + -2.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f, 0.0f, 4.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f, + 4.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f, + -8.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, + -2.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, 0.0f, 6.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, + 4.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, + -8.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, + -2.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, 0.0f, 8.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, + 4.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, + -8.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, + -2.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, 0.0f, -8.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, + 4.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, + -8.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, + -2.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 0.0f, -6.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, + 4.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, + -8.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, + -2.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 0.0f, -4.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, + 4.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, + -8.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, + -2.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, 0.0f, -2.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, + 4.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, + -8.0f/9.0f, 0.0f, -6.0f/9.0f, -6.0f/9.0f, 0.0f, -6.0f/9.0f, -4.0f/9.0f, 0.0f, -6.0f/9.0f, + -2.0f/9.0f, 0.0f, -6.0f/9.0f, 0.0f, 0.0f, -6.0f/9.0f, 2.0f/9.0f, 0.0f, -6.0f/9.0f, + 4.0f/9.0f, 0.0f, -6.0f/9.0f, 6.0f/9.0f, 0.0f, -6.0f/9.0f, 8.0f/9.0f, 0.0f, -6.0f/9.0f, + -8.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, + -2.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 0.0f, 2.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, + 4.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, + -8.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, + -2.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, 0.0f, 4.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, + 4.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, + -8.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, + -2.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 0.0f, 6.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, + 4.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, + -8.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, + -2.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 0.0f, 8.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, + 4.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, + -8.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, + -2.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, 0.0f, -8.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, + 4.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, + -8.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, + -2.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 0.0f, -6.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, + 4.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, + -8.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, + -2.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 0.0f, -4.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, + 4.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, + -8.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, + -2.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, 0.0f, -2.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, + 4.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, + -8.0f/9.0f, 0.0f, -4.0f/9.0f, -6.0f/9.0f, 0.0f, -4.0f/9.0f, -4.0f/9.0f, 0.0f, -4.0f/9.0f, + -2.0f/9.0f, 0.0f, -4.0f/9.0f, 0.0f, 0.0f, -4.0f/9.0f, 2.0f/9.0f, 0.0f, -4.0f/9.0f, + 4.0f/9.0f, 0.0f, -4.0f/9.0f, 6.0f/9.0f, 0.0f, -4.0f/9.0f, 8.0f/9.0f, 0.0f, -4.0f/9.0f, + -8.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, + -2.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 0.0f, 2.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, + 4.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, + -8.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, + -2.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, 0.0f, 4.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, + 4.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, + -8.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, + -2.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 0.0f, 6.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, + 4.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, + -8.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, + -2.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 0.0f, 8.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, + 4.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, + -8.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f, + -2.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f, 0.0f, -8.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f, + 4.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f, + -8.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, + -2.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, 0.0f, -6.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, + 4.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, + -8.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, + -2.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, 0.0f, -4.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, + 4.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, + -8.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f, + -2.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f, 0.0f, -2.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f, + 4.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f, + -8.0f/9.0f, 0.0f, -2.0f/9.0f, -6.0f/9.0f, 0.0f, -2.0f/9.0f, -4.0f/9.0f, 0.0f, -2.0f/9.0f, + -2.0f/9.0f, 0.0f, -2.0f/9.0f, 0.0f, 0.0f, -2.0f/9.0f, 2.0f/9.0f, 0.0f, -2.0f/9.0f, + 4.0f/9.0f, 0.0f, -2.0f/9.0f, 6.0f/9.0f, 0.0f, -2.0f/9.0f, 8.0f/9.0f, 0.0f, -2.0f/9.0f, + -8.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, + -2.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, 0.0f, 2.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, + 4.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, + -8.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f, + -2.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f, 0.0f, 4.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f, + 4.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f, + -8.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, + -2.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, 0.0f, 6.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, + 4.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, + -8.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, + -2.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, 0.0f, 8.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, + 4.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, + -8.0f/9.0f, -8.0f/9.0f, 0.0f, -6.0f/9.0f, -8.0f/9.0f, 0.0f, -4.0f/9.0f, -8.0f/9.0f, 0.0f, + -2.0f/9.0f, -8.0f/9.0f, 0.0f, 0.0f, -8.0f/9.0f, 0.0f, 2.0f/9.0f, -8.0f/9.0f, 0.0f, + 4.0f/9.0f, -8.0f/9.0f, 0.0f, 6.0f/9.0f, -8.0f/9.0f, 0.0f, 8.0f/9.0f, -8.0f/9.0f, 0.0f, + -8.0f/9.0f, -6.0f/9.0f, 0.0f, -6.0f/9.0f, -6.0f/9.0f, 0.0f, -4.0f/9.0f, -6.0f/9.0f, 0.0f, + -2.0f/9.0f, -6.0f/9.0f, 0.0f, 0.0f, -6.0f/9.0f, 0.0f, 2.0f/9.0f, -6.0f/9.0f, 0.0f, + 4.0f/9.0f, -6.0f/9.0f, 0.0f, 6.0f/9.0f, -6.0f/9.0f, 0.0f, 8.0f/9.0f, -6.0f/9.0f, 0.0f, + -8.0f/9.0f, -4.0f/9.0f, 0.0f, -6.0f/9.0f, -4.0f/9.0f, 0.0f, -4.0f/9.0f, -4.0f/9.0f, 0.0f, + -2.0f/9.0f, -4.0f/9.0f, 0.0f, 0.0f, -4.0f/9.0f, 0.0f, 2.0f/9.0f, -4.0f/9.0f, 0.0f, + 4.0f/9.0f, -4.0f/9.0f, 0.0f, 6.0f/9.0f, -4.0f/9.0f, 0.0f, 8.0f/9.0f, -4.0f/9.0f, 0.0f, + -8.0f/9.0f, -2.0f/9.0f, 0.0f, -6.0f/9.0f, -2.0f/9.0f, 0.0f, -4.0f/9.0f, -2.0f/9.0f, 0.0f, + -2.0f/9.0f, -2.0f/9.0f, 0.0f, 0.0f, -2.0f/9.0f, 0.0f, 2.0f/9.0f, -2.0f/9.0f, 0.0f, + 4.0f/9.0f, -2.0f/9.0f, 0.0f, 6.0f/9.0f, -2.0f/9.0f, 0.0f, 8.0f/9.0f, -2.0f/9.0f, 0.0f, + -8.0f/9.0f, 0.0f, 0.0f, -6.0f/9.0f, 0.0f, 0.0f, -4.0f/9.0f, 0.0f, 0.0f, + -2.0f/9.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f/9.0f, 0.0f, 0.0f, + 4.0f/9.0f, 0.0f, 0.0f, 6.0f/9.0f, 0.0f, 0.0f, 8.0f/9.0f, 0.0f, 0.0f, + -8.0f/9.0f, 2.0f/9.0f, 0.0f, -6.0f/9.0f, 2.0f/9.0f, 0.0f, -4.0f/9.0f, 2.0f/9.0f, 0.0f, + -2.0f/9.0f, 2.0f/9.0f, 0.0f, 0.0f, 2.0f/9.0f, 0.0f, 2.0f/9.0f, 2.0f/9.0f, 0.0f, + 4.0f/9.0f, 2.0f/9.0f, 0.0f, 6.0f/9.0f, 2.0f/9.0f, 0.0f, 8.0f/9.0f, 2.0f/9.0f, 0.0f, + -8.0f/9.0f, 4.0f/9.0f, 0.0f, -6.0f/9.0f, 4.0f/9.0f, 0.0f, -4.0f/9.0f, 4.0f/9.0f, 0.0f, + -2.0f/9.0f, 4.0f/9.0f, 0.0f, 0.0f, 4.0f/9.0f, 0.0f, 2.0f/9.0f, 4.0f/9.0f, 0.0f, + 4.0f/9.0f, 4.0f/9.0f, 0.0f, 6.0f/9.0f, 4.0f/9.0f, 0.0f, 8.0f/9.0f, 4.0f/9.0f, 0.0f, + -8.0f/9.0f, 6.0f/9.0f, 0.0f, -6.0f/9.0f, 6.0f/9.0f, 0.0f, -4.0f/9.0f, 6.0f/9.0f, 0.0f, + -2.0f/9.0f, 6.0f/9.0f, 0.0f, 0.0f, 6.0f/9.0f, 0.0f, 2.0f/9.0f, 6.0f/9.0f, 0.0f, + 4.0f/9.0f, 6.0f/9.0f, 0.0f, 6.0f/9.0f, 6.0f/9.0f, 0.0f, 8.0f/9.0f, 6.0f/9.0f, 0.0f, + -8.0f/9.0f, 8.0f/9.0f, 0.0f, -6.0f/9.0f, 8.0f/9.0f, 0.0f, -4.0f/9.0f, 8.0f/9.0f, 0.0f, + -2.0f/9.0f, 8.0f/9.0f, 0.0f, 0.0f, 8.0f/9.0f, 0.0f, 2.0f/9.0f, 8.0f/9.0f, 0.0f, + 4.0f/9.0f, 8.0f/9.0f, 0.0f, 6.0f/9.0f, 8.0f/9.0f, 0.0f, 8.0f/9.0f, 8.0f/9.0f, 0.0f, + -8.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, + -2.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, 0.0f, -8.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, + 4.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, + -8.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, + -2.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 0.0f, -6.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, + 4.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, + -8.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, + -2.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 0.0f, -4.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, + 4.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, + -8.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, + -2.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, 0.0f, -2.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, + 4.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, + -8.0f/9.0f, 0.0f, 2.0f/9.0f, -6.0f/9.0f, 0.0f, 2.0f/9.0f, -4.0f/9.0f, 0.0f, 2.0f/9.0f, + -2.0f/9.0f, 0.0f, 2.0f/9.0f, 0.0f, 0.0f, 2.0f/9.0f, 2.0f/9.0f, 0.0f, 2.0f/9.0f, + 4.0f/9.0f, 0.0f, 2.0f/9.0f, 6.0f/9.0f, 0.0f, 2.0f/9.0f, 8.0f/9.0f, 0.0f, 2.0f/9.0f, + -8.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, + -2.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 0.0f, 2.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, + 4.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, + -8.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, + -2.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, 0.0f, 4.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, + 4.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, + -8.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, + -2.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 0.0f, 6.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, + 4.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, + -8.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, + -2.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 0.0f, 8.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, + 4.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, + -8.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f, + -2.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f, 0.0f, -8.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f, + 4.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f, + -8.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, + -2.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, 0.0f, -6.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, + 4.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, + -8.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, + -2.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, 0.0f, -4.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, + 4.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, + -8.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f, + -2.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f, 0.0f, -2.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f, + 4.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f, + -8.0f/9.0f, 0.0f, 4.0f/9.0f, -6.0f/9.0f, 0.0f, 4.0f/9.0f, -4.0f/9.0f, 0.0f, 4.0f/9.0f, + -2.0f/9.0f, 0.0f, 4.0f/9.0f, 0.0f, 0.0f, 4.0f/9.0f, 2.0f/9.0f, 0.0f, 4.0f/9.0f, + 4.0f/9.0f, 0.0f, 4.0f/9.0f, 6.0f/9.0f, 0.0f, 4.0f/9.0f, 8.0f/9.0f, 0.0f, 4.0f/9.0f, + -8.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, + -2.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, 0.0f, 2.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, + 4.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, + -8.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f, + -2.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f, 0.0f, 4.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f, + 4.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f, + -8.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, + -2.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, 0.0f, 6.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, + 4.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, + -8.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, + -2.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, 0.0f, 8.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, + 4.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, + -8.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, + -2.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, 0.0f, -8.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, + 4.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, + -8.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, + -2.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 0.0f, -6.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, + 4.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, + -8.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, + -2.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 0.0f, -4.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, + 4.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, + -8.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, + -2.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, 0.0f, -2.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, + 4.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, + -8.0f/9.0f, 0.0f, 6.0f/9.0f, -6.0f/9.0f, 0.0f, 6.0f/9.0f, -4.0f/9.0f, 0.0f, 6.0f/9.0f, + -2.0f/9.0f, 0.0f, 6.0f/9.0f, 0.0f, 0.0f, 6.0f/9.0f, 2.0f/9.0f, 0.0f, 6.0f/9.0f, + 4.0f/9.0f, 0.0f, 6.0f/9.0f, 6.0f/9.0f, 0.0f, 6.0f/9.0f, 8.0f/9.0f, 0.0f, 6.0f/9.0f, + -8.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, + -2.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 0.0f, 2.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, + 4.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, + -8.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, + -2.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, 0.0f, 4.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, + 4.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, + -8.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, + -2.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 0.0f, 6.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, + 4.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, + -8.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, + -2.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 0.0f, 8.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, + 4.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, + -8.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, + -2.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, 0.0f, -8.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, + 4.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, + -8.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, + -2.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 0.0f, -6.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, + 4.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, + -8.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, + -2.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 0.0f, -4.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, + 4.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, + -8.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, + -2.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, 0.0f, -2.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, + 4.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, + -8.0f/9.0f, 0.0f, 8.0f/9.0f, -6.0f/9.0f, 0.0f, 8.0f/9.0f, -4.0f/9.0f, 0.0f, 8.0f/9.0f, + -2.0f/9.0f, 0.0f, 8.0f/9.0f, 0.0f, 0.0f, 8.0f/9.0f, 2.0f/9.0f, 0.0f, 8.0f/9.0f, + 4.0f/9.0f, 0.0f, 8.0f/9.0f, 6.0f/9.0f, 0.0f, 8.0f/9.0f, 8.0f/9.0f, 0.0f, 8.0f/9.0f, + -8.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, + -2.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 0.0f, 2.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, + 4.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, + -8.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, + -2.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, 0.0f, 4.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, + 4.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, + -8.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, + -2.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 0.0f, 6.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, + 4.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, + -8.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, + -2.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 0.0f, 8.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, + 4.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f + }; + + // data taken from ISO/IEC DIS 11172, Annexes 3-B.2[abcd] and 3-B.4: + + // subbands 0-2 in tables 3-B.2a and 2b: (index is allocation) + public static final int table_ab1_codelength[] = + // bits per codeword + { 0, 5, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; + + public static final float table_ab1_groupingtables[][] = + // pointer to sample grouping table, or NULL-pointer if ungrouped + { null, grouping_5bits, null, null, null, null, null, null, null, null, null, null, null, null, null, null }; + + public static final float table_ab1_factor[] = + // factor for requantization: (real)sample * factor - 1.0 gives requantized sample + { 0.0f, 1.0f/2.0f, 1.0f/4.0f, 1.0f/8.0f, 1.0f/16.0f, 1.0f/32.0f, 1.0f/64.0f, + 1.0f/128.0f, 1.0f/256.0f, 1.0f/512.0f, 1.0f/1024.0f, 1.0f/2048.0f, + 1.0f/4096.0f, 1.0f/8192.0f, 1.0f/16384.0f, 1.0f/32768.0f }; + + public static final float table_ab1_c[] = + // factor c for requantization from table 3-B.4 + { 0.0f, 1.33333333333f, 1.14285714286f, 1.06666666666f, 1.03225806452f, + 1.01587301587f, 1.00787401575f, 1.00392156863f, 1.00195694716f, 1.00097751711f, + 1.00048851979f, 1.00024420024f, 1.00012208522f, 1.00006103888f, 1.00003051851f, + 1.00001525902f }; + + public static final float table_ab1_d[] = + // addend d for requantization from table 3-B.4 + { 0.0f, 0.50000000000f, 0.25000000000f, 0.12500000000f, 0.06250000000f, + 0.03125000000f, 0.01562500000f, 0.00781250000f, 0.00390625000f, 0.00195312500f, + 0.00097656250f, 0.00048828125f, 0.00024414063f, 0.00012207031f, 0.00006103516f, + 0.00003051758f }; + + // subbands 3-... tables 3-B.2a and 2b: + public static final float[] table_ab234_groupingtables[] = + { null, grouping_5bits, grouping_7bits, null, grouping_10bits, null, null, null, null, null, null, null, null, null, null, null }; + + // subbands 3-10 in tables 3-B.2a and 2b: + public static final int table_ab2_codelength[] = + { 0, 5, 7, 3, 10, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 }; + public static final float table_ab2_factor[] = + { 0.0f, 1.0f/2.0f, 1.0f/4.0f, 1.0f/4.0f, 1.0f/8.0f, 1.0f/8.0f, 1.0f/16.0f, + 1.0f/32.0f, 1.0f/64.0f, 1.0f/128.0f, 1.0f/256.0f, 1.0f/512.0f, + 1.0f/1024.0f, 1.0f/2048.0f, 1.0f/4096.0f, 1.0f/32768.0f }; + public static final float table_ab2_c[] = + { 0.0f, 1.33333333333f, 1.60000000000f, 1.14285714286f, 1.77777777777f, + 1.06666666666f, 1.03225806452f, 1.01587301587f, 1.00787401575f, 1.00392156863f, + 1.00195694716f, 1.00097751711f, 1.00048851979f, 1.00024420024f, 1.00012208522f, + 1.00001525902f }; + public static final float table_ab2_d[] = + { 0.0f, 0.50000000000f, 0.50000000000f, 0.25000000000f, 0.50000000000f, + 0.12500000000f, 0.06250000000f, 0.03125000000f, 0.01562500000f, 0.00781250000f, + 0.00390625000f, 0.00195312500f, 0.00097656250f, 0.00048828125f, 0.00024414063f, + 0.00003051758f }; + + // subbands 11-22 in tables 3-B.2a and 2b: + public static final int table_ab3_codelength[] = { 0, 5, 7, 3, 10, 4, 5, 16 }; + public static final float table_ab3_factor[] = + { 0.0f, 1.0f/2.0f, 1.0f/4.0f, 1.0f/4.0f, 1.0f/8.0f, 1.0f/8.0f, 1.0f/16.0f, 1.0f/32768.0f }; + public static final float table_ab3_c[] = + { 0.0f, 1.33333333333f, 1.60000000000f, 1.14285714286f, 1.77777777777f, + 1.06666666666f, 1.03225806452f, 1.00001525902f }; + public static final float table_ab3_d[] = + { 0.0f, 0.50000000000f, 0.50000000000f, 0.25000000000f, 0.50000000000f, + 0.12500000000f, 0.06250000000f, 0.00003051758f }; + + // subbands 23-... in tables 3-B.2a and 2b: + public static final int table_ab4_codelength[] = { 0, 5, 7, 16 }; + public static final float table_ab4_factor[] = { 0.0f, 1.0f/2.0f, 1.0f/4.0f, 1.0f/32768.0f }; + public static final float table_ab4_c[] = { 0.0f, 1.33333333333f, 1.60000000000f, 1.00001525902f }; + public static final float table_ab4_d[] = { 0.0f, 0.50000000000f, 0.50000000000f, 0.00003051758f }; + + // subbands in tables 3-B.2c and 2d: + public static final int table_cd_codelength[] = + { 0, 5, 7, 10, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; + public static final float table_cd_groupingtables[][] = + { null, grouping_5bits, grouping_7bits, grouping_10bits, null, null, null, null, null, null, null, null, null, null, null, null }; + public static final float table_cd_factor[] = + { 0.0f, 1.0f/2.0f, 1.0f/4.0f, 1.0f/8.0f, 1.0f/8.0f, 1.0f/16.0f, 1.0f/32.0f, 1.0f/64.0f, + 1.0f/128.0f, 1.0f/256.0f, 1.0f/512.0f, 1.0f/1024.0f, 1.0f/2048.0f, 1.0f/4096.0f, + 1.0f/8192.0f, 1.0f/16384.0f }; + public static final float table_cd_c[] = + { 0.0f, 1.33333333333f, 1.60000000000f, 1.77777777777f, 1.06666666666f, + 1.03225806452f, 1.01587301587f, 1.00787401575f, 1.00392156863f, 1.00195694716f, + 1.00097751711f, 1.00048851979f, 1.00024420024f, 1.00012208522f, 1.00006103888f, + 1.00003051851f }; + public static final float table_cd_d[] = + { 0.0f, 0.50000000000f, 0.50000000000f, 0.50000000000f, 0.12500000000f, + 0.06250000000f, 0.03125000000f, 0.01562500000f, 0.00781250000f, 0.00390625000f, + 0.00195312500f, 0.00097656250f, 0.00048828125f, 0.00024414063f, 0.00012207031f, + 0.00006103516f }; + + + + protected int subbandnumber; + protected int allocation; + protected int scfsi; + protected float scalefactor1, scalefactor2, scalefactor3; + protected int[] codelength = {0}; + protected float groupingtable[][] = new float[2][]; + //protected float[][] groupingtable = {{0},{0}} ; + protected float[] factor = {0.0f}; + protected int groupnumber; + protected int samplenumber; + protected float[] samples = new float[3]; + protected float[] c = {0}; + protected float[] d = {0}; + /** + * Constructor + */ + public SubbandLayer2(int subbandnumber) + { + this.subbandnumber = subbandnumber; + groupnumber = samplenumber = 0; + } + + + /** + * + */ + protected int get_allocationlength (Header header) + { + if (header.version() == Header.MPEG1) + { + int channel_bitrate = header.bitrate_index(); + + // calculate bitrate per channel: + if (header.mode() != Header.SINGLE_CHANNEL) + if (channel_bitrate == 4) + channel_bitrate = 1; + else + channel_bitrate -= 4; + + if (channel_bitrate == 1 || channel_bitrate == 2) + // table 3-B.2c or 3-B.2d + if (subbandnumber <= 1) + return 4; + else + return 3; + else + // tables 3-B.2a or 3-B.2b + if (subbandnumber <= 10) + return 4; + else if (subbandnumber <= 22) + return 3; + else + return 2; + } + else + { // MPEG-2 LSF -- Jeff + + // table B.1 of ISO/IEC 13818-3 + if (subbandnumber <= 3) + return 4; + else if (subbandnumber <= 10) + return 3; + else + return 2; + } + } + + /** + * + */ + protected void prepare_sample_reading(Header header, int allocation, + //float[][] groupingtable, + int channel, + float[] factor, int[] codelength, + float[] c, float[] d) + { + int channel_bitrate = header.bitrate_index(); + // calculate bitrate per channel: + if (header.mode() != Header.SINGLE_CHANNEL) + if (channel_bitrate == 4) + channel_bitrate = 1; + else + channel_bitrate -= 4; + + if (channel_bitrate == 1 || channel_bitrate == 2) + { + // table 3-B.2c or 3-B.2d + groupingtable[channel] = table_cd_groupingtables[allocation]; + factor[0] = table_cd_factor[allocation]; + codelength[0] = table_cd_codelength[allocation]; + c[0] = table_cd_c[allocation]; + d[0] = table_cd_d[allocation]; + } + else + { + // tables 3-B.2a or 3-B.2b + if (subbandnumber <= 2) + { + groupingtable[channel] = table_ab1_groupingtables[allocation]; + factor[0] = table_ab1_factor[allocation]; + codelength[0] = table_ab1_codelength[allocation]; + c[0] = table_ab1_c[allocation]; + d[0] = table_ab1_d[allocation]; + } + else + { + groupingtable[channel] = table_ab234_groupingtables[allocation]; + if (subbandnumber <= 10) + { + factor[0] = table_ab2_factor[allocation]; + codelength[0] = table_ab2_codelength[allocation]; + c[0] = table_ab2_c[allocation]; + d[0] = table_ab2_d[allocation]; + } + else if (subbandnumber <= 22) + { + factor[0] = table_ab3_factor[allocation]; + codelength[0] = table_ab3_codelength[allocation]; + c[0] = table_ab3_c[allocation]; + d[0] = table_ab3_d[allocation]; + } + else + { + factor[0] = table_ab4_factor[allocation]; + codelength[0] = table_ab4_codelength[allocation]; + c[0] = table_ab4_c[allocation]; + d[0] = table_ab4_d[allocation]; + } + } + } + } + + + /** + * + */ + public void read_allocation(Bitstream stream, Header header, Crc16 crc) + { + int length = get_allocationlength(header); + allocation = stream.get_bits(length); + if (crc != null) + crc.add_bits(allocation, length); + } + + /** + * + */ + public void read_scalefactor_selection (Bitstream stream, Crc16 crc) + { + if (allocation != 0) + { + scfsi = stream.get_bits(2); + if (crc != null) crc.add_bits(scfsi, 2); + } + } + + /** + * + */ + public void read_scalefactor (Bitstream stream, Header header) + { + if (allocation != 0) + { + switch (scfsi) + { + case 0: + scalefactor1 = scalefactors[stream.get_bits(6)]; + scalefactor2 = scalefactors[stream.get_bits(6)]; + scalefactor3 = scalefactors[stream.get_bits(6)]; + break; + case 1: + scalefactor1 = scalefactor2 = scalefactors[stream.get_bits(6)]; + scalefactor3 = scalefactors[stream.get_bits(6)]; + break; + case 2: + scalefactor1 = scalefactor2 = scalefactor3 = scalefactors[stream.get_bits(6)]; + break; + case 3: + scalefactor1 = scalefactors[stream.get_bits(6)]; + scalefactor2 = scalefactor3 = scalefactors[stream.get_bits(6)]; + break; + } + prepare_sample_reading(header, allocation, 0, + factor, codelength, c, d); + } + } + + /** + * + */ + public boolean read_sampledata (Bitstream stream) + { + if (allocation != 0) + if (groupingtable[0] != null) + { + int samplecode = stream.get_bits(codelength[0]); + // create requantized samples: + samplecode += samplecode << 1; + float[] target = samples; + float[] source = groupingtable[0]; + /* + int tmp = 0; + int temp = 0; + target[tmp++] = source[samplecode + temp]; + temp++; + target[tmp++] = source[samplecode + temp]; + temp++; + target[tmp] = source[samplecode + temp]; + */ + //Bugfix: + int tmp = 0; + int temp = samplecode; + + if(temp > source.length - 3) temp = source.length - 3; + + target[tmp] = source[temp]; + temp++;tmp++; + target[tmp] = source[temp]; + temp++;tmp++; + target[tmp] = source[temp]; + + // memcpy (samples, groupingtable + samplecode, 3 * sizeof (real)); + } + else + { + samples[0] = (float) ((stream.get_bits(codelength[0])) * factor[0] - 1.0); + samples[1] = (float) ((stream.get_bits(codelength[0])) * factor[0] - 1.0); + samples[2] = (float) ((stream.get_bits(codelength[0])) * factor[0] - 1.0); + } + + samplenumber = 0; + if (++groupnumber == 12) + return true; + else + return false; + } + + /** + * + */ + public boolean put_next_sample(int channels, SynthesisFilter filter1, SynthesisFilter filter2) + { + if ((allocation != 0) && (channels != OutputChannels.RIGHT_CHANNEL)) + { + float sample = samples[samplenumber]; + + if (groupingtable[0] == null) + sample = (sample + d[0]) * c[0]; + if (groupnumber <= 4) + sample *= scalefactor1; + else if (groupnumber <= 8) + sample *= scalefactor2; + else + sample *= scalefactor3; + filter1.input_sample(sample, subbandnumber); + } + + if (++samplenumber == 3) + return true; + else + return false; + } + }; + + /** + * Class for layer II subbands in joint stereo mode. + */ + static class SubbandLayer2IntensityStereo extends SubbandLayer2 + { + protected int channel2_scfsi; + protected float channel2_scalefactor1, channel2_scalefactor2, channel2_scalefactor3; + + /** + * Constructor + */ + public SubbandLayer2IntensityStereo (int subbandnumber) + { + super(subbandnumber); + } + + /** + * + */ + public void read_allocation(Bitstream stream, Header header, Crc16 crc) + { + super.read_allocation (stream, header, crc); + } + + /** + * + */ + public void read_scalefactor_selection(Bitstream stream, Crc16 crc) + { + if (allocation != 0) + { + scfsi = stream.get_bits(2); + channel2_scfsi = stream.get_bits(2); + if (crc != null) + { + crc.add_bits(scfsi, 2); + crc.add_bits(channel2_scfsi, 2); + } + } + } + + /** + * + */ + public void read_scalefactor(Bitstream stream, Header header) + { + if (allocation != 0) + { + super.read_scalefactor(stream, header); + switch (channel2_scfsi) + { + case 0: + channel2_scalefactor1 = scalefactors[stream.get_bits(6)]; + channel2_scalefactor2 = scalefactors[stream.get_bits(6)]; + channel2_scalefactor3 = scalefactors[stream.get_bits(6)]; + break; + + case 1: + channel2_scalefactor1 = channel2_scalefactor2 = scalefactors[stream.get_bits (6)]; + channel2_scalefactor3 = scalefactors[stream.get_bits(6)]; + break; + + case 2: + channel2_scalefactor1 = channel2_scalefactor2 = + channel2_scalefactor3 = scalefactors[stream.get_bits(6)]; + break; + + case 3: + channel2_scalefactor1 = scalefactors[stream.get_bits(6)]; + channel2_scalefactor2 = channel2_scalefactor3 = scalefactors[stream.get_bits (6)]; + break; + } + } + + } + + /** + * + */ + public boolean read_sampledata(Bitstream stream) + { + return super.read_sampledata (stream); + } + + /** + * + */ + public boolean put_next_sample(int channels, SynthesisFilter filter1, SynthesisFilter filter2) + { + if (allocation != 0) + { + float sample = samples[samplenumber]; + + if (groupingtable[0] == null) + sample = (sample + d[0]) * c[0]; + if (channels == OutputChannels.BOTH_CHANNELS) + { + float sample2 = sample; + if (groupnumber <= 4) + { + sample *= scalefactor1; + sample2 *= channel2_scalefactor1; + } + else if (groupnumber <= 8) + { + sample *= scalefactor2; + sample2 *= channel2_scalefactor2; + } + else + { + sample *= scalefactor3; + sample2 *= channel2_scalefactor3; + } + filter1.input_sample(sample, subbandnumber); + filter2.input_sample(sample2, subbandnumber); + } + else if (channels == OutputChannels.LEFT_CHANNEL) + { + if (groupnumber <= 4) + sample *= scalefactor1; + else if (groupnumber <= 8) + sample *= scalefactor2; + else + sample *= scalefactor3; + filter1.input_sample(sample, subbandnumber); + } + else + { + if (groupnumber <= 4) + sample *= channel2_scalefactor1; + else if (groupnumber <= 8) + sample *= channel2_scalefactor2; + else + sample *= channel2_scalefactor3; + filter1.input_sample(sample, subbandnumber); + } + } + + if (++samplenumber == 3) + return true; + else + return false; + } + }; + + /** + * Class for layer II subbands in stereo mode. + */ + static class SubbandLayer2Stereo extends SubbandLayer2 + { + protected int channel2_allocation; + protected int channel2_scfsi; + protected float channel2_scalefactor1, channel2_scalefactor2, channel2_scalefactor3; + //protected boolean channel2_grouping; ???? Never used! + protected int[] channel2_codelength = {0}; + //protected float[][] channel2_groupingtable = {{0},{0}}; + protected float[] channel2_factor = {0}; + protected float[] channel2_samples; + protected float[] channel2_c = {0}; + protected float[] channel2_d = {0}; + + /** + * Constructor + */ + public SubbandLayer2Stereo(int subbandnumber) + { + super(subbandnumber); + channel2_samples = new float[3]; + } + + /** + * + */ + public void read_allocation (Bitstream stream, Header header, Crc16 crc) + { + int length = get_allocationlength(header); + allocation = stream.get_bits(length); + channel2_allocation = stream.get_bits(length); + if (crc != null) + { + crc.add_bits(allocation, length); + crc.add_bits(channel2_allocation, length); + } + } + + /** + * + */ + public void read_scalefactor_selection(Bitstream stream, Crc16 crc) + { + if (allocation != 0) + { + scfsi = stream.get_bits(2); + if (crc != null) + crc.add_bits(scfsi, 2); + } + if (channel2_allocation != 0) + { + channel2_scfsi = stream.get_bits(2); + if (crc != null) + crc.add_bits(channel2_scfsi, 2); + } + } + + /** + * + */ + public void read_scalefactor(Bitstream stream, Header header) + { + super.read_scalefactor(stream, header); + if (channel2_allocation != 0) + { + switch (channel2_scfsi) + { + case 0: + channel2_scalefactor1 = scalefactors[stream.get_bits(6)]; + channel2_scalefactor2 = scalefactors[stream.get_bits(6)]; + channel2_scalefactor3 = scalefactors[stream.get_bits(6)]; + break; + + case 1: + channel2_scalefactor1 = channel2_scalefactor2 = + scalefactors[stream.get_bits(6)]; + channel2_scalefactor3 = scalefactors[stream.get_bits(6)]; + break; + + case 2: + channel2_scalefactor1 = channel2_scalefactor2 = + channel2_scalefactor3 = scalefactors[stream.get_bits(6)]; + break; + + case 3: + channel2_scalefactor1 = scalefactors[stream.get_bits(6)]; + channel2_scalefactor2 = channel2_scalefactor3 = + scalefactors[stream.get_bits(6)]; + break; + } + prepare_sample_reading(header, channel2_allocation, 1, + channel2_factor, channel2_codelength, channel2_c, + channel2_d); + } + } + + /** + * + */ + public boolean read_sampledata (Bitstream stream) + { + boolean returnvalue = super.read_sampledata(stream); + + if (channel2_allocation != 0) + if (groupingtable[1] != null) + { + int samplecode = stream.get_bits(channel2_codelength[0]); + // create requantized samples: + samplecode += samplecode << 1; + /* + float[] target = channel2_samples; + float[] source = channel2_groupingtable[0]; + int tmp = 0; + int temp = 0; + target[tmp++] = source[samplecode + temp]; + temp++; + target[tmp++] = source[samplecode + temp]; + temp++; + target[tmp] = source[samplecode + temp]; + // memcpy (channel2_samples, channel2_groupingtable + samplecode, 3 * sizeof (real)); + */ + float[] target = channel2_samples; + float[] source = groupingtable[1]; + int tmp = 0; + int temp = samplecode; + target[tmp] = source[temp]; + temp++;tmp++; + target[tmp] = source[temp]; + temp++;tmp++; + target[tmp] = source[temp]; + + } + else + { + channel2_samples[0] = (float) ((stream.get_bits(channel2_codelength[0])) * + channel2_factor[0] - 1.0); + channel2_samples[1] = (float) ((stream.get_bits(channel2_codelength[0])) * + channel2_factor[0] - 1.0); + channel2_samples[2] = (float) ((stream.get_bits(channel2_codelength[0])) * + channel2_factor[0] - 1.0); + } + return returnvalue; + } + + /** + * + */ + public boolean put_next_sample(int channels, SynthesisFilter filter1, SynthesisFilter filter2) + { + boolean returnvalue = super.put_next_sample(channels, filter1, filter2); + if ((channel2_allocation != 0) && (channels != OutputChannels.LEFT_CHANNEL)) + { + float sample = channel2_samples[samplenumber - 1]; + + if (groupingtable[1] == null) + sample = (sample + channel2_d[0]) * channel2_c[0]; + + if (groupnumber <= 4) + sample *= channel2_scalefactor1; + else if (groupnumber <= 8) + sample *= channel2_scalefactor2; + else + sample *= channel2_scalefactor3; + if (channels == OutputChannels.BOTH_CHANNELS) + filter2.input_sample(sample, subbandnumber); + else + filter1.input_sample(sample, subbandnumber); + } + return returnvalue; + } + } +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/LayerIIIDecoder.java b/src/lwjgl/java/javazoom/jl/decoder/LayerIIIDecoder.java new file mode 100644 index 0000000..009e60d --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/LayerIIIDecoder.java @@ -0,0 +1,2436 @@ +/* + * 11/19/04 1.0 moved to LGPL. + * + * 18/06/01 Michael Scheerer, Fixed bugs which causes + * negative indexes in method huffmann_decode and in method + * dequanisize_sample. + * + * 16/07/01 Michael Scheerer, Catched a bug in method + * huffmann_decode, which causes an outOfIndexException. + * Cause : Indexnumber of 24 at SfBandIndex, + * which has only a length of 22. I have simply and dirty + * fixed the index to <= 22, because I'm not really be able + * to fix the bug. The Indexnumber is taken from the MP3 + * file and the origin Ma-Player with the same code works + * well. + * + * 02/19/99 Java Conversion by E.B, javalayer@javazoom.net + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + +package javazoom.jl.decoder; + +/** + * Class Implementing Layer 3 Decoding. + * + * @since 0.0 + */ +final class LayerIIIDecoder implements FrameDecoder +{ + static final double d43 = (4.0/3.0); + + public int[] scalefac_buffer; + + // MDM: removed, as this wasn't being used. + //private float CheckSumOut1d = 0.0f; + private int CheckSumHuff = 0; + private int[] is_1d; + private float[][][] ro; + private float[][][] lr; + private float[] out_1d; + private float[][] prevblck; + private float[][] k; + private int[] nonzero; + private Bitstream stream; + private Header header; + private SynthesisFilter filter1, filter2; + private Obuffer buffer; + private int which_channels; + private BitReserve br; + private III_side_info_t si; + + private temporaire2[] III_scalefac_t; + private temporaire2[] scalefac; + // private III_scalefac_t scalefac; + + private int max_gr; + private int frame_start; + private int part2_start; + private int channels; + private int first_channel; + private int last_channel; + private int sfreq; + + + /** + * Constructor. + */ + // REVIEW: these constructor arguments should be moved to the + // decodeFrame() method, where possible, so that one + public LayerIIIDecoder(Bitstream stream0, Header header0, + SynthesisFilter filtera, SynthesisFilter filterb, + Obuffer buffer0, int which_ch0) + { + huffcodetab.inithuff(); + is_1d = new int[SBLIMIT*SSLIMIT+4]; + ro = new float[2][SBLIMIT][SSLIMIT]; + lr = new float[2][SBLIMIT][SSLIMIT]; + out_1d = new float[SBLIMIT*SSLIMIT]; + prevblck = new float[2][SBLIMIT*SSLIMIT]; + k = new float[2][SBLIMIT*SSLIMIT]; + nonzero = new int[2]; + + //III_scalefact_t + III_scalefac_t = new temporaire2[2]; + III_scalefac_t[0] = new temporaire2(); + III_scalefac_t[1] = new temporaire2(); + scalefac = III_scalefac_t; + // L3TABLE INIT + + sfBandIndex = new SBI[9]; // SZD: MPEG2.5 +3 indices + int[] l0 = {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}; + int[] s0 = {0,4,8,12,18,24,32,42,56,74,100,132,174,192}; + int[] l1 = {0,6,12,18,24,30,36,44,54,66,80,96,114,136,162,194,232,278,330,394,464,540,576}; + int[] s1 = {0,4,8,12,18,26,36,48,62,80,104,136,180,192}; + int[] l2 = {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}; + int[] s2 = {0,4,8,12,18,26,36,48,62,80,104,134,174,192}; + + int[] l3 = {0,4,8,12,16,20,24,30,36,44,52,62,74,90,110,134,162,196,238,288,342,418,576}; + int[] s3 = {0,4,8,12,16,22,30,40,52,66,84,106,136,192}; + int[] l4 = {0,4,8,12,16,20,24,30,36,42,50,60,72,88,106,128,156,190,230,276,330,384,576}; + int[] s4 = {0,4,8,12,16,22,28,38,50,64,80,100,126,192}; + int[] l5 = {0,4,8,12,16,20,24,30,36,44,54,66,82,102,126,156,194,240,296,364,448,550,576}; + int[] s5 = {0,4,8,12,16,22,30,42,58,78,104,138,180,192}; + // SZD: MPEG2.5 + int[] l6 = {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}; + int[] s6 = {0,4,8,12,18,26,36,48,62,80,104,134,174,192}; + int[] l7 = {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}; + int[] s7 = {0,4,8,12,18,26,36,48,62,80,104,134,174,192}; + int[] l8 = {0,12,24,36,48,60,72,88,108,132,160,192,232,280,336,400,476,566,568,570,572,574,576}; + int[] s8 = {0,8,16,24,36,52,72,96,124,160,162,164,166,192}; + + sfBandIndex[0]= new SBI(l0,s0); + sfBandIndex[1]= new SBI(l1,s1); + sfBandIndex[2]= new SBI(l2,s2); + + sfBandIndex[3]= new SBI(l3,s3); + sfBandIndex[4]= new SBI(l4,s4); + sfBandIndex[5]= new SBI(l5,s5); + //SZD: MPEG2.5 + sfBandIndex[6]= new SBI(l6,s6); + sfBandIndex[7]= new SBI(l7,s7); + sfBandIndex[8]= new SBI(l8,s8); + // END OF L3TABLE INIT + + if(reorder_table == null) { // SZD: generate LUT + reorder_table = new int[9][]; + for(int i = 0; i < 9; i++) + reorder_table[i] = reorder(sfBandIndex[i].s); + } + + // Sftable + int[] ll0 = {0, 6, 11, 16, 21}; + int[] ss0 = {0, 6, 12}; + sftable = new Sftable(ll0,ss0); + // END OF Sftable + + // scalefac_buffer + scalefac_buffer = new int[54]; + // END OF scalefac_buffer + + stream = stream0; + header = header0; + filter1 = filtera; + filter2 = filterb; + buffer = buffer0; + which_channels = which_ch0; + + frame_start = 0; + channels = (header.mode() == Header.SINGLE_CHANNEL) ? 1 : 2; + max_gr = (header.version() == Header.MPEG1) ? 2 : 1; + + sfreq = header.sample_frequency() + + ((header.version() == Header.MPEG1) ? 3 : + (header.version() == Header.MPEG25_LSF) ? 6 : 0); // SZD + + if (channels == 2) + { + switch (which_channels) + { + case OutputChannels.LEFT_CHANNEL: + case OutputChannels.DOWNMIX_CHANNELS: + first_channel = last_channel = 0; + break; + + case OutputChannels.RIGHT_CHANNEL: + first_channel = last_channel = 1; + break; + + case OutputChannels.BOTH_CHANNELS: + default: + first_channel = 0; + last_channel = 1; + break; + } + } + else + { + first_channel = last_channel = 0; + } + + for(int ch=0;ch<2;ch++) + for (int j=0; j<576; j++) + prevblck[ch][j] = 0.0f; + + nonzero[0] = nonzero[1] = 576; + + br = new BitReserve(); + si = new III_side_info_t(); + } + + /** + * Notify decoder that a seek is being made. + */ + public void seek_notify() + { + frame_start = 0; + for(int ch=0;ch<2;ch++) + for (int j=0; j<576; j++) + prevblck[ch][j] = 0.0f; + br = new BitReserve(); + } + + public void decodeFrame() + { + decode(); + } + + /** + * Decode one frame, filling the buffer with the output samples. + */ + + // subband samples are buffered and passed to the + // SynthesisFilter in one go. + private float[] samples1 = new float[32]; + private float[] samples2 = new float[32]; + + public void decode() + { + int nSlots = header.slots(); + int flush_main; + int gr, ch, ss, sb, sb18; + int main_data_end; + int bytes_to_discard; + int i; + + get_side_info(); + + for (i=0; i>> 3; // of previous frame + + if ((flush_main = (br.hsstell() & 7)) != 0) { + br.hgetbits(8 - flush_main); + main_data_end++; + } + + bytes_to_discard = frame_start - main_data_end + - si.main_data_begin; + + frame_start += nSlots; + + if (bytes_to_discard < 0) + return; + + if (main_data_end > 4096) { + frame_start -= 4096; + br.rewindNbytes(4096); + } + + for (; bytes_to_discard > 0; bytes_to_discard--) + br.hgetbits(8); + + for (gr=0;gr>> 4) / 5 ; + new_slen[1] = (scalefac_comp >>> 4) % 5 ; + new_slen[2] = (scalefac_comp & 0xF) >>> 2 ; + new_slen[3] = (scalefac_comp & 3); + si.ch[ch].gr[gr].preflag = 0; + blocknumber = 0; + + } else if (scalefac_comp < 500) { + + new_slen[0] = ((scalefac_comp - 400) >>> 2) / 5 ; + new_slen[1] = ((scalefac_comp - 400) >>> 2) % 5 ; + new_slen[2] = (scalefac_comp - 400 ) & 3 ; + new_slen[3] = 0; + si.ch[ch].gr[gr].preflag = 0; + blocknumber = 1; + + } else if (scalefac_comp < 512) { + + new_slen[0] = (scalefac_comp - 500 ) / 3 ; + new_slen[1] = (scalefac_comp - 500) % 3 ; + new_slen[2] = 0; + new_slen[3] = 0; + si.ch[ch].gr[gr].preflag = 1; + blocknumber = 2; + } + } + + if((((mode_ext == 1) || (mode_ext == 3)) && (ch == 1))) + { + int_scalefac_comp = scalefac_comp >>> 1; + + if (int_scalefac_comp < 180) + { + new_slen[0] = int_scalefac_comp / 36 ; + new_slen[1] = (int_scalefac_comp % 36 ) / 6 ; + new_slen[2] = (int_scalefac_comp % 36) % 6; + new_slen[3] = 0; + si.ch[ch].gr[gr].preflag = 0; + blocknumber = 3; + } else if (int_scalefac_comp < 244) { + new_slen[0] = ((int_scalefac_comp - 180 ) & 0x3F) >>> 4 ; + new_slen[1] = ((int_scalefac_comp - 180) & 0xF) >>> 2 ; + new_slen[2] = (int_scalefac_comp - 180 ) & 3 ; + new_slen[3] = 0; + si.ch[ch].gr[gr].preflag = 0; + blocknumber = 4; + } else if (int_scalefac_comp < 255) { + new_slen[0] = (int_scalefac_comp - 244 ) / 3 ; + new_slen[1] = (int_scalefac_comp - 244 ) % 3 ; + new_slen[2] = 0 ; + new_slen[3] = 0; + si.ch[ch].gr[gr].preflag = 0; + blocknumber = 5; + } + } + + for (int x=0; x<45; x++) // why 45, not 54? + scalefac_buffer[x] = 0; + + m = 0; + for (int i=0; i<4;i++) { + for (int j = 0; j < nr_of_sfb_block[blocknumber][blocktypenumber][i]; + j++) + { + scalefac_buffer[m] = (new_slen[i] == 0) ? 0 : + br.hgetbits(new_slen[i]); + m++; + + } // for (unint32 j ... + } // for (uint32 i ... + } + + /** + * + */ + private void get_LSF_scale_factors(int ch, int gr) + { + int m = 0; + int sfb, window; + gr_info_s gr_info = (si.ch[ch].gr[gr]); + + get_LSF_scale_data(ch, gr); + + if ((gr_info.window_switching_flag != 0) && (gr_info.block_type == 2)) { + if (gr_info.mixed_block_flag != 0) { // MIXED + for (sfb = 0; sfb < 8; sfb++) + { + scalefac[ch].l[sfb] = scalefac_buffer[m]; + m++; + } + for (sfb = 3; sfb < 12; sfb++) { + for (window=0; window<3; window++) + { + scalefac[ch].s[window][sfb] = scalefac_buffer[m]; + m++; + } + } + for (window=0; window<3; window++) + scalefac[ch].s[window][12] = 0; + + } else { // SHORT + + for (sfb = 0; sfb < 12; sfb++) { + for (window=0; window<3; window++) + { + scalefac[ch].s[window][sfb] = scalefac_buffer[m]; + m++; + } + } + + for (window=0; window<3; window++) + scalefac[ch].s[window][12] = 0; + } + } else { // LONG types 0,1,3 + + for (sfb = 0; sfb < 21; sfb++) { + scalefac[ch].l[sfb] = scalefac_buffer[m]; + m++; + } + scalefac[ch].l[21] = 0; // Jeff + scalefac[ch].l[22] = 0; + } + } + + /** + * + */ + int[] x = {0}; + int[] y = {0}; + int[] v = {0}; + int[] w = {0}; + private void huffman_decode(int ch, int gr) + { + x[0] = 0; + y[0] = 0; + v[0] = 0; + w[0] = 0; + + int part2_3_end = part2_start + si.ch[ch].gr[gr].part2_3_length; + int num_bits; + int region1Start; + int region2Start; + int index; + + int buf, buf1; + + huffcodetab h; + + // Find region boundary for short block case + + if ( ((si.ch[ch].gr[gr].window_switching_flag) != 0) && + (si.ch[ch].gr[gr].block_type == 2) ) { + + // Region2. + //MS: Extrahandling for 8KHZ + region1Start = (sfreq == 8) ? 72 : 36; // sfb[9/3]*3=36 or in case 8KHZ = 72 + region2Start = 576; // No Region2 for short block case + + } else { // Find region boundary for long block case + + buf = si.ch[ch].gr[gr].region0_count + 1; + buf1 = buf + si.ch[ch].gr[gr].region1_count + 1; + + if(buf1 > sfBandIndex[sfreq].l.length - 1) buf1 = sfBandIndex[sfreq].l.length - 1; + + region1Start = sfBandIndex[sfreq].l[buf]; + region2Start = sfBandIndex[sfreq].l[buf1]; /* MI */ + } + + index = 0; + // Read bigvalues area + for (int i=0; i<(si.ch[ch].gr[gr].big_values<<1); i+=2) { + if (i= is_1d.length) System.out.println("i0="+i+"/"+(si.ch[ch].gr[gr].big_values<<1)+" Index="+index+" is_1d="+is_1d.length); + + is_1d[index++] = x[0]; + is_1d[index++] = y[0]; + + CheckSumHuff = CheckSumHuff + x[0] + y[0]; + // System.out.println("x = "+x[0]+" y = "+y[0]); + } + + // Read count1 area + h = huffcodetab.ht[si.ch[ch].gr[gr].count1table_select+32]; + num_bits = br.hsstell(); + + while ((num_bits < part2_3_end) && (index < 576)) { + + huffcodetab.huffman_decoder(h, x, y, v, w, br); + + is_1d[index++] = v[0]; + is_1d[index++] = w[0]; + is_1d[index++] = x[0]; + is_1d[index++] = y[0]; + CheckSumHuff = CheckSumHuff + v[0] + w[0] + x[0] + y[0]; + // System.out.println("v = "+v[0]+" w = "+w[0]); + // System.out.println("x = "+x[0]+" y = "+y[0]); + num_bits = br.hsstell(); + } + + if (num_bits > part2_3_end) { + br.rewindNbits(num_bits - part2_3_end); + index-=4; + } + + num_bits = br.hsstell(); + + // Dismiss stuffing bits + if (num_bits < part2_3_end) + br.hgetbits(part2_3_end - num_bits); + + // Zero out rest + + if (index < 576) + nonzero[ch] = index; + else + nonzero[ch] = 576; + + if (index < 0) index = 0; + + // may not be necessary + for (; index<576; index++) + is_1d[index] = 0; + } + + /** + * + */ + private void i_stereo_k_values(int is_pos, int io_type, int i) + { + if (is_pos == 0) { + k[0][i] = 1.0f; + k[1][i] = 1.0f; + } else if ((is_pos & 1) != 0) { + k[0][i] = io[io_type][(is_pos + 1) >>> 1]; + k[1][i] = 1.0f; + } else { + k[0][i] = 1.0f; + k[1][i] = io[io_type][is_pos >>> 1]; + } + } + + /** + * + */ + private void dequantize_sample(float xr[][], int ch, int gr) + { + gr_info_s gr_info = (si.ch[ch].gr[gr]); + int cb=0; + int next_cb_boundary; + int cb_begin = 0; + int cb_width = 0; + int index=0, t_index, j; + float g_gain; + float[][] xr_1d = xr; + + // choose correct scalefactor band per block type, initalize boundary + + if ((gr_info.window_switching_flag !=0 ) && (gr_info.block_type == 2) ) { + if (gr_info.mixed_block_flag != 0) + next_cb_boundary=sfBandIndex[sfreq].l[1]; // LONG blocks: 0,1,3 + else { + cb_width = sfBandIndex[sfreq].s[1]; + next_cb_boundary = (cb_width << 2) - cb_width; + cb_begin = 0; + } + } else { + next_cb_boundary=sfBandIndex[sfreq].l[1]; // LONG blocks: 0,1,3 + } + + // Compute overall (global) scaling. + + g_gain = (float) Math.pow(2.0 , (0.25 * (gr_info.global_gain - 210.0))); + + for (j=0; j 0) xr_1d[quotien][reste] = g_gain * t_43[abv]; + else + { + if (-abv < t_43.length) xr_1d[quotien][reste] = -g_gain * t_43[-abv]; + else xr_1d[quotien][reste] = -g_gain * (float)Math.pow(-abv, d43); + } + } + else + { + if (is_1d[j] > 0) xr_1d[quotien][reste] = g_gain * (float)Math.pow(abv, d43); + else xr_1d[quotien][reste] = -g_gain * (float)Math.pow(-abv, d43); + } + } + } + + // apply formula per block type + for (j=0; j= 36)) )) + { + + t_index = (index - cb_begin) / cb_width; + /* xr[sb][ss] *= pow(2.0, ((-2.0 * gr_info.subblock_gain[t_index]) + -(0.5 * (1.0 + gr_info.scalefac_scale) + * scalefac[ch].s[t_index][cb]))); */ + int idx = scalefac[ch].s[t_index][cb] + << gr_info.scalefac_scale; + idx += (gr_info.subblock_gain[t_index] << 2); + + xr_1d[quotien][reste] *= two_to_negative_half_pow[idx]; + + } else { // LONG block types 0,1,3 & 1st 2 subbands of switched blocks + /* xr[sb][ss] *= pow(2.0, -0.5 * (1.0+gr_info.scalefac_scale) + * (scalefac[ch].l[cb] + + gr_info.preflag * pretab[cb])); */ + int idx = scalefac[ch].l[cb]; + + if (gr_info.preflag != 0) + idx += pretab[cb]; + + idx = idx << gr_info.scalefac_scale; + xr_1d[quotien][reste] *= two_to_negative_half_pow[idx]; + } + index++; + } + + for (j=nonzero[ch]; j<576; j++) + { + // Modif E.B 02/22/99 + int reste = j % SSLIMIT; + int quotien = (int) ((j-reste)/SSLIMIT); + if(reste < 0) reste = 0; + if(quotien < 0) quotien = 0; + xr_1d[quotien][reste] = 0.0f; + } + + return; + } + + /** + * + */ + private void reorder(float xr[][], int ch, int gr) + { + gr_info_s gr_info = (si.ch[ch].gr[gr]); + int freq, freq3; + int index; + int sfb, sfb_start, sfb_lines; + int src_line, des_line; + float[][] xr_1d = xr; + + if ((gr_info.window_switching_flag !=0) && (gr_info.block_type == 2)) { + + for(index=0; index<576; index++) + out_1d[index] = 0.0f; + + if (gr_info.mixed_block_flag !=0 ) { + // NO REORDER FOR LOW 2 SUBBANDS + for (index = 0; index < 36; index++) + { + // Modif E.B 02/22/99 + int reste = index % SSLIMIT; + int quotien = (int) ((index-reste)/SSLIMIT); + out_1d[index] = xr_1d[quotien][reste]; + } + // REORDERING FOR REST SWITCHED SHORT + /*for( sfb=3,sfb_start=sfBandIndex[sfreq].s[3], + sfb_lines=sfBandIndex[sfreq].s[4] - sfb_start; + sfb < 13; sfb++,sfb_start = sfBandIndex[sfreq].s[sfb], + sfb_lines = sfBandIndex[sfreq].s[sfb+1] - sfb_start ) + {*/ + for( sfb=3; sfb < 13; sfb++) + { + //System.out.println("sfreq="+sfreq+" sfb="+sfb+" sfBandIndex="+sfBandIndex.length+" sfBandIndex[sfreq].s="+sfBandIndex[sfreq].s.length); + sfb_start = sfBandIndex[sfreq].s[sfb]; + sfb_lines = sfBandIndex[sfreq].s[sfb+1] - sfb_start; + + int sfb_start3 = (sfb_start << 2) - sfb_start; + + for(freq=0, freq3=0; freq=3; sfb-- ) { + i = sfBandIndex[sfreq].s[sfb]; + lines = sfBandIndex[sfreq].s[sfb+1] - i; + i = (i << 2) - i + (j+1) * lines - 1; + + while (lines > 0) { + if (ro[1][i/18][i%18] != 0.0f) { + // MDM: in java, array access is very slow. + // Is quicker to compute div and mod values. + //if (ro[1][ss_div[i]][ss_mod[i]] != 0.0f) { + sfbcnt = sfb; + sfb = -10; + lines = -10; + } + + lines--; + i--; + + } // while (lines > 0) + + } // for (sfb=12 ... + sfb = sfbcnt + 1; + + if (sfb > max_sfb) + max_sfb = sfb; + + while(sfb < 12) { + temp = sfBandIndex[sfreq].s[sfb]; + sb = sfBandIndex[sfreq].s[sfb+1] - temp; + i = (temp << 2) - temp + j * sb; + + for ( ; sb > 0; sb--) { + is_pos[i] = scalefac[1].s[j][sfb]; + if (is_pos[i] != 7) + if (lsf) + i_stereo_k_values(is_pos[i], io_type, i); + else + is_ratio[i] = TAN12[is_pos[i]]; + + i++; + } // for (; sb>0... + sfb++; + } // while (sfb < 12) + sfb = sfBandIndex[sfreq].s[10]; + sb = sfBandIndex[sfreq].s[11] - sfb; + sfb = (sfb << 2) - sfb + j * sb; + temp = sfBandIndex[sfreq].s[11]; + sb = sfBandIndex[sfreq].s[12] - temp; + i = (temp << 2) - temp + j * sb; + + for (; sb > 0; sb--) { + is_pos[i] = is_pos[sfb]; + + if (lsf) { + k[0][i] = k[0][sfb]; + k[1][i] = k[1][sfb]; + } else { + is_ratio[i] = is_ratio[sfb]; + } + i++; + } // for (; sb > 0 ... + } + if (max_sfb <= 3) { + i = 2; + ss = 17; + sb = -1; + while (i >= 0) { + if (ro[1][i][ss] != 0.0f) { + sb = (i<<4) + (i<<1) + ss; + i = -1; + } else { + ss--; + if (ss < 0) { + i--; + ss = 17; + } + } // if (ro ... + } // while (i>=0) + i = 0; + while (sfBandIndex[sfreq].l[i] <= sb) + i++; + sfb = i; + i = sfBandIndex[sfreq].l[i]; + for (; sfb<8; sfb++) { + sb = sfBandIndex[sfreq].l[sfb+1]-sfBandIndex[sfreq].l[sfb]; + for (; sb>0; sb--) { + is_pos[i] = scalefac[1].l[sfb]; + if (is_pos[i] != 7) + if (lsf) + i_stereo_k_values(is_pos[i], io_type, i); + else + is_ratio[i] = TAN12[is_pos[i]]; + i++; + } // for (; sb>0 ... + } // for (; sfb<8 ... + } // for (j=0 ... + } else { // if (gr_info.mixed_block_flag) + for (int j=0; j<3; j++) { + int sfbcnt; + sfbcnt = -1; + for( sfb=12; sfb >=0; sfb-- ) + { + temp = sfBandIndex[sfreq].s[sfb]; + lines = sfBandIndex[sfreq].s[sfb+1] - temp; + i = (temp << 2) - temp + (j+1) * lines - 1; + + while (lines > 0) { + if (ro[1][i/18][i%18] != 0.0f) { + // MDM: in java, array access is very slow. + // Is quicker to compute div and mod values. + //if (ro[1][ss_div[i]][ss_mod[i]] != 0.0f) { + sfbcnt = sfb; + sfb = -10; + lines = -10; + } + lines--; + i--; + } // while (lines > 0) */ + + } // for (sfb=12 ... + sfb = sfbcnt + 1; + while(sfb<12) { + temp = sfBandIndex[sfreq].s[sfb]; + sb = sfBandIndex[sfreq].s[sfb+1] - temp; + i = (temp << 2) - temp + j * sb; + for ( ; sb > 0; sb--) { + is_pos[i] = scalefac[1].s[j][sfb]; + if (is_pos[i] != 7) + if (lsf) + i_stereo_k_values(is_pos[i], io_type, i); + else + is_ratio[i] = TAN12[is_pos[i]]; + i++; + } // for (; sb>0 ... + sfb++; + } // while (sfb<12) + + temp = sfBandIndex[sfreq].s[10]; + temp2= sfBandIndex[sfreq].s[11]; + sb = temp2 - temp; + sfb = (temp << 2) - temp + j * sb; + sb = sfBandIndex[sfreq].s[12] - temp2; + i = (temp2 << 2) - temp2 + j * sb; + + for (; sb>0; sb--) { + is_pos[i] = is_pos[sfb]; + + if (lsf) { + k[0][i] = k[0][sfb]; + k[1][i] = k[1][sfb]; + } else { + is_ratio[i] = is_ratio[sfb]; + } + i++; + } // for (; sb>0 ... + } // for (sfb=12 + } // for (j=0 ... + } else { // if (gr_info.window_switching_flag ... + i = 31; + ss = 17; + sb = 0; + while (i >= 0) { + if (ro[1][i][ss] != 0.0f) { + sb = (i<<4) + (i<<1) + ss; + i = -1; + } else { + ss--; + if (ss < 0) { + i--; + ss = 17; + } + } + } + i = 0; + while (sfBandIndex[sfreq].l[i] <= sb) + i++; + + sfb = i; + i = sfBandIndex[sfreq].l[i]; + for (; sfb<21; sfb++) { + sb = sfBandIndex[sfreq].l[sfb+1] - sfBandIndex[sfreq].l[sfb]; + for (; sb > 0; sb--) { + is_pos[i] = scalefac[1].l[sfb]; + if (is_pos[i] != 7) + if (lsf) + i_stereo_k_values(is_pos[i], io_type, i); + else + is_ratio[i] = TAN12[is_pos[i]]; + i++; + } + } + sfb = sfBandIndex[sfreq].l[20]; + for (sb = 576 - sfBandIndex[sfreq].l[21]; (sb > 0) && (i<576); sb--) + { + is_pos[i] = is_pos[sfb]; // error here : i >=576 + + if (lsf) { + k[0][i] = k[0][sfb]; + k[1][i] = k[1][sfb]; + } else { + is_ratio[i] = is_ratio[sfb]; + } + i++; + } // if (gr_info.mixed_block_flag) + } // if (gr_info.window_switching_flag ... + } // if (i_stereo) + + i = 0; + for(sb=0;sb 32767.0f) ? 32767 : + ((sample < -32768.0f) ? -32768 : + (short) sample)); + } + + /** + * Write the samples to the file or directly to the audio hardware. + */ + public abstract void write_buffer(int val); + public abstract void close(); + + /** + * Clears all data in the buffer (for seeking). + */ + public abstract void clear_buffer(); + + /** + * Notify the buffer that the user has stopped the stream. + */ + public abstract void set_stop_flag(); +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/OutputChannels.java b/src/lwjgl/java/javazoom/jl/decoder/OutputChannels.java new file mode 100644 index 0000000..7197306 --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/OutputChannels.java @@ -0,0 +1,143 @@ +/* + * 11/19/04 1.0 moved to LGPL. + * 12/12/99 Initial implementation. mdm@techie.com. + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + +package javazoom.jl.decoder; + + +/** + * A Type-safe representation of the the supported output channel + * constants. + * + * This class is immutable and, hence, is thread safe. + * + * @author Mat McGowan 12/12/99 + * @since 0.0.7 + */ +public class OutputChannels +{ + /** + * Flag to indicate output should include both channels. + */ + public static final int BOTH_CHANNELS = 0; + + /** + * Flag to indicate output should include the left channel only. + */ + public static final int LEFT_CHANNEL = 1; + + /** + * Flag to indicate output should include the right channel only. + */ + public static final int RIGHT_CHANNEL = 2; + + /** + * Flag to indicate output is mono. + */ + public static final int DOWNMIX_CHANNELS = 3; + + + public static final OutputChannels LEFT = new OutputChannels(LEFT_CHANNEL); + public static final OutputChannels RIGHT = new OutputChannels(RIGHT_CHANNEL); + public static final OutputChannels BOTH = new OutputChannels(BOTH_CHANNELS); + public static final OutputChannels DOWNMIX = new OutputChannels(DOWNMIX_CHANNELS); + + + private /*final*/ int outputChannels; + + /** + * Creates an OutputChannels instance + * corresponding to the given channel code. + * + * @param code one of the OutputChannels channel code constants. + * + * @throws IllegalArgumentException if code is not a valid + * channel code. + */ + public static OutputChannels fromInt(int code) + { + switch (code) + { + case LEFT_CHANNEL: + return LEFT; + case RIGHT_CHANNEL: + return RIGHT; + case BOTH_CHANNELS: + return BOTH; + case DOWNMIX_CHANNELS: + return DOWNMIX; + default: + throw new IllegalArgumentException("Invalid channel code: "+code); + } + } + + private OutputChannels(int channels) + { + outputChannels = channels; + + if (channels<0 || channels>3) + throw new IllegalArgumentException("channels"); + } + + /** + * Retrieves the code representing the desired output channels. + * Will be one of LEFT_CHANNEL, RIGHT_CHANNEL, BOTH_CHANNELS + * or DOWNMIX_CHANNELS. + * + * @return the channel code represented by this instance. + */ + public int getChannelsOutputCode() + { + return outputChannels; + } + + /** + * Retrieves the number of output channels represented + * by this channel output type. + * + * @return The number of output channels for this channel output + * type. This will be 2 for BOTH_CHANNELS only, and 1 + * for all other types. + */ + public int getChannelCount() + { + int count = (outputChannels==BOTH_CHANNELS) ? 2 : 1; + return count; + } + + + public boolean equals(Object o) + { + boolean equals = false; + + if (o instanceof OutputChannels) + { + OutputChannels oc = (OutputChannels)o; + equals = (oc.outputChannels == outputChannels); + } + + return equals; + } + + public int hashCode() + { + return outputChannels; + } + +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/SampleBuffer.java b/src/lwjgl/java/javazoom/jl/decoder/SampleBuffer.java new file mode 100644 index 0000000..00b9f1b --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/SampleBuffer.java @@ -0,0 +1,132 @@ +/* + * 11/19/04 1.0 moved to LGPL. + * + * 12/12/99 Initial Version based on FileObuffer. mdm@techie.com. + * + * FileObuffer: + * 15/02/99 Java Conversion by E.B ,javalayer@javazoom.net + * + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + +package javazoom.jl.decoder; + +/** + * The SampleBuffer class implements an output buffer + * that provides storage for a fixed size block of samples. + */ +public class SampleBuffer extends Obuffer +{ + private short[] buffer; + private int[] bufferp; + private int channels; + private int frequency; + + /** + * Constructor + */ + public SampleBuffer(int sample_frequency, int number_of_channels) + { + buffer = new short[OBUFFERSIZE]; + bufferp = new int[MAXCHANNELS]; + channels = number_of_channels; + frequency = sample_frequency; + + for (int i = 0; i < number_of_channels; ++i) + bufferp[i] = (short)i; + + } + + public int getChannelCount() + { + return this.channels; + } + + public int getSampleFrequency() + { + return this.frequency; + } + + public short[] getBuffer() + { + return this.buffer; + } + + public int getBufferLength() + { + return bufferp[0]; + } + + /** + * Takes a 16 Bit PCM sample. + */ + public void append(int channel, short value) + { + buffer[bufferp[channel]] = value; + bufferp[channel] += channels; + } + + public void appendSamples(int channel, float[] f) + { + int pos = bufferp[channel]; + + short s; + float fs; + for (int i=0; i<32;) + { + fs = f[i++]; + fs = (fs>32767.0f ? 32767.0f + : (fs < -32767.0f ? -32767.0f : fs)); + + s = (short)fs; + buffer[pos] = s; + pos += channels; + } + + bufferp[channel] = pos; + } + + + /** + * Write the samples to the file (Random Access). + */ + public void write_buffer(int val) + { + + //for (int i = 0; i < channels; ++i) + // bufferp[i] = (short)i; + + } + + public void close() + {} + + /** + * + */ + public void clear_buffer() + { + for (int i = 0; i < channels; ++i) + bufferp[i] = (short)i; + } + + /** + * + */ + public void set_stop_flag() + {} +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/Source.java b/src/lwjgl/java/javazoom/jl/decoder/Source.java new file mode 100644 index 0000000..9d6a5d7 --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/Source.java @@ -0,0 +1,49 @@ +/* + * 11/19/04 1.0 moved to LGPL. + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + +package javazoom.jl.decoder; + +import java.io.IOException; + +/** + * Work in progress. + * + * Class to describe a seekable data source. + * + */ +public interface Source +{ + + public static final long LENGTH_UNKNOWN = -1; + + public int read(byte[] b, int offs, int len) + throws IOException; + + + public boolean willReadBlock(); + + public boolean isSeekable(); + + public long length(); + + public long tell(); + + public long seek(long pos); + +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/SynthesisFilter.java b/src/lwjgl/java/javazoom/jl/decoder/SynthesisFilter.java new file mode 100644 index 0000000..ea6e1a7 --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/SynthesisFilter.java @@ -0,0 +1,1815 @@ +/* + * 11/19/04 1.0 moved to LGPL. + * + * 04/01/00 Fixes for running under build 23xx Microsoft JVM. mdm. + * + * 19/12/99 Performance improvements to compute_pcm_samples(). + * Mat McGowan. mdm@techie.com. + * + * 16/02/99 Java Conversion by E.B , javalayer@javazoom.net + * + * @(#) synthesis_filter.h 1.8, last edit: 6/15/94 16:52:00 + * @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de) + * @(#) Berlin University of Technology + * + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ +package javazoom.jl.decoder; + +import java.io.IOException; + +/** + * A class for the synthesis filter bank. + * This class does a fast downsampling from 32, 44.1 or 48 kHz to 8 kHz, if ULAW is defined. + * Frequencies above 4 kHz are removed by ignoring higher subbands. + */ +final class SynthesisFilter +{ + private float[] v1; + private float[] v2; + private float[] actual_v; // v1 or v2 + private int actual_write_pos; // 0-15 + private float[] samples; // 32 new subband samples + private int channel; + private float scalefactor; + private float[] eq; + + /** + * Quality value for controlling CPU usage/quality tradeoff. + */ + /* + private int quality; + + private int v_inc; + + + + public static final int HIGH_QUALITY = 1; + public static final int MEDIUM_QUALITY = 2; + public static final int LOW_QUALITY = 4; + */ + + /** + * Constructor. + * + * The scalefactor scales the calculated float pcm samples to short values + * (raw pcm samples are in [-1.0, 1.0], if no violations occur). + */ + public SynthesisFilter(int channelnumber, float factor, float[] eq0) + { + if (d==null) + { + d = load_d(); + d16 = splitArray(d, 16); + } + + v1 = new float[512]; + v2 = new float[512]; + samples = new float[32]; + channel = channelnumber; + scalefactor = factor; + setEQ(eq); + //setQuality(HIGH_QUALITY); + + reset(); + } + + public void setEQ(float[] eq0) + { + this.eq = eq0; + if (eq==null) + { + eq = new float[32]; + for (int i=0; i<32; i++) + eq[i] = 1.0f; + } + if (eq.length<32) + { + throw new IllegalArgumentException("eq0"); + } + + } + + /* + private void setQuality(int quality0) + { + switch (quality0) + { + case HIGH_QUALITY: + case MEDIUM_QUALITY: + case LOW_QUALITY: + v_inc = 16 * quality0; + quality = quality0; + break; + default : + throw new IllegalArgumentException("Unknown quality value"); + } + } + + public int getQuality() + { + return quality; + } + */ + + /** + * Reset the synthesis filter. + */ + public void reset() + { + //float[] floatp; + // float[] floatp2; + + // initialize v1[] and v2[]: + //for (floatp = v1 + 512, floatp2 = v2 + 512; floatp > v1; ) + // *--floatp = *--floatp2 = 0.0; + for (int p=0;p<512;p++) + v1[p] = v2[p] = 0.0f; + + // initialize samples[]: + //for (floatp = samples + 32; floatp > samples; ) + // *--floatp = 0.0; + for (int p2=0;p2<32;p2++) + samples[p2] = 0.0f; + + actual_v = v1; + actual_write_pos = 15; + } + + + /** + * Inject Sample. + */ + public void input_sample(float sample, int subbandnumber) + { + samples[subbandnumber] = eq[subbandnumber]*sample; + } + + public void input_samples(float[] s) + { + for (int i=31; i>=0; i--) + { + samples[i] = s[i]*eq[i]; + } + } + + /** + * Compute new values via a fast cosine transform. + */ + private void compute_new_v() + { + // p is fully initialized from x1 + //float[] p = _p; + // pp is fully initialized from p + //float[] pp = _pp; + + //float[] new_v = _new_v; + + //float[] new_v = new float[32]; // new V[0-15] and V[33-48] of Figure 3-A.2 in ISO DIS 11172-3 + //float[] p = new float[16]; + //float[] pp = new float[16]; + + /* + for (int i=31; i>=0; i--) + { + new_v[i] = 0.0f; + } + */ + + float new_v0, new_v1, new_v2, new_v3, new_v4, new_v5, new_v6, new_v7, new_v8, new_v9; + float new_v10, new_v11, new_v12, new_v13, new_v14, new_v15, new_v16, new_v17, new_v18, new_v19; + float new_v20, new_v21, new_v22, new_v23, new_v24, new_v25, new_v26, new_v27, new_v28, new_v29; + float new_v30, new_v31; + + new_v0 = new_v1 = new_v2 = new_v3 = new_v4 = new_v5 = new_v6 = new_v7 = new_v8 = new_v9 = + new_v10 = new_v11 = new_v12 = new_v13 = new_v14 = new_v15 = new_v16 = new_v17 = new_v18 = new_v19 = + new_v20 = new_v21 = new_v22 = new_v23 = new_v24 = new_v25 = new_v26 = new_v27 = new_v28 = new_v29 = + new_v30 = new_v31 = 0.0f; + + +// float[] new_v = new float[32]; // new V[0-15] and V[33-48] of Figure 3-A.2 in ISO DIS 11172-3 +// float[] p = new float[16]; +// float[] pp = new float[16]; + + float[] s = samples; + + float s0 = s[0]; + float s1 = s[1]; + float s2 = s[2]; + float s3 = s[3]; + float s4 = s[4]; + float s5 = s[5]; + float s6 = s[6]; + float s7 = s[7]; + float s8 = s[8]; + float s9 = s[9]; + float s10 = s[10]; + float s11 = s[11]; + float s12 = s[12]; + float s13 = s[13]; + float s14 = s[14]; + float s15 = s[15]; + float s16 = s[16]; + float s17 = s[17]; + float s18 = s[18]; + float s19 = s[19]; + float s20 = s[20]; + float s21 = s[21]; + float s22 = s[22]; + float s23 = s[23]; + float s24 = s[24]; + float s25 = s[25]; + float s26 = s[26]; + float s27 = s[27]; + float s28 = s[28]; + float s29 = s[29]; + float s30 = s[30]; + float s31 = s[31]; + + float p0 = s0 + s31; + float p1 = s1 + s30; + float p2 = s2 + s29; + float p3 = s3 + s28; + float p4 = s4 + s27; + float p5 = s5 + s26; + float p6 = s6 + s25; + float p7 = s7 + s24; + float p8 = s8 + s23; + float p9 = s9 + s22; + float p10 = s10 + s21; + float p11 = s11 + s20; + float p12 = s12 + s19; + float p13 = s13 + s18; + float p14 = s14 + s17; + float p15 = s15 + s16; + + float pp0 = p0 + p15; + float pp1 = p1 + p14; + float pp2 = p2 + p13; + float pp3 = p3 + p12; + float pp4 = p4 + p11; + float pp5 = p5 + p10; + float pp6 = p6 + p9; + float pp7 = p7 + p8; + float pp8 = (p0 - p15) * cos1_32; + float pp9 = (p1 - p14) * cos3_32; + float pp10 = (p2 - p13) * cos5_32; + float pp11 = (p3 - p12) * cos7_32; + float pp12 = (p4 - p11) * cos9_32; + float pp13 = (p5 - p10) * cos11_32; + float pp14 = (p6 - p9) * cos13_32; + float pp15 = (p7 - p8) * cos15_32; + + p0 = pp0 + pp7; + p1 = pp1 + pp6; + p2 = pp2 + pp5; + p3 = pp3 + pp4; + p4 = (pp0 - pp7) * cos1_16; + p5 = (pp1 - pp6) * cos3_16; + p6 = (pp2 - pp5) * cos5_16; + p7 = (pp3 - pp4) * cos7_16; + p8 = pp8 + pp15; + p9 = pp9 + pp14; + p10 = pp10 + pp13; + p11 = pp11 + pp12; + p12 = (pp8 - pp15) * cos1_16; + p13 = (pp9 - pp14) * cos3_16; + p14 = (pp10 - pp13) * cos5_16; + p15 = (pp11 - pp12) * cos7_16; + + + pp0 = p0 + p3; + pp1 = p1 + p2; + pp2 = (p0 - p3) * cos1_8; + pp3 = (p1 - p2) * cos3_8; + pp4 = p4 + p7; + pp5 = p5 + p6; + pp6 = (p4 - p7) * cos1_8; + pp7 = (p5 - p6) * cos3_8; + pp8 = p8 + p11; + pp9 = p9 + p10; + pp10 = (p8 - p11) * cos1_8; + pp11 = (p9 - p10) * cos3_8; + pp12 = p12 + p15; + pp13 = p13 + p14; + pp14 = (p12 - p15) * cos1_8; + pp15 = (p13 - p14) * cos3_8; + + p0 = pp0 + pp1; + p1 = (pp0 - pp1) * cos1_4; + p2 = pp2 + pp3; + p3 = (pp2 - pp3) * cos1_4; + p4 = pp4 + pp5; + p5 = (pp4 - pp5) * cos1_4; + p6 = pp6 + pp7; + p7 = (pp6 - pp7) * cos1_4; + p8 = pp8 + pp9; + p9 = (pp8 - pp9) * cos1_4; + p10 = pp10 + pp11; + p11 = (pp10 - pp11) * cos1_4; + p12 = pp12 + pp13; + p13 = (pp12 - pp13) * cos1_4; + p14 = pp14 + pp15; + p15 = (pp14 - pp15) * cos1_4; + + // this is pretty insane coding + float tmp1; + new_v19/*36-17*/ = -(new_v4 = (new_v12 = p7) + p5) - p6; + new_v27/*44-17*/ = -p6 - p7 - p4; + new_v6 = (new_v10 = (new_v14 = p15) + p11) + p13; + new_v17/*34-17*/ = -(new_v2 = p15 + p13 + p9) - p14; + new_v21/*38-17*/ = (tmp1 = -p14 - p15 - p10 - p11) - p13; + new_v29/*46-17*/ = -p14 - p15 - p12 - p8; + new_v25/*42-17*/ = tmp1 - p12; + new_v31/*48-17*/ = -p0; + new_v0 = p1; + new_v23/*40-17*/ = -(new_v8 = p3) - p2; + + p0 = (s0 - s31) * cos1_64; + p1 = (s1 - s30) * cos3_64; + p2 = (s2 - s29) * cos5_64; + p3 = (s3 - s28) * cos7_64; + p4 = (s4 - s27) * cos9_64; + p5 = (s5 - s26) * cos11_64; + p6 = (s6 - s25) * cos13_64; + p7 = (s7 - s24) * cos15_64; + p8 = (s8 - s23) * cos17_64; + p9 = (s9 - s22) * cos19_64; + p10 = (s10 - s21) * cos21_64; + p11 = (s11 - s20) * cos23_64; + p12 = (s12 - s19) * cos25_64; + p13 = (s13 - s18) * cos27_64; + p14 = (s14 - s17) * cos29_64; + p15 = (s15 - s16) * cos31_64; + + + pp0 = p0 + p15; + pp1 = p1 + p14; + pp2 = p2 + p13; + pp3 = p3 + p12; + pp4 = p4 + p11; + pp5 = p5 + p10; + pp6 = p6 + p9; + pp7 = p7 + p8; + pp8 = (p0 - p15) * cos1_32; + pp9 = (p1 - p14) * cos3_32; + pp10 = (p2 - p13) * cos5_32; + pp11 = (p3 - p12) * cos7_32; + pp12 = (p4 - p11) * cos9_32; + pp13 = (p5 - p10) * cos11_32; + pp14 = (p6 - p9) * cos13_32; + pp15 = (p7 - p8) * cos15_32; + + + p0 = pp0 + pp7; + p1 = pp1 + pp6; + p2 = pp2 + pp5; + p3 = pp3 + pp4; + p4 = (pp0 - pp7) * cos1_16; + p5 = (pp1 - pp6) * cos3_16; + p6 = (pp2 - pp5) * cos5_16; + p7 = (pp3 - pp4) * cos7_16; + p8 = pp8 + pp15; + p9 = pp9 + pp14; + p10 = pp10 + pp13; + p11 = pp11 + pp12; + p12 = (pp8 - pp15) * cos1_16; + p13 = (pp9 - pp14) * cos3_16; + p14 = (pp10 - pp13) * cos5_16; + p15 = (pp11 - pp12) * cos7_16; + + + pp0 = p0 + p3; + pp1 = p1 + p2; + pp2 = (p0 - p3) * cos1_8; + pp3 = (p1 - p2) * cos3_8; + pp4 = p4 + p7; + pp5 = p5 + p6; + pp6 = (p4 - p7) * cos1_8; + pp7 = (p5 - p6) * cos3_8; + pp8 = p8 + p11; + pp9 = p9 + p10; + pp10 = (p8 - p11) * cos1_8; + pp11 = (p9 - p10) * cos3_8; + pp12 = p12 + p15; + pp13 = p13 + p14; + pp14 = (p12 - p15) * cos1_8; + pp15 = (p13 - p14) * cos3_8; + + + p0 = pp0 + pp1; + p1 = (pp0 - pp1) * cos1_4; + p2 = pp2 + pp3; + p3 = (pp2 - pp3) * cos1_4; + p4 = pp4 + pp5; + p5 = (pp4 - pp5) * cos1_4; + p6 = pp6 + pp7; + p7 = (pp6 - pp7) * cos1_4; + p8 = pp8 + pp9; + p9 = (pp8 - pp9) * cos1_4; + p10 = pp10 + pp11; + p11 = (pp10 - pp11) * cos1_4; + p12 = pp12 + pp13; + p13 = (pp12 - pp13) * cos1_4; + p14 = pp14 + pp15; + p15 = (pp14 - pp15) * cos1_4; + + + // manually doing something that a compiler should handle sucks + // coding like this is hard to read + float tmp2; + new_v5 = (new_v11 = (new_v13 = (new_v15 = p15) + p7) + p11) + + p5 + p13; + new_v7 = (new_v9 = p15 + p11 + p3) + p13; + new_v16/*33-17*/ = -(new_v1 = (tmp1 = p13 + p15 + p9) + p1) - p14; + new_v18/*35-17*/ = -(new_v3 = tmp1 + p5 + p7) - p6 - p14; + + new_v22/*39-17*/ = (tmp1 = -p10 - p11 - p14 - p15) + - p13 - p2 - p3; + new_v20/*37-17*/ = tmp1 - p13 - p5 - p6 - p7; + new_v24/*41-17*/ = tmp1 - p12 - p2 - p3; + new_v26/*43-17*/ = tmp1 - p12 - (tmp2 = p4 + p6 + p7); + new_v30/*47-17*/ = (tmp1 = -p8 - p12 - p14 - p15) - p0; + new_v28/*45-17*/ = tmp1 - tmp2; + + // insert V[0-15] (== new_v[0-15]) into actual v: + // float[] x2 = actual_v + actual_write_pos; + float dest[] = actual_v; + + int pos = actual_write_pos; + + dest[0 + pos] = new_v0; + dest[16 + pos] = new_v1; + dest[32 + pos] = new_v2; + dest[48 + pos] = new_v3; + dest[64 + pos] = new_v4; + dest[80 + pos] = new_v5; + dest[96 + pos] = new_v6; + dest[112 + pos] = new_v7; + dest[128 + pos] = new_v8; + dest[144 + pos] = new_v9; + dest[160 + pos] = new_v10; + dest[176 + pos] = new_v11; + dest[192 + pos] = new_v12; + dest[208 + pos] = new_v13; + dest[224 + pos] = new_v14; + dest[240 + pos] = new_v15; + + // V[16] is always 0.0: + dest[256 + pos] = 0.0f; + + // insert V[17-31] (== -new_v[15-1]) into actual v: + dest[272 + pos] = -new_v15; + dest[288 + pos] = -new_v14; + dest[304 + pos] = -new_v13; + dest[320 + pos] = -new_v12; + dest[336 + pos] = -new_v11; + dest[352 + pos] = -new_v10; + dest[368 + pos] = -new_v9; + dest[384 + pos] = -new_v8; + dest[400 + pos] = -new_v7; + dest[416 + pos] = -new_v6; + dest[432 + pos] = -new_v5; + dest[448 + pos] = -new_v4; + dest[464 + pos] = -new_v3; + dest[480 + pos] = -new_v2; + dest[496 + pos] = -new_v1; + + // insert V[32] (== -new_v[0]) into other v: + dest = (actual_v==v1) ? v2 : v1; + + dest[0 + pos] = -new_v0; + // insert V[33-48] (== new_v[16-31]) into other v: + dest[16 + pos] = new_v16; + dest[32 + pos] = new_v17; + dest[48 + pos] = new_v18; + dest[64 + pos] = new_v19; + dest[80 + pos] = new_v20; + dest[96 + pos] = new_v21; + dest[112 + pos] = new_v22; + dest[128 + pos] = new_v23; + dest[144 + pos] = new_v24; + dest[160 + pos] = new_v25; + dest[176 + pos] = new_v26; + dest[192 + pos] = new_v27; + dest[208 + pos] = new_v28; + dest[224 + pos] = new_v29; + dest[240 + pos] = new_v30; + dest[256 + pos] = new_v31; + + // insert V[49-63] (== new_v[30-16]) into other v: + dest[272 + pos] = new_v30; + dest[288 + pos] = new_v29; + dest[304 + pos] = new_v28; + dest[320 + pos] = new_v27; + dest[336 + pos] = new_v26; + dest[352 + pos] = new_v25; + dest[368 + pos] = new_v24; + dest[384 + pos] = new_v23; + dest[400 + pos] = new_v22; + dest[416 + pos] = new_v21; + dest[432 + pos] = new_v20; + dest[448 + pos] = new_v19; + dest[464 + pos] = new_v18; + dest[480 + pos] = new_v17; + dest[496 + pos] = new_v16; +/* + } + else + { + v1[0 + actual_write_pos] = -new_v0; + // insert V[33-48] (== new_v[16-31]) into other v: + v1[16 + actual_write_pos] = new_v16; + v1[32 + actual_write_pos] = new_v17; + v1[48 + actual_write_pos] = new_v18; + v1[64 + actual_write_pos] = new_v19; + v1[80 + actual_write_pos] = new_v20; + v1[96 + actual_write_pos] = new_v21; + v1[112 + actual_write_pos] = new_v22; + v1[128 + actual_write_pos] = new_v23; + v1[144 + actual_write_pos] = new_v24; + v1[160 + actual_write_pos] = new_v25; + v1[176 + actual_write_pos] = new_v26; + v1[192 + actual_write_pos] = new_v27; + v1[208 + actual_write_pos] = new_v28; + v1[224 + actual_write_pos] = new_v29; + v1[240 + actual_write_pos] = new_v30; + v1[256 + actual_write_pos] = new_v31; + + // insert V[49-63] (== new_v[30-16]) into other v: + v1[272 + actual_write_pos] = new_v30; + v1[288 + actual_write_pos] = new_v29; + v1[304 + actual_write_pos] = new_v28; + v1[320 + actual_write_pos] = new_v27; + v1[336 + actual_write_pos] = new_v26; + v1[352 + actual_write_pos] = new_v25; + v1[368 + actual_write_pos] = new_v24; + v1[384 + actual_write_pos] = new_v23; + v1[400 + actual_write_pos] = new_v22; + v1[416 + actual_write_pos] = new_v21; + v1[432 + actual_write_pos] = new_v20; + v1[448 + actual_write_pos] = new_v19; + v1[464 + actual_write_pos] = new_v18; + v1[480 + actual_write_pos] = new_v17; + v1[496 + actual_write_pos] = new_v16; + } +*/ + } + + /** + * Compute new values via a fast cosine transform. + */ + private void compute_new_v_old() + { + // p is fully initialized from x1 + //float[] p = _p; + // pp is fully initialized from p + //float[] pp = _pp; + + //float[] new_v = _new_v; + + float[] new_v = new float[32]; // new V[0-15] and V[33-48] of Figure 3-A.2 in ISO DIS 11172-3 + float[] p = new float[16]; + float[] pp = new float[16]; + + + for (int i=31; i>=0; i--) + { + new_v[i] = 0.0f; + } + +// float[] new_v = new float[32]; // new V[0-15] and V[33-48] of Figure 3-A.2 in ISO DIS 11172-3 +// float[] p = new float[16]; +// float[] pp = new float[16]; + + float[] x1 = samples; + + p[0] = x1[0] + x1[31]; + p[1] = x1[1] + x1[30]; + p[2] = x1[2] + x1[29]; + p[3] = x1[3] + x1[28]; + p[4] = x1[4] + x1[27]; + p[5] = x1[5] + x1[26]; + p[6] = x1[6] + x1[25]; + p[7] = x1[7] + x1[24]; + p[8] = x1[8] + x1[23]; + p[9] = x1[9] + x1[22]; + p[10] = x1[10] + x1[21]; + p[11] = x1[11] + x1[20]; + p[12] = x1[12] + x1[19]; + p[13] = x1[13] + x1[18]; + p[14] = x1[14] + x1[17]; + p[15] = x1[15] + x1[16]; + + pp[0] = p[0] + p[15]; + pp[1] = p[1] + p[14]; + pp[2] = p[2] + p[13]; + pp[3] = p[3] + p[12]; + pp[4] = p[4] + p[11]; + pp[5] = p[5] + p[10]; + pp[6] = p[6] + p[9]; + pp[7] = p[7] + p[8]; + pp[8] = (p[0] - p[15]) * cos1_32; + pp[9] = (p[1] - p[14]) * cos3_32; + pp[10] = (p[2] - p[13]) * cos5_32; + pp[11] = (p[3] - p[12]) * cos7_32; + pp[12] = (p[4] - p[11]) * cos9_32; + pp[13] = (p[5] - p[10]) * cos11_32; + pp[14] = (p[6] - p[9]) * cos13_32; + pp[15] = (p[7] - p[8]) * cos15_32; + + p[0] = pp[0] + pp[7]; + p[1] = pp[1] + pp[6]; + p[2] = pp[2] + pp[5]; + p[3] = pp[3] + pp[4]; + p[4] = (pp[0] - pp[7]) * cos1_16; + p[5] = (pp[1] - pp[6]) * cos3_16; + p[6] = (pp[2] - pp[5]) * cos5_16; + p[7] = (pp[3] - pp[4]) * cos7_16; + p[8] = pp[8] + pp[15]; + p[9] = pp[9] + pp[14]; + p[10] = pp[10] + pp[13]; + p[11] = pp[11] + pp[12]; + p[12] = (pp[8] - pp[15]) * cos1_16; + p[13] = (pp[9] - pp[14]) * cos3_16; + p[14] = (pp[10] - pp[13]) * cos5_16; + p[15] = (pp[11] - pp[12]) * cos7_16; + + + pp[0] = p[0] + p[3]; + pp[1] = p[1] + p[2]; + pp[2] = (p[0] - p[3]) * cos1_8; + pp[3] = (p[1] - p[2]) * cos3_8; + pp[4] = p[4] + p[7]; + pp[5] = p[5] + p[6]; + pp[6] = (p[4] - p[7]) * cos1_8; + pp[7] = (p[5] - p[6]) * cos3_8; + pp[8] = p[8] + p[11]; + pp[9] = p[9] + p[10]; + pp[10] = (p[8] - p[11]) * cos1_8; + pp[11] = (p[9] - p[10]) * cos3_8; + pp[12] = p[12] + p[15]; + pp[13] = p[13] + p[14]; + pp[14] = (p[12] - p[15]) * cos1_8; + pp[15] = (p[13] - p[14]) * cos3_8; + + p[0] = pp[0] + pp[1]; + p[1] = (pp[0] - pp[1]) * cos1_4; + p[2] = pp[2] + pp[3]; + p[3] = (pp[2] - pp[3]) * cos1_4; + p[4] = pp[4] + pp[5]; + p[5] = (pp[4] - pp[5]) * cos1_4; + p[6] = pp[6] + pp[7]; + p[7] = (pp[6] - pp[7]) * cos1_4; + p[8] = pp[8] + pp[9]; + p[9] = (pp[8] - pp[9]) * cos1_4; + p[10] = pp[10] + pp[11]; + p[11] = (pp[10] - pp[11]) * cos1_4; + p[12] = pp[12] + pp[13]; + p[13] = (pp[12] - pp[13]) * cos1_4; + p[14] = pp[14] + pp[15]; + p[15] = (pp[14] - pp[15]) * cos1_4; + + // this is pretty insane coding + float tmp1; + new_v[36-17] = -(new_v[4] = (new_v[12] = p[7]) + p[5]) - p[6]; + new_v[44-17] = -p[6] - p[7] - p[4]; + new_v[6] = (new_v[10] = (new_v[14] = p[15]) + p[11]) + p[13]; + new_v[34-17] = -(new_v[2] = p[15] + p[13] + p[9]) - p[14]; + new_v[38-17] = (tmp1 = -p[14] - p[15] - p[10] - p[11]) - p[13]; + new_v[46-17] = -p[14] - p[15] - p[12] - p[8]; + new_v[42-17] = tmp1 - p[12]; + new_v[48-17] = -p[0]; + new_v[0] = p[1]; + new_v[40-17] = -(new_v[8] = p[3]) - p[2]; + + p[0] = (x1[0] - x1[31]) * cos1_64; + p[1] = (x1[1] - x1[30]) * cos3_64; + p[2] = (x1[2] - x1[29]) * cos5_64; + p[3] = (x1[3] - x1[28]) * cos7_64; + p[4] = (x1[4] - x1[27]) * cos9_64; + p[5] = (x1[5] - x1[26]) * cos11_64; + p[6] = (x1[6] - x1[25]) * cos13_64; + p[7] = (x1[7] - x1[24]) * cos15_64; + p[8] = (x1[8] - x1[23]) * cos17_64; + p[9] = (x1[9] - x1[22]) * cos19_64; + p[10] = (x1[10] - x1[21]) * cos21_64; + p[11] = (x1[11] - x1[20]) * cos23_64; + p[12] = (x1[12] - x1[19]) * cos25_64; + p[13] = (x1[13] - x1[18]) * cos27_64; + p[14] = (x1[14] - x1[17]) * cos29_64; + p[15] = (x1[15] - x1[16]) * cos31_64; + + + pp[0] = p[0] + p[15]; + pp[1] = p[1] + p[14]; + pp[2] = p[2] + p[13]; + pp[3] = p[3] + p[12]; + pp[4] = p[4] + p[11]; + pp[5] = p[5] + p[10]; + pp[6] = p[6] + p[9]; + pp[7] = p[7] + p[8]; + pp[8] = (p[0] - p[15]) * cos1_32; + pp[9] = (p[1] - p[14]) * cos3_32; + pp[10] = (p[2] - p[13]) * cos5_32; + pp[11] = (p[3] - p[12]) * cos7_32; + pp[12] = (p[4] - p[11]) * cos9_32; + pp[13] = (p[5] - p[10]) * cos11_32; + pp[14] = (p[6] - p[9]) * cos13_32; + pp[15] = (p[7] - p[8]) * cos15_32; + + + p[0] = pp[0] + pp[7]; + p[1] = pp[1] + pp[6]; + p[2] = pp[2] + pp[5]; + p[3] = pp[3] + pp[4]; + p[4] = (pp[0] - pp[7]) * cos1_16; + p[5] = (pp[1] - pp[6]) * cos3_16; + p[6] = (pp[2] - pp[5]) * cos5_16; + p[7] = (pp[3] - pp[4]) * cos7_16; + p[8] = pp[8] + pp[15]; + p[9] = pp[9] + pp[14]; + p[10] = pp[10] + pp[13]; + p[11] = pp[11] + pp[12]; + p[12] = (pp[8] - pp[15]) * cos1_16; + p[13] = (pp[9] - pp[14]) * cos3_16; + p[14] = (pp[10] - pp[13]) * cos5_16; + p[15] = (pp[11] - pp[12]) * cos7_16; + + + pp[0] = p[0] + p[3]; + pp[1] = p[1] + p[2]; + pp[2] = (p[0] - p[3]) * cos1_8; + pp[3] = (p[1] - p[2]) * cos3_8; + pp[4] = p[4] + p[7]; + pp[5] = p[5] + p[6]; + pp[6] = (p[4] - p[7]) * cos1_8; + pp[7] = (p[5] - p[6]) * cos3_8; + pp[8] = p[8] + p[11]; + pp[9] = p[9] + p[10]; + pp[10] = (p[8] - p[11]) * cos1_8; + pp[11] = (p[9] - p[10]) * cos3_8; + pp[12] = p[12] + p[15]; + pp[13] = p[13] + p[14]; + pp[14] = (p[12] - p[15]) * cos1_8; + pp[15] = (p[13] - p[14]) * cos3_8; + + + p[0] = pp[0] + pp[1]; + p[1] = (pp[0] - pp[1]) * cos1_4; + p[2] = pp[2] + pp[3]; + p[3] = (pp[2] - pp[3]) * cos1_4; + p[4] = pp[4] + pp[5]; + p[5] = (pp[4] - pp[5]) * cos1_4; + p[6] = pp[6] + pp[7]; + p[7] = (pp[6] - pp[7]) * cos1_4; + p[8] = pp[8] + pp[9]; + p[9] = (pp[8] - pp[9]) * cos1_4; + p[10] = pp[10] + pp[11]; + p[11] = (pp[10] - pp[11]) * cos1_4; + p[12] = pp[12] + pp[13]; + p[13] = (pp[12] - pp[13]) * cos1_4; + p[14] = pp[14] + pp[15]; + p[15] = (pp[14] - pp[15]) * cos1_4; + + + // manually doing something that a compiler should handle sucks + // coding like this is hard to read + float tmp2; + new_v[5] = (new_v[11] = (new_v[13] = (new_v[15] = p[15]) + p[7]) + p[11]) + + p[5] + p[13]; + new_v[7] = (new_v[9] = p[15] + p[11] + p[3]) + p[13]; + new_v[33-17] = -(new_v[1] = (tmp1 = p[13] + p[15] + p[9]) + p[1]) - p[14]; + new_v[35-17] = -(new_v[3] = tmp1 + p[5] + p[7]) - p[6] - p[14]; + + new_v[39-17] = (tmp1 = -p[10] - p[11] - p[14] - p[15]) + - p[13] - p[2] - p[3]; + new_v[37-17] = tmp1 - p[13] - p[5] - p[6] - p[7]; + new_v[41-17] = tmp1 - p[12] - p[2] - p[3]; + new_v[43-17] = tmp1 - p[12] - (tmp2 = p[4] + p[6] + p[7]); + new_v[47-17] = (tmp1 = -p[8] - p[12] - p[14] - p[15]) - p[0]; + new_v[45-17] = tmp1 - tmp2; + + // insert V[0-15] (== new_v[0-15]) into actual v: + x1 = new_v; + // float[] x2 = actual_v + actual_write_pos; + float[] dest = actual_v; + + dest[0 + actual_write_pos] = x1[0]; + dest[16 + actual_write_pos] = x1[1]; + dest[32 + actual_write_pos] = x1[2]; + dest[48 + actual_write_pos] = x1[3]; + dest[64 + actual_write_pos] = x1[4]; + dest[80 + actual_write_pos] = x1[5]; + dest[96 + actual_write_pos] = x1[6]; + dest[112 + actual_write_pos] = x1[7]; + dest[128 + actual_write_pos] = x1[8]; + dest[144 + actual_write_pos] = x1[9]; + dest[160 + actual_write_pos] = x1[10]; + dest[176 + actual_write_pos] = x1[11]; + dest[192 + actual_write_pos] = x1[12]; + dest[208 + actual_write_pos] = x1[13]; + dest[224 + actual_write_pos] = x1[14]; + dest[240 + actual_write_pos] = x1[15]; + + // V[16] is always 0.0: + dest[256 + actual_write_pos] = 0.0f; + + // insert V[17-31] (== -new_v[15-1]) into actual v: + dest[272 + actual_write_pos] = -x1[15]; + dest[288 + actual_write_pos] = -x1[14]; + dest[304 + actual_write_pos] = -x1[13]; + dest[320 + actual_write_pos] = -x1[12]; + dest[336 + actual_write_pos] = -x1[11]; + dest[352 + actual_write_pos] = -x1[10]; + dest[368 + actual_write_pos] = -x1[9]; + dest[384 + actual_write_pos] = -x1[8]; + dest[400 + actual_write_pos] = -x1[7]; + dest[416 + actual_write_pos] = -x1[6]; + dest[432 + actual_write_pos] = -x1[5]; + dest[448 + actual_write_pos] = -x1[4]; + dest[464 + actual_write_pos] = -x1[3]; + dest[480 + actual_write_pos] = -x1[2]; + dest[496 + actual_write_pos] = -x1[1]; + + // insert V[32] (== -new_v[0]) into other v: + + } + + /** + * Compute PCM Samples. + */ + + private float[] _tmpOut = new float[32]; + + + private void compute_pcm_samples0(Obuffer buffer) + { + final float[] vp = actual_v; + //int inc = v_inc; + final float[] tmpOut = _tmpOut; + int dvp =0; + + // fat chance of having this loop unroll + for( int i=0; i<32; i++) + { + float pcm_sample; + final float[] dp = d16[i]; + pcm_sample = (float)(((vp[0 + dvp] * dp[0]) + + (vp[15 + dvp] * dp[1]) + + (vp[14 + dvp] * dp[2]) + + (vp[13 + dvp] * dp[3]) + + (vp[12 + dvp] * dp[4]) + + (vp[11 + dvp] * dp[5]) + + (vp[10 + dvp] * dp[6]) + + (vp[9 + dvp] * dp[7]) + + (vp[8 + dvp] * dp[8]) + + (vp[7 + dvp] * dp[9]) + + (vp[6 + dvp] * dp[10]) + + (vp[5 + dvp] * dp[11]) + + (vp[4 + dvp] * dp[12]) + + (vp[3 + dvp] * dp[13]) + + (vp[2 + dvp] * dp[14]) + + (vp[1 + dvp] * dp[15]) + ) * scalefactor); + + tmpOut[i] = pcm_sample; + + dvp += 16; + } // for + } + + private void compute_pcm_samples1(Obuffer buffer) + { + final float[] vp = actual_v; + //int inc = v_inc; + final float[] tmpOut = _tmpOut; + int dvp =0; + + // fat chance of having this loop unroll + for( int i=0; i<32; i++) + { + final float[] dp = d16[i]; + float pcm_sample; + + pcm_sample = (float)(((vp[1 + dvp] * dp[0]) + + (vp[0 + dvp] * dp[1]) + + (vp[15 + dvp] * dp[2]) + + (vp[14 + dvp] * dp[3]) + + (vp[13 + dvp] * dp[4]) + + (vp[12 + dvp] * dp[5]) + + (vp[11 + dvp] * dp[6]) + + (vp[10 + dvp] * dp[7]) + + (vp[9 + dvp] * dp[8]) + + (vp[8 + dvp] * dp[9]) + + (vp[7 + dvp] * dp[10]) + + (vp[6 + dvp] * dp[11]) + + (vp[5 + dvp] * dp[12]) + + (vp[4 + dvp] * dp[13]) + + (vp[3 + dvp] * dp[14]) + + (vp[2 + dvp] * dp[15]) + ) * scalefactor); + + tmpOut[i] = pcm_sample; + + dvp += 16; + } // for + } + private void compute_pcm_samples2(Obuffer buffer) + { + final float[] vp = actual_v; + + //int inc = v_inc; + final float[] tmpOut = _tmpOut; + int dvp =0; + + // fat chance of having this loop unroll + for( int i=0; i<32; i++) + { + final float[] dp = d16[i]; + float pcm_sample; + + pcm_sample = (float)(((vp[2 + dvp] * dp[0]) + + (vp[1 + dvp] * dp[1]) + + (vp[0 + dvp] * dp[2]) + + (vp[15 + dvp] * dp[3]) + + (vp[14 + dvp] * dp[4]) + + (vp[13 + dvp] * dp[5]) + + (vp[12 + dvp] * dp[6]) + + (vp[11 + dvp] * dp[7]) + + (vp[10 + dvp] * dp[8]) + + (vp[9 + dvp] * dp[9]) + + (vp[8 + dvp] * dp[10]) + + (vp[7 + dvp] * dp[11]) + + (vp[6 + dvp] * dp[12]) + + (vp[5 + dvp] * dp[13]) + + (vp[4 + dvp] * dp[14]) + + (vp[3 + dvp] * dp[15]) + ) * scalefactor); + + tmpOut[i] = pcm_sample; + + dvp += 16; + } // for + } + + private void compute_pcm_samples3(Obuffer buffer) + { + final float[] vp = actual_v; + + int idx = 0; + //int inc = v_inc; + final float[] tmpOut = _tmpOut; + int dvp =0; + + // fat chance of having this loop unroll + for( int i=0; i<32; i++) + { + final float[] dp = d16[i]; + float pcm_sample; + + pcm_sample = (float)(((vp[3 + dvp] * dp[0]) + + (vp[2 + dvp] * dp[1]) + + (vp[1 + dvp] * dp[2]) + + (vp[0 + dvp] * dp[3]) + + (vp[15 + dvp] * dp[4]) + + (vp[14 + dvp] * dp[5]) + + (vp[13 + dvp] * dp[6]) + + (vp[12 + dvp] * dp[7]) + + (vp[11 + dvp] * dp[8]) + + (vp[10 + dvp] * dp[9]) + + (vp[9 + dvp] * dp[10]) + + (vp[8 + dvp] * dp[11]) + + (vp[7 + dvp] * dp[12]) + + (vp[6 + dvp] * dp[13]) + + (vp[5 + dvp] * dp[14]) + + (vp[4 + dvp] * dp[15]) + ) * scalefactor); + + tmpOut[i] = pcm_sample; + + dvp += 16; + } // for + } + + private void compute_pcm_samples4(Obuffer buffer) + { + final float[] vp = actual_v; + + //int inc = v_inc; + final float[] tmpOut = _tmpOut; + int dvp =0; + + // fat chance of having this loop unroll + for( int i=0; i<32; i++) + { + final float[] dp = d16[i]; + float pcm_sample; + + pcm_sample = (float)(((vp[4 + dvp] * dp[0]) + + (vp[3 + dvp] * dp[1]) + + (vp[2 + dvp] * dp[2]) + + (vp[1 + dvp] * dp[3]) + + (vp[0 + dvp] * dp[4]) + + (vp[15 + dvp] * dp[5]) + + (vp[14 + dvp] * dp[6]) + + (vp[13 + dvp] * dp[7]) + + (vp[12 + dvp] * dp[8]) + + (vp[11 + dvp] * dp[9]) + + (vp[10 + dvp] * dp[10]) + + (vp[9 + dvp] * dp[11]) + + (vp[8 + dvp] * dp[12]) + + (vp[7 + dvp] * dp[13]) + + (vp[6 + dvp] * dp[14]) + + (vp[5 + dvp] * dp[15]) + ) * scalefactor); + + tmpOut[i] = pcm_sample; + + dvp += 16; + } // for + } + + private void compute_pcm_samples5(Obuffer buffer) + { + final float[] vp = actual_v; + + //int inc = v_inc; + final float[] tmpOut = _tmpOut; + int dvp =0; + + // fat chance of having this loop unroll + for( int i=0; i<32; i++) + { + final float[] dp = d16[i]; + float pcm_sample; + + pcm_sample = (float)(((vp[5 + dvp] * dp[0]) + + (vp[4 + dvp] * dp[1]) + + (vp[3 + dvp] * dp[2]) + + (vp[2 + dvp] * dp[3]) + + (vp[1 + dvp] * dp[4]) + + (vp[0 + dvp] * dp[5]) + + (vp[15 + dvp] * dp[6]) + + (vp[14 + dvp] * dp[7]) + + (vp[13 + dvp] * dp[8]) + + (vp[12 + dvp] * dp[9]) + + (vp[11 + dvp] * dp[10]) + + (vp[10 + dvp] * dp[11]) + + (vp[9 + dvp] * dp[12]) + + (vp[8 + dvp] * dp[13]) + + (vp[7 + dvp] * dp[14]) + + (vp[6 + dvp] * dp[15]) + ) * scalefactor); + + tmpOut[i] = pcm_sample; + + dvp += 16; + } // for + } + + private void compute_pcm_samples6(Obuffer buffer) + { + final float[] vp = actual_v; + //int inc = v_inc; + final float[] tmpOut = _tmpOut; + int dvp =0; + + // fat chance of having this loop unroll + for( int i=0; i<32; i++) + { + final float[] dp = d16[i]; + float pcm_sample; + + pcm_sample = (float)(((vp[6 + dvp] * dp[0]) + + (vp[5 + dvp] * dp[1]) + + (vp[4 + dvp] * dp[2]) + + (vp[3 + dvp] * dp[3]) + + (vp[2 + dvp] * dp[4]) + + (vp[1 + dvp] * dp[5]) + + (vp[0 + dvp] * dp[6]) + + (vp[15 + dvp] * dp[7]) + + (vp[14 + dvp] * dp[8]) + + (vp[13 + dvp] * dp[9]) + + (vp[12 + dvp] * dp[10]) + + (vp[11 + dvp] * dp[11]) + + (vp[10 + dvp] * dp[12]) + + (vp[9 + dvp] * dp[13]) + + (vp[8 + dvp] * dp[14]) + + (vp[7 + dvp] * dp[15]) + ) * scalefactor); + + tmpOut[i] = pcm_sample; + + dvp += 16; + } // for + } + + private void compute_pcm_samples7(Obuffer buffer) + { + final float[] vp = actual_v; + + //int inc = v_inc; + final float[] tmpOut = _tmpOut; + int dvp =0; + + // fat chance of having this loop unroll + for( int i=0; i<32; i++) + { + final float[] dp = d16[i]; + float pcm_sample; + + pcm_sample = (float)(((vp[7 + dvp] * dp[0]) + + (vp[6 + dvp] * dp[1]) + + (vp[5 + dvp] * dp[2]) + + (vp[4 + dvp] * dp[3]) + + (vp[3 + dvp] * dp[4]) + + (vp[2 + dvp] * dp[5]) + + (vp[1 + dvp] * dp[6]) + + (vp[0 + dvp] * dp[7]) + + (vp[15 + dvp] * dp[8]) + + (vp[14 + dvp] * dp[9]) + + (vp[13 + dvp] * dp[10]) + + (vp[12 + dvp] * dp[11]) + + (vp[11 + dvp] * dp[12]) + + (vp[10 + dvp] * dp[13]) + + (vp[9 + dvp] * dp[14]) + + (vp[8 + dvp] * dp[15]) + ) * scalefactor); + + tmpOut[i] = pcm_sample; + + dvp += 16; + } // for + } + private void compute_pcm_samples8(Obuffer buffer) + { + final float[] vp = actual_v; + + //int inc = v_inc; + final float[] tmpOut = _tmpOut; + int dvp =0; + + // fat chance of having this loop unroll + for( int i=0; i<32; i++) + { + final float[] dp = d16[i]; + float pcm_sample; + + pcm_sample = (float)(((vp[8 + dvp] * dp[0]) + + (vp[7 + dvp] * dp[1]) + + (vp[6 + dvp] * dp[2]) + + (vp[5 + dvp] * dp[3]) + + (vp[4 + dvp] * dp[4]) + + (vp[3 + dvp] * dp[5]) + + (vp[2 + dvp] * dp[6]) + + (vp[1 + dvp] * dp[7]) + + (vp[0 + dvp] * dp[8]) + + (vp[15 + dvp] * dp[9]) + + (vp[14 + dvp] * dp[10]) + + (vp[13 + dvp] * dp[11]) + + (vp[12 + dvp] * dp[12]) + + (vp[11 + dvp] * dp[13]) + + (vp[10 + dvp] * dp[14]) + + (vp[9 + dvp] * dp[15]) + ) * scalefactor); + + tmpOut[i] = pcm_sample; + + dvp += 16; + } // for + } + + private void compute_pcm_samples9(Obuffer buffer) + { + final float[] vp = actual_v; + + //int inc = v_inc; + final float[] tmpOut = _tmpOut; + int dvp =0; + + // fat chance of having this loop unroll + for( int i=0; i<32; i++) + { + final float[] dp = d16[i]; + float pcm_sample; + + pcm_sample = (float)(((vp[9 + dvp] * dp[0]) + + (vp[8 + dvp] * dp[1]) + + (vp[7 + dvp] * dp[2]) + + (vp[6 + dvp] * dp[3]) + + (vp[5 + dvp] * dp[4]) + + (vp[4 + dvp] * dp[5]) + + (vp[3 + dvp] * dp[6]) + + (vp[2 + dvp] * dp[7]) + + (vp[1 + dvp] * dp[8]) + + (vp[0 + dvp] * dp[9]) + + (vp[15 + dvp] * dp[10]) + + (vp[14 + dvp] * dp[11]) + + (vp[13 + dvp] * dp[12]) + + (vp[12 + dvp] * dp[13]) + + (vp[11 + dvp] * dp[14]) + + (vp[10 + dvp] * dp[15]) + ) * scalefactor); + + tmpOut[i] = pcm_sample; + + dvp += 16; + } // for + } + + private void compute_pcm_samples10(Obuffer buffer) + { + final float[] vp = actual_v; + //int inc = v_inc; + final float[] tmpOut = _tmpOut; + int dvp =0; + + // fat chance of having this loop unroll + for( int i=0; i<32; i++) + { + final float[] dp = d16[i]; + float pcm_sample; + + pcm_sample = (float)(((vp[10 + dvp] * dp[0]) + + (vp[9 + dvp] * dp[1]) + + (vp[8 + dvp] * dp[2]) + + (vp[7 + dvp] * dp[3]) + + (vp[6 + dvp] * dp[4]) + + (vp[5 + dvp] * dp[5]) + + (vp[4 + dvp] * dp[6]) + + (vp[3 + dvp] * dp[7]) + + (vp[2 + dvp] * dp[8]) + + (vp[1 + dvp] * dp[9]) + + (vp[0 + dvp] * dp[10]) + + (vp[15 + dvp] * dp[11]) + + (vp[14 + dvp] * dp[12]) + + (vp[13 + dvp] * dp[13]) + + (vp[12 + dvp] * dp[14]) + + (vp[11 + dvp] * dp[15]) + ) * scalefactor); + + tmpOut[i] = pcm_sample; + + dvp += 16; + } // for + } + private void compute_pcm_samples11(Obuffer buffer) + { + final float[] vp = actual_v; + + //int inc = v_inc; + final float[] tmpOut = _tmpOut; + int dvp =0; + + // fat chance of having this loop unroll + for( int i=0; i<32; i++) + { + final float[] dp = d16[i]; + float pcm_sample; + + pcm_sample = (float)(((vp[11 + dvp] * dp[0]) + + (vp[10 + dvp] * dp[1]) + + (vp[9 + dvp] * dp[2]) + + (vp[8 + dvp] * dp[3]) + + (vp[7 + dvp] * dp[4]) + + (vp[6 + dvp] * dp[5]) + + (vp[5 + dvp] * dp[6]) + + (vp[4 + dvp] * dp[7]) + + (vp[3 + dvp] * dp[8]) + + (vp[2 + dvp] * dp[9]) + + (vp[1 + dvp] * dp[10]) + + (vp[0 + dvp] * dp[11]) + + (vp[15 + dvp] * dp[12]) + + (vp[14 + dvp] * dp[13]) + + (vp[13 + dvp] * dp[14]) + + (vp[12 + dvp] * dp[15]) + ) * scalefactor); + + tmpOut[i] = pcm_sample; + + dvp += 16; + } // for + } + private void compute_pcm_samples12(Obuffer buffer) + { + final float[] vp = actual_v; + //int inc = v_inc; + final float[] tmpOut = _tmpOut; + int dvp =0; + + // fat chance of having this loop unroll + for( int i=0; i<32; i++) + { + final float[] dp = d16[i]; + float pcm_sample; + + pcm_sample = (float)(((vp[12 + dvp] * dp[0]) + + (vp[11 + dvp] * dp[1]) + + (vp[10 + dvp] * dp[2]) + + (vp[9 + dvp] * dp[3]) + + (vp[8 + dvp] * dp[4]) + + (vp[7 + dvp] * dp[5]) + + (vp[6 + dvp] * dp[6]) + + (vp[5 + dvp] * dp[7]) + + (vp[4 + dvp] * dp[8]) + + (vp[3 + dvp] * dp[9]) + + (vp[2 + dvp] * dp[10]) + + (vp[1 + dvp] * dp[11]) + + (vp[0 + dvp] * dp[12]) + + (vp[15 + dvp] * dp[13]) + + (vp[14 + dvp] * dp[14]) + + (vp[13 + dvp] * dp[15]) + ) * scalefactor); + + tmpOut[i] = pcm_sample; + + dvp += 16; + } // for + } + private void compute_pcm_samples13(Obuffer buffer) + { + final float[] vp = actual_v; + + //int inc = v_inc; + final float[] tmpOut = _tmpOut; + int dvp =0; + + // fat chance of having this loop unroll + for( int i=0; i<32; i++) + { + final float[] dp = d16[i]; + float pcm_sample; + + pcm_sample = (float)(((vp[13 + dvp] * dp[0]) + + (vp[12 + dvp] * dp[1]) + + (vp[11 + dvp] * dp[2]) + + (vp[10 + dvp] * dp[3]) + + (vp[9 + dvp] * dp[4]) + + (vp[8 + dvp] * dp[5]) + + (vp[7 + dvp] * dp[6]) + + (vp[6 + dvp] * dp[7]) + + (vp[5 + dvp] * dp[8]) + + (vp[4 + dvp] * dp[9]) + + (vp[3 + dvp] * dp[10]) + + (vp[2 + dvp] * dp[11]) + + (vp[1 + dvp] * dp[12]) + + (vp[0 + dvp] * dp[13]) + + (vp[15 + dvp] * dp[14]) + + (vp[14 + dvp] * dp[15]) + ) * scalefactor); + + tmpOut[i] = pcm_sample; + + dvp += 16; + } // for + } + private void compute_pcm_samples14(Obuffer buffer) + { + final float[] vp = actual_v; + + //int inc = v_inc; + final float[] tmpOut = _tmpOut; + int dvp =0; + + // fat chance of having this loop unroll + for( int i=0; i<32; i++) + { + final float[] dp = d16[i]; + float pcm_sample; + + pcm_sample = (float)(((vp[14 + dvp] * dp[0]) + + (vp[13 + dvp] * dp[1]) + + (vp[12 + dvp] * dp[2]) + + (vp[11 + dvp] * dp[3]) + + (vp[10 + dvp] * dp[4]) + + (vp[9 + dvp] * dp[5]) + + (vp[8 + dvp] * dp[6]) + + (vp[7 + dvp] * dp[7]) + + (vp[6 + dvp] * dp[8]) + + (vp[5 + dvp] * dp[9]) + + (vp[4 + dvp] * dp[10]) + + (vp[3 + dvp] * dp[11]) + + (vp[2 + dvp] * dp[12]) + + (vp[1 + dvp] * dp[13]) + + (vp[0 + dvp] * dp[14]) + + (vp[15 + dvp] * dp[15]) + ) * scalefactor); + + tmpOut[i] = pcm_sample; + + dvp += 16; + } // for + } + private void compute_pcm_samples15(Obuffer buffer) + { + final float[] vp = actual_v; + + //int inc = v_inc; + final float[] tmpOut = _tmpOut; + int dvp =0; + + // fat chance of having this loop unroll + for( int i=0; i<32; i++) + { + float pcm_sample; + final float dp[] = d16[i]; + pcm_sample = (float)(((vp[15 + dvp] * dp[0]) + + (vp[14 + dvp] * dp[1]) + + (vp[13 + dvp] * dp[2]) + + (vp[12 + dvp] * dp[3]) + + (vp[11 + dvp] * dp[4]) + + (vp[10 + dvp] * dp[5]) + + (vp[9 + dvp] * dp[6]) + + (vp[8 + dvp] * dp[7]) + + (vp[7 + dvp] * dp[8]) + + (vp[6 + dvp] * dp[9]) + + (vp[5 + dvp] * dp[10]) + + (vp[4 + dvp] * dp[11]) + + (vp[3 + dvp] * dp[12]) + + (vp[2 + dvp] * dp[13]) + + (vp[1 + dvp] * dp[14]) + + (vp[0 + dvp] * dp[15]) + ) * scalefactor); + + tmpOut[i] = pcm_sample; + dvp += 16; + } // for + } + +private void compute_pcm_samples(Obuffer buffer) +{ + + switch (actual_write_pos) + { + case 0: + compute_pcm_samples0(buffer); + break; + case 1: + compute_pcm_samples1(buffer); + break; + case 2: + compute_pcm_samples2(buffer); + break; + case 3: + compute_pcm_samples3(buffer); + break; + case 4: + compute_pcm_samples4(buffer); + break; + case 5: + compute_pcm_samples5(buffer); + break; + case 6: + compute_pcm_samples6(buffer); + break; + case 7: + compute_pcm_samples7(buffer); + break; + case 8: + compute_pcm_samples8(buffer); + break; + case 9: + compute_pcm_samples9(buffer); + break; + case 10: + compute_pcm_samples10(buffer); + break; + case 11: + compute_pcm_samples11(buffer); + break; + case 12: + compute_pcm_samples12(buffer); + break; + case 13: + compute_pcm_samples13(buffer); + break; + case 14: + compute_pcm_samples14(buffer); + break; + case 15: + compute_pcm_samples15(buffer); + break; + } + + if (buffer!=null) + { + buffer.appendSamples(channel, _tmpOut); + } + +/* + // MDM: I was considering putting in quality control for + // low-spec CPUs, but the performance gain (about 10-15%) + // did not justify the considerable drop in audio quality. + switch (inc) + { + case 16: + buffer.appendSamples(channel, tmpOut); + break; + case 32: + for (int i=0; i<16; i++) + { + buffer.append(channel, (short)tmpOut[i]); + buffer.append(channel, (short)tmpOut[i]); + } + break; + case 64: + for (int i=0; i<8; i++) + { + buffer.append(channel, (short)tmpOut[i]); + buffer.append(channel, (short)tmpOut[i]); + buffer.append(channel, (short)tmpOut[i]); + buffer.append(channel, (short)tmpOut[i]); + } + break; + + } +*/ + } + + /** + * Calculate 32 PCM samples and put the into the Obuffer-object. + */ + + public void calculate_pcm_samples(Obuffer buffer) + { + compute_new_v(); + compute_pcm_samples(buffer); + + actual_write_pos = (actual_write_pos + 1) & 0xf; + actual_v = (actual_v == v1) ? v2 : v1; + + // initialize samples[]: + //for (register float *floatp = samples + 32; floatp > samples; ) + // *--floatp = 0.0f; + + // MDM: this may not be necessary. The Layer III decoder always + // outputs 32 subband samples, but I haven't checked layer I & II. + for (int p=0;p<32;p++) + samples[p] = 0.0f; + } + + + private static final double MY_PI = 3.14159265358979323846; + private static final float cos1_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI / 64.0))); + private static final float cos3_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 3.0 / 64.0))); + private static final float cos5_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 5.0 / 64.0))); + private static final float cos7_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 7.0 / 64.0))); + private static final float cos9_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 9.0 / 64.0))); + private static final float cos11_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 11.0 / 64.0))); + private static final float cos13_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 13.0 / 64.0))); + private static final float cos15_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 15.0 / 64.0))); + private static final float cos17_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 17.0 / 64.0))); + private static final float cos19_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 19.0 / 64.0))); + private static final float cos21_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 21.0 / 64.0))); + private static final float cos23_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 23.0 / 64.0))); + private static final float cos25_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 25.0 / 64.0))); + private static final float cos27_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 27.0 / 64.0))); + private static final float cos29_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 29.0 / 64.0))); + private static final float cos31_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 31.0 / 64.0))); + private static final float cos1_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI / 32.0))); + private static final float cos3_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 3.0 / 32.0))); + private static final float cos5_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 5.0 / 32.0))); + private static final float cos7_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 7.0 / 32.0))); + private static final float cos9_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 9.0 / 32.0))); + private static final float cos11_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 11.0 / 32.0))); + private static final float cos13_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 13.0 / 32.0))); + private static final float cos15_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 15.0 / 32.0))); + private static final float cos1_16 =(float) (1.0 / (2.0 * Math.cos(MY_PI / 16.0))); + private static final float cos3_16 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 3.0 / 16.0))); + private static final float cos5_16 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 5.0 / 16.0))); + private static final float cos7_16 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 7.0 / 16.0))); + private static final float cos1_8 =(float) (1.0 / (2.0 * Math.cos(MY_PI / 8.0))); + private static final float cos3_8 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 3.0 / 8.0))); + private static final float cos1_4 =(float) (1.0 / (2.0 * Math.cos(MY_PI / 4.0))); + + // Note: These values are not in the same order + // as in Annex 3-B.3 of the ISO/IEC DIS 11172-3 + // private float d[] = {0.000000000, -4.000442505}; + + private static float d[] = null; + + /** + * d[] split into subarrays of length 16. This provides for + * more faster access by allowing a block of 16 to be addressed + * with constant offset. + **/ + private static float d16[][] = null; + + /** + * Loads the data for the d[] from the resource SFd.ser. + * @return the loaded values for d[]. + */ + static private float[] load_d() + { + try + { + Class elemType = Float.TYPE; + Object o = JavaLayerUtils.deserializeArrayResource("sfd.ser", elemType, 512); + return (float[])o; + } + catch (IOException ex) + { + throw new ExceptionInInitializerError(ex); + } + } + + /** + * Converts a 1D array into a number of smaller arrays. This is used + * to achieve offset + constant indexing into an array. Each sub-array + * represents a block of values of the original array. + * @param array The array to split up into blocks. + * @param blockSize The size of the blocks to split the array + * into. This must be an exact divisor of + * the length of the array, or some data + * will be lost from the main array. + * + * @return An array of arrays in which each element in the returned + * array will be of length blockSize. + */ + static private float[][] splitArray(final float[] array, final int blockSize) + { + int size = array.length / blockSize; + float[][] split = new float[size][]; + for (int i=0; i array.length) + { + len = array.length-offs; + } + + if (len < 0) + len = 0; + + float[] subarray = new float[len]; + System.arraycopy(array, offs + 0, subarray, 0, len); + + return subarray; + } + + // The original data for d[]. This data is loaded from a file + // to reduce the overall package size and to improve performance. +/* + static final float d_data[] = { + 0.000000000f, -0.000442505f, 0.003250122f, -0.007003784f, + 0.031082153f, -0.078628540f, 0.100311279f, -0.572036743f, + 1.144989014f, 0.572036743f, 0.100311279f, 0.078628540f, + 0.031082153f, 0.007003784f, 0.003250122f, 0.000442505f, + -0.000015259f, -0.000473022f, 0.003326416f, -0.007919312f, + 0.030517578f, -0.084182739f, 0.090927124f, -0.600219727f, + 1.144287109f, 0.543823242f, 0.108856201f, 0.073059082f, + 0.031478882f, 0.006118774f, 0.003173828f, 0.000396729f, + -0.000015259f, -0.000534058f, 0.003387451f, -0.008865356f, + 0.029785156f, -0.089706421f, 0.080688477f, -0.628295898f, + 1.142211914f, 0.515609741f, 0.116577148f, 0.067520142f, + 0.031738281f, 0.005294800f, 0.003082275f, 0.000366211f, + -0.000015259f, -0.000579834f, 0.003433228f, -0.009841919f, + 0.028884888f, -0.095169067f, 0.069595337f, -0.656219482f, + 1.138763428f, 0.487472534f, 0.123474121f, 0.061996460f, + 0.031845093f, 0.004486084f, 0.002990723f, 0.000320435f, + -0.000015259f, -0.000625610f, 0.003463745f, -0.010848999f, + 0.027801514f, -0.100540161f, 0.057617188f, -0.683914185f, + 1.133926392f, 0.459472656f, 0.129577637f, 0.056533813f, + 0.031814575f, 0.003723145f, 0.002899170f, 0.000289917f, + -0.000015259f, -0.000686646f, 0.003479004f, -0.011886597f, + 0.026535034f, -0.105819702f, 0.044784546f, -0.711318970f, + 1.127746582f, 0.431655884f, 0.134887695f, 0.051132202f, + 0.031661987f, 0.003005981f, 0.002792358f, 0.000259399f, + -0.000015259f, -0.000747681f, 0.003479004f, -0.012939453f, + 0.025085449f, -0.110946655f, 0.031082153f, -0.738372803f, + 1.120223999f, 0.404083252f, 0.139450073f, 0.045837402f, + 0.031387329f, 0.002334595f, 0.002685547f, 0.000244141f, + -0.000030518f, -0.000808716f, 0.003463745f, -0.014022827f, + 0.023422241f, -0.115921021f, 0.016510010f, -0.765029907f, + 1.111373901f, 0.376800537f, 0.143264771f, 0.040634155f, + 0.031005859f, 0.001693726f, 0.002578735f, 0.000213623f, + -0.000030518f, -0.000885010f, 0.003417969f, -0.015121460f, + 0.021575928f, -0.120697021f, 0.001068115f, -0.791213989f, + 1.101211548f, 0.349868774f, 0.146362305f, 0.035552979f, + 0.030532837f, 0.001098633f, 0.002456665f, 0.000198364f, + -0.000030518f, -0.000961304f, 0.003372192f, -0.016235352f, + 0.019531250f, -0.125259399f, -0.015228271f, -0.816864014f, + 1.089782715f, 0.323318481f, 0.148773193f, 0.030609131f, + 0.029937744f, 0.000549316f, 0.002349854f, 0.000167847f, + -0.000030518f, -0.001037598f, 0.003280640f, -0.017349243f, + 0.017257690f, -0.129562378f, -0.032379150f, -0.841949463f, + 1.077117920f, 0.297210693f, 0.150497437f, 0.025817871f, + 0.029281616f, 0.000030518f, 0.002243042f, 0.000152588f, + -0.000045776f, -0.001113892f, 0.003173828f, -0.018463135f, + 0.014801025f, -0.133590698f, -0.050354004f, -0.866363525f, + 1.063217163f, 0.271591187f, 0.151596069f, 0.021179199f, + 0.028533936f, -0.000442505f, 0.002120972f, 0.000137329f, + -0.000045776f, -0.001205444f, 0.003051758f, -0.019577026f, + 0.012115479f, -0.137298584f, -0.069168091f, -0.890090942f, + 1.048156738f, 0.246505737f, 0.152069092f, 0.016708374f, + 0.027725220f, -0.000869751f, 0.002014160f, 0.000122070f, + -0.000061035f, -0.001296997f, 0.002883911f, -0.020690918f, + 0.009231567f, -0.140670776f, -0.088775635f, -0.913055420f, + 1.031936646f, 0.221984863f, 0.151962280f, 0.012420654f, + 0.026840210f, -0.001266479f, 0.001907349f, 0.000106812f, + -0.000061035f, -0.001388550f, 0.002700806f, -0.021789551f, + 0.006134033f, -0.143676758f, -0.109161377f, -0.935195923f, + 1.014617920f, 0.198059082f, 0.151306152f, 0.008316040f, + 0.025909424f, -0.001617432f, 0.001785278f, 0.000106812f, + -0.000076294f, -0.001480103f, 0.002487183f, -0.022857666f, + 0.002822876f, -0.146255493f, -0.130310059f, -0.956481934f, + 0.996246338f, 0.174789429f, 0.150115967f, 0.004394531f, + 0.024932861f, -0.001937866f, 0.001693726f, 0.000091553f, + -0.000076294f, -0.001586914f, 0.002227783f, -0.023910522f, + -0.000686646f, -0.148422241f, -0.152206421f, -0.976852417f, + 0.976852417f, 0.152206421f, 0.148422241f, 0.000686646f, + 0.023910522f, -0.002227783f, 0.001586914f, 0.000076294f, + -0.000091553f, -0.001693726f, 0.001937866f, -0.024932861f, + -0.004394531f, -0.150115967f, -0.174789429f, -0.996246338f, + 0.956481934f, 0.130310059f, 0.146255493f, -0.002822876f, + 0.022857666f, -0.002487183f, 0.001480103f, 0.000076294f, + -0.000106812f, -0.001785278f, 0.001617432f, -0.025909424f, + -0.008316040f, -0.151306152f, -0.198059082f, -1.014617920f, + 0.935195923f, 0.109161377f, 0.143676758f, -0.006134033f, + 0.021789551f, -0.002700806f, 0.001388550f, 0.000061035f, + -0.000106812f, -0.001907349f, 0.001266479f, -0.026840210f, + -0.012420654f, -0.151962280f, -0.221984863f, -1.031936646f, + 0.913055420f, 0.088775635f, 0.140670776f, -0.009231567f, + 0.020690918f, -0.002883911f, 0.001296997f, 0.000061035f, + -0.000122070f, -0.002014160f, 0.000869751f, -0.027725220f, + -0.016708374f, -0.152069092f, -0.246505737f, -1.048156738f, + 0.890090942f, 0.069168091f, 0.137298584f, -0.012115479f, + 0.019577026f, -0.003051758f, 0.001205444f, 0.000045776f, + -0.000137329f, -0.002120972f, 0.000442505f, -0.028533936f, + -0.021179199f, -0.151596069f, -0.271591187f, -1.063217163f, + 0.866363525f, 0.050354004f, 0.133590698f, -0.014801025f, + 0.018463135f, -0.003173828f, 0.001113892f, 0.000045776f, + -0.000152588f, -0.002243042f, -0.000030518f, -0.029281616f, + -0.025817871f, -0.150497437f, -0.297210693f, -1.077117920f, + 0.841949463f, 0.032379150f, 0.129562378f, -0.017257690f, + 0.017349243f, -0.003280640f, 0.001037598f, 0.000030518f, + -0.000167847f, -0.002349854f, -0.000549316f, -0.029937744f, + -0.030609131f, -0.148773193f, -0.323318481f, -1.089782715f, + 0.816864014f, 0.015228271f, 0.125259399f, -0.019531250f, + 0.016235352f, -0.003372192f, 0.000961304f, 0.000030518f, + -0.000198364f, -0.002456665f, -0.001098633f, -0.030532837f, + -0.035552979f, -0.146362305f, -0.349868774f, -1.101211548f, + 0.791213989f, -0.001068115f, 0.120697021f, -0.021575928f, + 0.015121460f, -0.003417969f, 0.000885010f, 0.000030518f, + -0.000213623f, -0.002578735f, -0.001693726f, -0.031005859f, + -0.040634155f, -0.143264771f, -0.376800537f, -1.111373901f, + 0.765029907f, -0.016510010f, 0.115921021f, -0.023422241f, + 0.014022827f, -0.003463745f, 0.000808716f, 0.000030518f, + -0.000244141f, -0.002685547f, -0.002334595f, -0.031387329f, + -0.045837402f, -0.139450073f, -0.404083252f, -1.120223999f, + 0.738372803f, -0.031082153f, 0.110946655f, -0.025085449f, + 0.012939453f, -0.003479004f, 0.000747681f, 0.000015259f, + -0.000259399f, -0.002792358f, -0.003005981f, -0.031661987f, + -0.051132202f, -0.134887695f, -0.431655884f, -1.127746582f, + 0.711318970f, -0.044784546f, 0.105819702f, -0.026535034f, + 0.011886597f, -0.003479004f, 0.000686646f, 0.000015259f, + -0.000289917f, -0.002899170f, -0.003723145f, -0.031814575f, + -0.056533813f, -0.129577637f, -0.459472656f, -1.133926392f, + 0.683914185f, -0.057617188f, 0.100540161f, -0.027801514f, + 0.010848999f, -0.003463745f, 0.000625610f, 0.000015259f, + -0.000320435f, -0.002990723f, -0.004486084f, -0.031845093f, + -0.061996460f, -0.123474121f, -0.487472534f, -1.138763428f, + 0.656219482f, -0.069595337f, 0.095169067f, -0.028884888f, + 0.009841919f, -0.003433228f, 0.000579834f, 0.000015259f, + -0.000366211f, -0.003082275f, -0.005294800f, -0.031738281f, + -0.067520142f, -0.116577148f, -0.515609741f, -1.142211914f, + 0.628295898f, -0.080688477f, 0.089706421f, -0.029785156f, + 0.008865356f, -0.003387451f, 0.000534058f, 0.000015259f, + -0.000396729f, -0.003173828f, -0.006118774f, -0.031478882f, + -0.073059082f, -0.108856201f, -0.543823242f, -1.144287109f, + 0.600219727f, -0.090927124f, 0.084182739f, -0.030517578f, + 0.007919312f, -0.003326416f, 0.000473022f, 0.000015259f + }; + */ + +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/au2lin.ser b/src/lwjgl/java/javazoom/jl/decoder/au2lin.ser new file mode 100644 index 0000000..0b20bc8 Binary files /dev/null and b/src/lwjgl/java/javazoom/jl/decoder/au2lin.ser differ diff --git a/src/lwjgl/java/javazoom/jl/decoder/huffcodetab.java b/src/lwjgl/java/javazoom/jl/decoder/huffcodetab.java new file mode 100644 index 0000000..3d80f17 --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/huffcodetab.java @@ -0,0 +1,600 @@ +/* + * 11/19/04 1.0 moved to LGPL. + * 16/11/99 Renamed class, added javadoc, and changed table + * name from String to 3 chars. mdm@techie.com + * 02/15/99 Java Conversion by E.B, javalayer@javazoom.net + * + * 04/19/97 : Adapted from the ISO MPEG Audio Subgroup Software Simulation + * Group's public c source for its MPEG audio decoder. Miscellaneous + * changes by Jeff Tsay (ctsay@pasteur.eecs.berkeley.edu). + *----------------------------------------------------------------------- + * Copyright (c) 1991 MPEG/audio software simulation group, All Rights Reserved + * MPEG/audio coding/decoding software, work in progress + * NOT for public distribution until verified and approved by the + * MPEG/audio committee. For further information, please contact + * Davis Pan, 508-493-2241, e-mail: pan@3d.enet.dec.com + * + * VERSION 4.1 + * changes made since last update: + * date programmers comment + * 27.2.92 F.O.Witte (ITT Intermetall) + * 8/24/93 M. Iwadare Changed for 1 pass decoding. + * 7/14/94 J. Koller useless 'typedef' before huffcodetab removed + *----------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *---------------------------------------------------------------------- + */ + +package javazoom.jl.decoder; + +/** + * Class that implements a Huffman decoder. + */ +final class huffcodetab +{ + private static final int MXOFF=250; + private static final int HTN=34; + + private char tablename0 = ' '; /* string, containing table_description */ + private char tablename1 = ' '; /* string, containing table_description */ + private char tablename2 = ' '; /* string, containing table_description */ + + private int xlen; /* max. x-index+ */ + private int ylen; /* max. y-index+ */ + private int linbits; /* number of linbits */ + private int linmax; /* max number to be stored in linbits */ + private int ref; /* a positive value indicates a reference */ + private int[] table=null; /* pointer to array[xlen][ylen] */ + private int[] hlen=null; /* pointer to array[xlen][ylen] */ + private int[][] val=null; /* decoder tree */ + private int treelen; /* length of decoder tree */ + + private static int ValTab0[][] = { + {0,0} // dummy + }; + + private static int ValTab1[][] = { + {2,1},{0,0},{2,1},{0,16},{2,1},{0,1},{0,17}, + }; + + private static int ValTab2[][] = { + {2,1},{0,0},{4,1},{2,1},{0,16},{0,1},{2,1},{0,17},{4,1},{2,1}, + {0,32},{0,33},{2,1},{0,18},{2,1},{0,2},{0,34}, + }; + + private static int ValTab3[][] = { + {4,1},{2,1},{0,0},{0,1},{2,1},{0,17},{2,1},{0,16},{4,1},{2,1}, + {0,32},{0,33},{2,1},{0,18},{2,1},{0,2},{0,34}, + }; + + private static int ValTab4[][] = {{0,0}}; // dummy + + private static int ValTab5[][] = { + {2,1},{0,0},{4,1},{2,1},{0,16},{0,1},{2,1},{0,17},{8,1},{4,1}, + {2,1},{0,32},{0,2},{2,1},{0,33},{0,18},{8,1},{4,1},{2,1},{0,34}, + {0,48},{2,1},{0,3},{0,19},{2,1},{0,49},{2,1},{0,50},{2,1},{0,35}, + {0,51}, + }; + + private static int ValTab6[][] = { + {6,1},{4,1},{2,1},{0,0},{0,16},{0,17},{6,1},{2,1},{0,1},{2,1}, + {0,32},{0,33},{6,1},{2,1},{0,18},{2,1},{0,2},{0,34},{4,1},{2,1}, + {0,49},{0,19},{4,1},{2,1},{0,48},{0,50},{2,1},{0,35},{2,1},{0,3}, + {0,51}, + }; + + private static int ValTab7[][] = { + {2,1},{0,0},{4,1},{2,1},{0,16},{0,1},{8,1},{2,1},{0,17},{4,1}, + {2,1},{0,32},{0,2},{0,33},{18,1},{6,1},{2,1},{0,18},{2,1},{0,34}, + {0,48},{4,1},{2,1},{0,49},{0,19},{4,1},{2,1},{0,3},{0,50},{2,1}, + {0,35},{0,4},{10,1},{4,1},{2,1},{0,64},{0,65},{2,1},{0,20},{2,1}, + {0,66},{0,36},{12,1},{6,1},{4,1},{2,1},{0,51},{0,67},{0,80},{4,1}, + {2,1},{0,52},{0,5},{0,81},{6,1},{2,1},{0,21},{2,1},{0,82},{0,37}, + {4,1},{2,1},{0,68},{0,53},{4,1},{2,1},{0,83},{0,84},{2,1},{0,69}, + {0,85}, + }; + + private static int ValTab8[][] = { + {6,1},{2,1},{0,0},{2,1},{0,16},{0,1},{2,1},{0,17},{4,1},{2,1}, + {0,33},{0,18},{14,1},{4,1},{2,1},{0,32},{0,2},{2,1},{0,34},{4,1}, + {2,1},{0,48},{0,3},{2,1},{0,49},{0,19},{14,1},{8,1},{4,1},{2,1}, + {0,50},{0,35},{2,1},{0,64},{0,4},{2,1},{0,65},{2,1},{0,20},{0,66}, + {12,1},{6,1},{2,1},{0,36},{2,1},{0,51},{0,80},{4,1},{2,1},{0,67}, + {0,52},{0,81},{6,1},{2,1},{0,21},{2,1},{0,5},{0,82},{6,1},{2,1}, + {0,37},{2,1},{0,68},{0,53},{2,1},{0,83},{2,1},{0,69},{2,1},{0,84}, + {0,85}, + }; + + private static int ValTab9[][] = { + {8,1},{4,1},{2,1},{0,0},{0,16},{2,1},{0,1},{0,17},{10,1},{4,1}, + {2,1},{0,32},{0,33},{2,1},{0,18},{2,1},{0,2},{0,34},{12,1},{6,1}, + {4,1},{2,1},{0,48},{0,3},{0,49},{2,1},{0,19},{2,1},{0,50},{0,35}, + {12,1},{4,1},{2,1},{0,65},{0,20},{4,1},{2,1},{0,64},{0,51},{2,1}, + {0,66},{0,36},{10,1},{6,1},{4,1},{2,1},{0,4},{0,80},{0,67},{2,1}, + {0,52},{0,81},{8,1},{4,1},{2,1},{0,21},{0,82},{2,1},{0,37},{0,68}, + {6,1},{4,1},{2,1},{0,5},{0,84},{0,83},{2,1},{0,53},{2,1},{0,69}, + {0,85}, + }; + + private static int ValTab10[][] = { + {2,1},{0,0},{4,1},{2,1},{0,16},{0,1},{10,1},{2,1},{0,17},{4,1}, + {2,1},{0,32},{0,2},{2,1},{0,33},{0,18},{28,1},{8,1},{4,1},{2,1}, + {0,34},{0,48},{2,1},{0,49},{0,19},{8,1},{4,1},{2,1},{0,3},{0,50}, + {2,1},{0,35},{0,64},{4,1},{2,1},{0,65},{0,20},{4,1},{2,1},{0,4}, + {0,51},{2,1},{0,66},{0,36},{28,1},{10,1},{6,1},{4,1},{2,1},{0,80}, + {0,5},{0,96},{2,1},{0,97},{0,22},{12,1},{6,1},{4,1},{2,1},{0,67}, + {0,52},{0,81},{2,1},{0,21},{2,1},{0,82},{0,37},{4,1},{2,1},{0,38}, + {0,54},{0,113},{20,1},{8,1},{2,1},{0,23},{4,1},{2,1},{0,68},{0,83}, + {0,6},{6,1},{4,1},{2,1},{0,53},{0,69},{0,98},{2,1},{0,112},{2,1}, + {0,7},{0,100},{14,1},{4,1},{2,1},{0,114},{0,39},{6,1},{2,1},{0,99}, + {2,1},{0,84},{0,85},{2,1},{0,70},{0,115},{8,1},{4,1},{2,1},{0,55}, + {0,101},{2,1},{0,86},{0,116},{6,1},{2,1},{0,71},{2,1},{0,102},{0,117}, + {4,1},{2,1},{0,87},{0,118},{2,1},{0,103},{0,119}, + }; + + private static int ValTab11[][] = { + {6,1},{2,1},{0,0},{2,1},{0,16},{0,1},{8,1},{2,1},{0,17},{4,1}, + {2,1},{0,32},{0,2},{0,18},{24,1},{8,1},{2,1},{0,33},{2,1},{0,34}, + {2,1},{0,48},{0,3},{4,1},{2,1},{0,49},{0,19},{4,1},{2,1},{0,50}, + {0,35},{4,1},{2,1},{0,64},{0,4},{2,1},{0,65},{0,20},{30,1},{16,1}, + {10,1},{4,1},{2,1},{0,66},{0,36},{4,1},{2,1},{0,51},{0,67},{0,80}, + {4,1},{2,1},{0,52},{0,81},{0,97},{6,1},{2,1},{0,22},{2,1},{0,6}, + {0,38},{2,1},{0,98},{2,1},{0,21},{2,1},{0,5},{0,82},{16,1},{10,1}, + {6,1},{4,1},{2,1},{0,37},{0,68},{0,96},{2,1},{0,99},{0,54},{4,1}, + {2,1},{0,112},{0,23},{0,113},{16,1},{6,1},{4,1},{2,1},{0,7},{0,100}, + {0,114},{2,1},{0,39},{4,1},{2,1},{0,83},{0,53},{2,1},{0,84},{0,69}, + {10,1},{4,1},{2,1},{0,70},{0,115},{2,1},{0,55},{2,1},{0,101},{0,86}, + {10,1},{6,1},{4,1},{2,1},{0,85},{0,87},{0,116},{2,1},{0,71},{0,102}, + {4,1},{2,1},{0,117},{0,118},{2,1},{0,103},{0,119}, + }; + + private static int ValTab12[][] = { + {12,1},{4,1},{2,1},{0,16},{0,1},{2,1},{0,17},{2,1},{0,0},{2,1}, + {0,32},{0,2},{16,1},{4,1},{2,1},{0,33},{0,18},{4,1},{2,1},{0,34}, + {0,49},{2,1},{0,19},{2,1},{0,48},{2,1},{0,3},{0,64},{26,1},{8,1}, + {4,1},{2,1},{0,50},{0,35},{2,1},{0,65},{0,51},{10,1},{4,1},{2,1}, + {0,20},{0,66},{2,1},{0,36},{2,1},{0,4},{0,80},{4,1},{2,1},{0,67}, + {0,52},{2,1},{0,81},{0,21},{28,1},{14,1},{8,1},{4,1},{2,1},{0,82}, + {0,37},{2,1},{0,83},{0,53},{4,1},{2,1},{0,96},{0,22},{0,97},{4,1}, + {2,1},{0,98},{0,38},{6,1},{4,1},{2,1},{0,5},{0,6},{0,68},{2,1}, + {0,84},{0,69},{18,1},{10,1},{4,1},{2,1},{0,99},{0,54},{4,1},{2,1}, + {0,112},{0,7},{0,113},{4,1},{2,1},{0,23},{0,100},{2,1},{0,70},{0,114}, + {10,1},{6,1},{2,1},{0,39},{2,1},{0,85},{0,115},{2,1},{0,55},{0,86}, + {8,1},{4,1},{2,1},{0,101},{0,116},{2,1},{0,71},{0,102},{4,1},{2,1}, + {0,117},{0,87},{2,1},{0,118},{2,1},{0,103},{0,119}, + }; + + private static int ValTab13[][] = { + {2,1},{0,0},{6,1},{2,1},{0,16},{2,1},{0,1},{0,17},{28,1},{8,1}, + {4,1},{2,1},{0,32},{0,2},{2,1},{0,33},{0,18},{8,1},{4,1},{2,1}, + {0,34},{0,48},{2,1},{0,3},{0,49},{6,1},{2,1},{0,19},{2,1},{0,50}, + {0,35},{4,1},{2,1},{0,64},{0,4},{0,65},{70,1},{28,1},{14,1},{6,1}, + {2,1},{0,20},{2,1},{0,51},{0,66},{4,1},{2,1},{0,36},{0,80},{2,1}, + {0,67},{0,52},{4,1},{2,1},{0,81},{0,21},{4,1},{2,1},{0,5},{0,82}, + {2,1},{0,37},{2,1},{0,68},{0,83},{14,1},{8,1},{4,1},{2,1},{0,96}, + {0,6},{2,1},{0,97},{0,22},{4,1},{2,1},{0,128},{0,8},{0,129},{16,1}, + {8,1},{4,1},{2,1},{0,53},{0,98},{2,1},{0,38},{0,84},{4,1},{2,1}, + {0,69},{0,99},{2,1},{0,54},{0,112},{6,1},{4,1},{2,1},{0,7},{0,85}, + {0,113},{2,1},{0,23},{2,1},{0,39},{0,55},{72,1},{24,1},{12,1},{4,1}, + {2,1},{0,24},{0,130},{2,1},{0,40},{4,1},{2,1},{0,100},{0,70},{0,114}, + {8,1},{4,1},{2,1},{0,132},{0,72},{2,1},{0,144},{0,9},{2,1},{0,145}, + {0,25},{24,1},{14,1},{8,1},{4,1},{2,1},{0,115},{0,101},{2,1},{0,86}, + {0,116},{4,1},{2,1},{0,71},{0,102},{0,131},{6,1},{2,1},{0,56},{2,1}, + {0,117},{0,87},{2,1},{0,146},{0,41},{14,1},{8,1},{4,1},{2,1},{0,103}, + {0,133},{2,1},{0,88},{0,57},{2,1},{0,147},{2,1},{0,73},{0,134},{6,1}, + {2,1},{0,160},{2,1},{0,104},{0,10},{2,1},{0,161},{0,26},{68,1},{24,1}, + {12,1},{4,1},{2,1},{0,162},{0,42},{4,1},{2,1},{0,149},{0,89},{2,1}, + {0,163},{0,58},{8,1},{4,1},{2,1},{0,74},{0,150},{2,1},{0,176},{0,11}, + {2,1},{0,177},{0,27},{20,1},{8,1},{2,1},{0,178},{4,1},{2,1},{0,118}, + {0,119},{0,148},{6,1},{4,1},{2,1},{0,135},{0,120},{0,164},{4,1},{2,1}, + {0,105},{0,165},{0,43},{12,1},{6,1},{4,1},{2,1},{0,90},{0,136},{0,179}, + {2,1},{0,59},{2,1},{0,121},{0,166},{6,1},{4,1},{2,1},{0,106},{0,180}, + {0,192},{4,1},{2,1},{0,12},{0,152},{0,193},{60,1},{22,1},{10,1},{6,1}, + {2,1},{0,28},{2,1},{0,137},{0,181},{2,1},{0,91},{0,194},{4,1},{2,1}, + {0,44},{0,60},{4,1},{2,1},{0,182},{0,107},{2,1},{0,196},{0,76},{16,1}, + {8,1},{4,1},{2,1},{0,168},{0,138},{2,1},{0,208},{0,13},{2,1},{0,209}, + {2,1},{0,75},{2,1},{0,151},{0,167},{12,1},{6,1},{2,1},{0,195},{2,1}, + {0,122},{0,153},{4,1},{2,1},{0,197},{0,92},{0,183},{4,1},{2,1},{0,29}, + {0,210},{2,1},{0,45},{2,1},{0,123},{0,211},{52,1},{28,1},{12,1},{4,1}, + {2,1},{0,61},{0,198},{4,1},{2,1},{0,108},{0,169},{2,1},{0,154},{0,212}, + {8,1},{4,1},{2,1},{0,184},{0,139},{2,1},{0,77},{0,199},{4,1},{2,1}, + {0,124},{0,213},{2,1},{0,93},{0,224},{10,1},{4,1},{2,1},{0,225},{0,30}, + {4,1},{2,1},{0,14},{0,46},{0,226},{8,1},{4,1},{2,1},{0,227},{0,109}, + {2,1},{0,140},{0,228},{4,1},{2,1},{0,229},{0,186},{0,240},{38,1},{16,1}, + {4,1},{2,1},{0,241},{0,31},{6,1},{4,1},{2,1},{0,170},{0,155},{0,185}, + {2,1},{0,62},{2,1},{0,214},{0,200},{12,1},{6,1},{2,1},{0,78},{2,1}, + {0,215},{0,125},{2,1},{0,171},{2,1},{0,94},{0,201},{6,1},{2,1},{0,15}, + {2,1},{0,156},{0,110},{2,1},{0,242},{0,47},{32,1},{16,1},{6,1},{4,1}, + {2,1},{0,216},{0,141},{0,63},{6,1},{2,1},{0,243},{2,1},{0,230},{0,202}, + {2,1},{0,244},{0,79},{8,1},{4,1},{2,1},{0,187},{0,172},{2,1},{0,231}, + {0,245},{4,1},{2,1},{0,217},{0,157},{2,1},{0,95},{0,232},{30,1},{12,1}, + {6,1},{2,1},{0,111},{2,1},{0,246},{0,203},{4,1},{2,1},{0,188},{0,173}, + {0,218},{8,1},{2,1},{0,247},{4,1},{2,1},{0,126},{0,127},{0,142},{6,1}, + {4,1},{2,1},{0,158},{0,174},{0,204},{2,1},{0,248},{0,143},{18,1},{8,1}, + {4,1},{2,1},{0,219},{0,189},{2,1},{0,234},{0,249},{4,1},{2,1},{0,159}, + {0,235},{2,1},{0,190},{2,1},{0,205},{0,250},{14,1},{4,1},{2,1},{0,221}, + {0,236},{6,1},{4,1},{2,1},{0,233},{0,175},{0,220},{2,1},{0,206},{0,251}, + {8,1},{4,1},{2,1},{0,191},{0,222},{2,1},{0,207},{0,238},{4,1},{2,1}, + {0,223},{0,239},{2,1},{0,255},{2,1},{0,237},{2,1},{0,253},{2,1},{0,252}, + {0,254}, + }; + + private static int ValTab14[][] = { + {0,0} // dummy + }; + + private static int ValTab15[][] = { + {16,1},{6,1},{2,1},{0,0},{2,1},{0,16},{0,1},{2,1},{0,17},{4,1}, + {2,1},{0,32},{0,2},{2,1},{0,33},{0,18},{50,1},{16,1},{6,1},{2,1}, + {0,34},{2,1},{0,48},{0,49},{6,1},{2,1},{0,19},{2,1},{0,3},{0,64}, + {2,1},{0,50},{0,35},{14,1},{6,1},{4,1},{2,1},{0,4},{0,20},{0,65}, + {4,1},{2,1},{0,51},{0,66},{2,1},{0,36},{0,67},{10,1},{6,1},{2,1}, + {0,52},{2,1},{0,80},{0,5},{2,1},{0,81},{0,21},{4,1},{2,1},{0,82}, + {0,37},{4,1},{2,1},{0,68},{0,83},{0,97},{90,1},{36,1},{18,1},{10,1}, + {6,1},{2,1},{0,53},{2,1},{0,96},{0,6},{2,1},{0,22},{0,98},{4,1}, + {2,1},{0,38},{0,84},{2,1},{0,69},{0,99},{10,1},{6,1},{2,1},{0,54}, + {2,1},{0,112},{0,7},{2,1},{0,113},{0,85},{4,1},{2,1},{0,23},{0,100}, + {2,1},{0,114},{0,39},{24,1},{16,1},{8,1},{4,1},{2,1},{0,70},{0,115}, + {2,1},{0,55},{0,101},{4,1},{2,1},{0,86},{0,128},{2,1},{0,8},{0,116}, + {4,1},{2,1},{0,129},{0,24},{2,1},{0,130},{0,40},{16,1},{8,1},{4,1}, + {2,1},{0,71},{0,102},{2,1},{0,131},{0,56},{4,1},{2,1},{0,117},{0,87}, + {2,1},{0,132},{0,72},{6,1},{4,1},{2,1},{0,144},{0,25},{0,145},{4,1}, + {2,1},{0,146},{0,118},{2,1},{0,103},{0,41},{92,1},{36,1},{18,1},{10,1}, + {4,1},{2,1},{0,133},{0,88},{4,1},{2,1},{0,9},{0,119},{0,147},{4,1}, + {2,1},{0,57},{0,148},{2,1},{0,73},{0,134},{10,1},{6,1},{2,1},{0,104}, + {2,1},{0,160},{0,10},{2,1},{0,161},{0,26},{4,1},{2,1},{0,162},{0,42}, + {2,1},{0,149},{0,89},{26,1},{14,1},{6,1},{2,1},{0,163},{2,1},{0,58}, + {0,135},{4,1},{2,1},{0,120},{0,164},{2,1},{0,74},{0,150},{6,1},{4,1}, + {2,1},{0,105},{0,176},{0,177},{4,1},{2,1},{0,27},{0,165},{0,178},{14,1}, + {8,1},{4,1},{2,1},{0,90},{0,43},{2,1},{0,136},{0,151},{2,1},{0,179}, + {2,1},{0,121},{0,59},{8,1},{4,1},{2,1},{0,106},{0,180},{2,1},{0,75}, + {0,193},{4,1},{2,1},{0,152},{0,137},{2,1},{0,28},{0,181},{80,1},{34,1}, + {16,1},{6,1},{4,1},{2,1},{0,91},{0,44},{0,194},{6,1},{4,1},{2,1}, + {0,11},{0,192},{0,166},{2,1},{0,167},{0,122},{10,1},{4,1},{2,1},{0,195}, + {0,60},{4,1},{2,1},{0,12},{0,153},{0,182},{4,1},{2,1},{0,107},{0,196}, + {2,1},{0,76},{0,168},{20,1},{10,1},{4,1},{2,1},{0,138},{0,197},{4,1}, + {2,1},{0,208},{0,92},{0,209},{4,1},{2,1},{0,183},{0,123},{2,1},{0,29}, + {2,1},{0,13},{0,45},{12,1},{4,1},{2,1},{0,210},{0,211},{4,1},{2,1}, + {0,61},{0,198},{2,1},{0,108},{0,169},{6,1},{4,1},{2,1},{0,154},{0,184}, + {0,212},{4,1},{2,1},{0,139},{0,77},{2,1},{0,199},{0,124},{68,1},{34,1}, + {18,1},{10,1},{4,1},{2,1},{0,213},{0,93},{4,1},{2,1},{0,224},{0,14}, + {0,225},{4,1},{2,1},{0,30},{0,226},{2,1},{0,170},{0,46},{8,1},{4,1}, + {2,1},{0,185},{0,155},{2,1},{0,227},{0,214},{4,1},{2,1},{0,109},{0,62}, + {2,1},{0,200},{0,140},{16,1},{8,1},{4,1},{2,1},{0,228},{0,78},{2,1}, + {0,215},{0,125},{4,1},{2,1},{0,229},{0,186},{2,1},{0,171},{0,94},{8,1}, + {4,1},{2,1},{0,201},{0,156},{2,1},{0,241},{0,31},{6,1},{4,1},{2,1}, + {0,240},{0,110},{0,242},{2,1},{0,47},{0,230},{38,1},{18,1},{8,1},{4,1}, + {2,1},{0,216},{0,243},{2,1},{0,63},{0,244},{6,1},{2,1},{0,79},{2,1}, + {0,141},{0,217},{2,1},{0,187},{0,202},{8,1},{4,1},{2,1},{0,172},{0,231}, + {2,1},{0,126},{0,245},{8,1},{4,1},{2,1},{0,157},{0,95},{2,1},{0,232}, + {0,142},{2,1},{0,246},{0,203},{34,1},{18,1},{10,1},{6,1},{4,1},{2,1}, + {0,15},{0,174},{0,111},{2,1},{0,188},{0,218},{4,1},{2,1},{0,173},{0,247}, + {2,1},{0,127},{0,233},{8,1},{4,1},{2,1},{0,158},{0,204},{2,1},{0,248}, + {0,143},{4,1},{2,1},{0,219},{0,189},{2,1},{0,234},{0,249},{16,1},{8,1}, + {4,1},{2,1},{0,159},{0,220},{2,1},{0,205},{0,235},{4,1},{2,1},{0,190}, + {0,250},{2,1},{0,175},{0,221},{14,1},{6,1},{4,1},{2,1},{0,236},{0,206}, + {0,251},{4,1},{2,1},{0,191},{0,237},{2,1},{0,222},{0,252},{6,1},{4,1}, + {2,1},{0,207},{0,253},{0,238},{4,1},{2,1},{0,223},{0,254},{2,1},{0,239}, + {0,255}, + }; + + private static int ValTab16[][] = { + {2,1},{0,0},{6,1},{2,1},{0,16},{2,1},{0,1},{0,17},{42,1},{8,1}, + {4,1},{2,1},{0,32},{0,2},{2,1},{0,33},{0,18},{10,1},{6,1},{2,1}, + {0,34},{2,1},{0,48},{0,3},{2,1},{0,49},{0,19},{10,1},{4,1},{2,1}, + {0,50},{0,35},{4,1},{2,1},{0,64},{0,4},{0,65},{6,1},{2,1},{0,20}, + {2,1},{0,51},{0,66},{4,1},{2,1},{0,36},{0,80},{2,1},{0,67},{0,52}, + {138,1},{40,1},{16,1},{6,1},{4,1},{2,1},{0,5},{0,21},{0,81},{4,1}, + {2,1},{0,82},{0,37},{4,1},{2,1},{0,68},{0,53},{0,83},{10,1},{6,1}, + {4,1},{2,1},{0,96},{0,6},{0,97},{2,1},{0,22},{0,98},{8,1},{4,1}, + {2,1},{0,38},{0,84},{2,1},{0,69},{0,99},{4,1},{2,1},{0,54},{0,112}, + {0,113},{40,1},{18,1},{8,1},{2,1},{0,23},{2,1},{0,7},{2,1},{0,85}, + {0,100},{4,1},{2,1},{0,114},{0,39},{4,1},{2,1},{0,70},{0,101},{0,115}, + {10,1},{6,1},{2,1},{0,55},{2,1},{0,86},{0,8},{2,1},{0,128},{0,129}, + {6,1},{2,1},{0,24},{2,1},{0,116},{0,71},{2,1},{0,130},{2,1},{0,40}, + {0,102},{24,1},{14,1},{8,1},{4,1},{2,1},{0,131},{0,56},{2,1},{0,117}, + {0,132},{4,1},{2,1},{0,72},{0,144},{0,145},{6,1},{2,1},{0,25},{2,1}, + {0,9},{0,118},{2,1},{0,146},{0,41},{14,1},{8,1},{4,1},{2,1},{0,133}, + {0,88},{2,1},{0,147},{0,57},{4,1},{2,1},{0,160},{0,10},{0,26},{8,1}, + {2,1},{0,162},{2,1},{0,103},{2,1},{0,87},{0,73},{6,1},{2,1},{0,148}, + {2,1},{0,119},{0,134},{2,1},{0,161},{2,1},{0,104},{0,149},{220,1},{126,1}, + {50,1},{26,1},{12,1},{6,1},{2,1},{0,42},{2,1},{0,89},{0,58},{2,1}, + {0,163},{2,1},{0,135},{0,120},{8,1},{4,1},{2,1},{0,164},{0,74},{2,1}, + {0,150},{0,105},{4,1},{2,1},{0,176},{0,11},{0,177},{10,1},{4,1},{2,1}, + {0,27},{0,178},{2,1},{0,43},{2,1},{0,165},{0,90},{6,1},{2,1},{0,179}, + {2,1},{0,166},{0,106},{4,1},{2,1},{0,180},{0,75},{2,1},{0,12},{0,193}, + {30,1},{14,1},{6,1},{4,1},{2,1},{0,181},{0,194},{0,44},{4,1},{2,1}, + {0,167},{0,195},{2,1},{0,107},{0,196},{8,1},{2,1},{0,29},{4,1},{2,1}, + {0,136},{0,151},{0,59},{4,1},{2,1},{0,209},{0,210},{2,1},{0,45},{0,211}, + {18,1},{6,1},{4,1},{2,1},{0,30},{0,46},{0,226},{6,1},{4,1},{2,1}, + {0,121},{0,152},{0,192},{2,1},{0,28},{2,1},{0,137},{0,91},{14,1},{6,1}, + {2,1},{0,60},{2,1},{0,122},{0,182},{4,1},{2,1},{0,76},{0,153},{2,1}, + {0,168},{0,138},{6,1},{2,1},{0,13},{2,1},{0,197},{0,92},{4,1},{2,1}, + {0,61},{0,198},{2,1},{0,108},{0,154},{88,1},{86,1},{36,1},{16,1},{8,1}, + {4,1},{2,1},{0,139},{0,77},{2,1},{0,199},{0,124},{4,1},{2,1},{0,213}, + {0,93},{2,1},{0,224},{0,14},{8,1},{2,1},{0,227},{4,1},{2,1},{0,208}, + {0,183},{0,123},{6,1},{4,1},{2,1},{0,169},{0,184},{0,212},{2,1},{0,225}, + {2,1},{0,170},{0,185},{24,1},{10,1},{6,1},{4,1},{2,1},{0,155},{0,214}, + {0,109},{2,1},{0,62},{0,200},{6,1},{4,1},{2,1},{0,140},{0,228},{0,78}, + {4,1},{2,1},{0,215},{0,229},{2,1},{0,186},{0,171},{12,1},{4,1},{2,1}, + {0,156},{0,230},{4,1},{2,1},{0,110},{0,216},{2,1},{0,141},{0,187},{8,1}, + {4,1},{2,1},{0,231},{0,157},{2,1},{0,232},{0,142},{4,1},{2,1},{0,203}, + {0,188},{0,158},{0,241},{2,1},{0,31},{2,1},{0,15},{0,47},{66,1},{56,1}, + {2,1},{0,242},{52,1},{50,1},{20,1},{8,1},{2,1},{0,189},{2,1},{0,94}, + {2,1},{0,125},{0,201},{6,1},{2,1},{0,202},{2,1},{0,172},{0,126},{4,1}, + {2,1},{0,218},{0,173},{0,204},{10,1},{6,1},{2,1},{0,174},{2,1},{0,219}, + {0,220},{2,1},{0,205},{0,190},{6,1},{4,1},{2,1},{0,235},{0,237},{0,238}, + {6,1},{4,1},{2,1},{0,217},{0,234},{0,233},{2,1},{0,222},{4,1},{2,1}, + {0,221},{0,236},{0,206},{0,63},{0,240},{4,1},{2,1},{0,243},{0,244},{2,1}, + {0,79},{2,1},{0,245},{0,95},{10,1},{2,1},{0,255},{4,1},{2,1},{0,246}, + {0,111},{2,1},{0,247},{0,127},{12,1},{6,1},{2,1},{0,143},{2,1},{0,248}, + {0,249},{4,1},{2,1},{0,159},{0,250},{0,175},{8,1},{4,1},{2,1},{0,251}, + {0,191},{2,1},{0,252},{0,207},{4,1},{2,1},{0,253},{0,223},{2,1},{0,254}, + {0,239}, + }; + + private static int ValTab24[][] = { + {60,1},{8,1},{4,1},{2,1},{0,0},{0,16},{2,1},{0,1},{0,17},{14,1}, + {6,1},{4,1},{2,1},{0,32},{0,2},{0,33},{2,1},{0,18},{2,1},{0,34}, + {2,1},{0,48},{0,3},{14,1},{4,1},{2,1},{0,49},{0,19},{4,1},{2,1}, + {0,50},{0,35},{4,1},{2,1},{0,64},{0,4},{0,65},{8,1},{4,1},{2,1}, + {0,20},{0,51},{2,1},{0,66},{0,36},{6,1},{4,1},{2,1},{0,67},{0,52}, + {0,81},{6,1},{4,1},{2,1},{0,80},{0,5},{0,21},{2,1},{0,82},{0,37}, + {250,1},{98,1},{34,1},{18,1},{10,1},{4,1},{2,1},{0,68},{0,83},{2,1}, + {0,53},{2,1},{0,96},{0,6},{4,1},{2,1},{0,97},{0,22},{2,1},{0,98}, + {0,38},{8,1},{4,1},{2,1},{0,84},{0,69},{2,1},{0,99},{0,54},{4,1}, + {2,1},{0,113},{0,85},{2,1},{0,100},{0,70},{32,1},{14,1},{6,1},{2,1}, + {0,114},{2,1},{0,39},{0,55},{2,1},{0,115},{4,1},{2,1},{0,112},{0,7}, + {0,23},{10,1},{4,1},{2,1},{0,101},{0,86},{4,1},{2,1},{0,128},{0,8}, + {0,129},{4,1},{2,1},{0,116},{0,71},{2,1},{0,24},{0,130},{16,1},{8,1}, + {4,1},{2,1},{0,40},{0,102},{2,1},{0,131},{0,56},{4,1},{2,1},{0,117}, + {0,87},{2,1},{0,132},{0,72},{8,1},{4,1},{2,1},{0,145},{0,25},{2,1}, + {0,146},{0,118},{4,1},{2,1},{0,103},{0,41},{2,1},{0,133},{0,88},{92,1}, + {34,1},{16,1},{8,1},{4,1},{2,1},{0,147},{0,57},{2,1},{0,148},{0,73}, + {4,1},{2,1},{0,119},{0,134},{2,1},{0,104},{0,161},{8,1},{4,1},{2,1}, + {0,162},{0,42},{2,1},{0,149},{0,89},{4,1},{2,1},{0,163},{0,58},{2,1}, + {0,135},{2,1},{0,120},{0,74},{22,1},{12,1},{4,1},{2,1},{0,164},{0,150}, + {4,1},{2,1},{0,105},{0,177},{2,1},{0,27},{0,165},{6,1},{2,1},{0,178}, + {2,1},{0,90},{0,43},{2,1},{0,136},{0,179},{16,1},{10,1},{6,1},{2,1}, + {0,144},{2,1},{0,9},{0,160},{2,1},{0,151},{0,121},{4,1},{2,1},{0,166}, + {0,106},{0,180},{12,1},{6,1},{2,1},{0,26},{2,1},{0,10},{0,176},{2,1}, + {0,59},{2,1},{0,11},{0,192},{4,1},{2,1},{0,75},{0,193},{2,1},{0,152}, + {0,137},{67,1},{34,1},{16,1},{8,1},{4,1},{2,1},{0,28},{0,181},{2,1}, + {0,91},{0,194},{4,1},{2,1},{0,44},{0,167},{2,1},{0,122},{0,195},{10,1}, + {6,1},{2,1},{0,60},{2,1},{0,12},{0,208},{2,1},{0,182},{0,107},{4,1}, + {2,1},{0,196},{0,76},{2,1},{0,153},{0,168},{16,1},{8,1},{4,1},{2,1}, + {0,138},{0,197},{2,1},{0,92},{0,209},{4,1},{2,1},{0,183},{0,123},{2,1}, + {0,29},{0,210},{9,1},{4,1},{2,1},{0,45},{0,211},{2,1},{0,61},{0,198}, + {85,250},{4,1},{2,1},{0,108},{0,169},{2,1},{0,154},{0,212},{32,1},{16,1}, + {8,1},{4,1},{2,1},{0,184},{0,139},{2,1},{0,77},{0,199},{4,1},{2,1}, + {0,124},{0,213},{2,1},{0,93},{0,225},{8,1},{4,1},{2,1},{0,30},{0,226}, + {2,1},{0,170},{0,185},{4,1},{2,1},{0,155},{0,227},{2,1},{0,214},{0,109}, + {20,1},{10,1},{6,1},{2,1},{0,62},{2,1},{0,46},{0,78},{2,1},{0,200}, + {0,140},{4,1},{2,1},{0,228},{0,215},{4,1},{2,1},{0,125},{0,171},{0,229}, + {10,1},{4,1},{2,1},{0,186},{0,94},{2,1},{0,201},{2,1},{0,156},{0,110}, + {8,1},{2,1},{0,230},{2,1},{0,13},{2,1},{0,224},{0,14},{4,1},{2,1}, + {0,216},{0,141},{2,1},{0,187},{0,202},{74,1},{2,1},{0,255},{64,1},{58,1}, + {32,1},{16,1},{8,1},{4,1},{2,1},{0,172},{0,231},{2,1},{0,126},{0,217}, + {4,1},{2,1},{0,157},{0,232},{2,1},{0,142},{0,203},{8,1},{4,1},{2,1}, + {0,188},{0,218},{2,1},{0,173},{0,233},{4,1},{2,1},{0,158},{0,204},{2,1}, + {0,219},{0,189},{16,1},{8,1},{4,1},{2,1},{0,234},{0,174},{2,1},{0,220}, + {0,205},{4,1},{2,1},{0,235},{0,190},{2,1},{0,221},{0,236},{8,1},{4,1}, + {2,1},{0,206},{0,237},{2,1},{0,222},{0,238},{0,15},{4,1},{2,1},{0,240}, + {0,31},{0,241},{4,1},{2,1},{0,242},{0,47},{2,1},{0,243},{0,63},{18,1}, + {8,1},{4,1},{2,1},{0,244},{0,79},{2,1},{0,245},{0,95},{4,1},{2,1}, + {0,246},{0,111},{2,1},{0,247},{2,1},{0,127},{0,143},{10,1},{4,1},{2,1}, + {0,248},{0,249},{4,1},{2,1},{0,159},{0,175},{0,250},{8,1},{4,1},{2,1}, + {0,251},{0,191},{2,1},{0,252},{0,207},{4,1},{2,1},{0,253},{0,223},{2,1}, + {0,254},{0,239}, + }; + + private static int ValTab32[][] = { + {2,1},{0,0},{8,1},{4,1},{2,1},{0,8},{0,4},{2,1},{0,1},{0,2}, + {8,1},{4,1},{2,1},{0,12},{0,10},{2,1},{0,3},{0,6},{6,1},{2,1}, + {0,9},{2,1},{0,5},{0,7},{4,1},{2,1},{0,14},{0,13},{2,1},{0,15}, + {0,11}, + }; + + private static int ValTab33[][] = { + {16,1},{8,1},{4,1},{2,1},{0,0},{0,1},{2,1},{0,2},{0,3},{4,1}, + {2,1},{0,4},{0,5},{2,1},{0,6},{0,7},{8,1},{4,1},{2,1},{0,8}, + {0,9},{2,1},{0,10},{0,11},{4,1},{2,1},{0,12},{0,13},{2,1},{0,14}, + {0,15}, + }; + + + public static huffcodetab[] ht = null; /* Simulate extern struct */ + + private static int[] bitbuf = new int[32]; + + /** + * Big Constructor : Computes all Huffman Tables. + */ + private huffcodetab(String S,int XLEN, int YLEN, int LINBITS, int LINMAX, int REF, + int[] TABLE, int[] HLEN, int[][] VAL, int TREELEN) + { + tablename0 = S.charAt(0); + tablename1 = S.charAt(1); + tablename2 = S.charAt(2); + xlen = XLEN; + ylen = YLEN; + linbits = LINBITS; + linmax = LINMAX; + ref = REF; + table = TABLE; + hlen = HLEN; + val = VAL; + treelen = TREELEN; + } + + + + /** + * Do the Huffman decoding. + * note! for counta,countb -the 4 bit value is returned in y, + * discard x. + */ + public static int huffman_decoder(huffcodetab h, int[] x, int[] y, int[] v, int[] w, BitReserve br) + { + // array of all huffcodtable headers + // 0..31 Huffman code table 0..31 + // 32,33 count1-tables + + int dmask = 1 << ((4 * 8) - 1); + int hs = 4 * 8; + int level; + int point = 0; + int error = 1; + level = dmask; + + if (h.val == null) return 2; + + /* table 0 needs no bits */ + if ( h.treelen == 0) + { + x[0] = y[0] = 0; + return 0; + } + + /* Lookup in Huffman table. */ + + /*int bitsAvailable = 0; + int bitIndex = 0; + + int bits[] = bitbuf;*/ + do + { + if (h.val[point][0]==0) + { /*end of tree*/ + x[0] = h.val[point][1] >>> 4; + y[0] = h.val[point][1] & 0xf; + error = 0; + break; + } + + // hget1bit() is called thousands of times, and so needs to be + // ultra fast. + /* + if (bitIndex==bitsAvailable) + { + bitsAvailable = br.readBits(bits, 32); + bitIndex = 0; + } + */ + //if (bits[bitIndex++]!=0) + if (br.hget1bit()!=0) + { + while (h.val[point][1] >= MXOFF) point += h.val[point][1]; + point += h.val[point][1]; + } + else + { + while (h.val[point][0] >= MXOFF) point += h.val[point][0]; + point += h.val[point][0]; + } + level >>>= 1; + // MDM: ht[0] is always 0; + } while ((level !=0 ) || (point < 0 /*ht[0].treelen*/) ); + + // put back any bits not consumed + /* + int unread = (bitsAvailable-bitIndex); + if (unread>0) + br.rewindNbits(unread); + */ + /* Process sign encodings for quadruples tables. */ + // System.out.println(h.tablename); + if (h.tablename0 == '3' && (h.tablename1 == '2' || h.tablename1 == '3')) + { + v[0] = (y[0]>>3) & 1; + w[0] = (y[0]>>2) & 1; + x[0] = (y[0]>>1) & 1; + y[0] = y[0] & 1; + + /* v, w, x and y are reversed in the bitstream. + switch them around to make test bistream work. */ + + if (v[0]!=0) + if (br.hget1bit() != 0) v[0] = -v[0]; + if (w[0]!=0) + if (br.hget1bit() != 0) w[0] = -w[0]; + if (x[0]!=0) + if (br.hget1bit() != 0) x[0] = -x[0]; + if (y[0]!=0) + if (br.hget1bit() != 0) y[0] = -y[0]; + } + else + { + // Process sign and escape encodings for dual tables. + // x and y are reversed in the test bitstream. + // Reverse x and y here to make test bitstream work. + + if (h.linbits != 0) + if ((h.xlen-1) == x[0]) + x[0] += br.hgetbits(h.linbits); + if (x[0] != 0) + if (br.hget1bit() != 0) x[0] = -x[0]; + if (h.linbits != 0) + if ((h.ylen-1) == y[0]) + y[0] += br.hgetbits(h.linbits); + if (y[0] != 0) + if (br.hget1bit() != 0) y[0] = -y[0]; + } + return error; + } + + public static void inithuff() + { + + if (ht!=null) + return; + + ht = new huffcodetab[HTN]; + ht[0] = new huffcodetab("0 ",0,0,0,0,-1,null,null,ValTab0,0); + ht[1] = new huffcodetab("1 ",2,2,0,0,-1,null,null,ValTab1,7); + ht[2] = new huffcodetab("2 ",3,3,0,0,-1,null,null,ValTab2,17); + ht[3] = new huffcodetab("3 ",3,3,0,0,-1,null,null,ValTab3,17); + ht[4] = new huffcodetab("4 ",0,0,0,0,-1,null,null,ValTab4,0); + ht[5] = new huffcodetab("5 ",4,4,0,0,-1,null,null,ValTab5,31); + ht[6] = new huffcodetab("6 ",4,4,0,0,-1,null,null,ValTab6,31); + ht[7] = new huffcodetab("7 ",6,6,0,0,-1,null,null,ValTab7,71); + ht[8] = new huffcodetab("8 ",6,6,0,0,-1,null,null,ValTab8,71); + ht[9] = new huffcodetab("9 ",6,6,0,0,-1,null,null,ValTab9,71); + ht[10] = new huffcodetab("10 ",8,8,0,0,-1,null,null,ValTab10,127); + ht[11] = new huffcodetab("11 ",8,8,0,0,-1,null,null,ValTab11,127); + ht[12] = new huffcodetab("12 ",8,8,0,0,-1,null,null,ValTab12,127); + ht[13] = new huffcodetab("13 ",16,16,0,0,-1,null,null,ValTab13,511); + ht[14] = new huffcodetab("14 ",0,0,0,0,-1,null,null,ValTab14,0); + ht[15] = new huffcodetab("15 ",16,16,0,0,-1,null,null,ValTab15,511); + ht[16] = new huffcodetab("16 ",16,16,1,1,-1,null,null,ValTab16,511); + ht[17] = new huffcodetab("17 ",16,16,2,3,16,null,null,ValTab16,511); + ht[18] = new huffcodetab("18 ",16,16,3,7,16,null,null,ValTab16,511); + ht[19] = new huffcodetab("19 ",16,16,4,15,16,null,null,ValTab16,511); + ht[20] = new huffcodetab("20 ",16,16,6,63,16,null,null,ValTab16,511); + ht[21] = new huffcodetab("21 ",16,16,8,255,16,null,null,ValTab16,511); + ht[22] = new huffcodetab("22 ",16,16,10,1023,16,null,null,ValTab16,511); + ht[23] = new huffcodetab("23 ",16,16,13,8191,16,null,null,ValTab16,511); + ht[24] = new huffcodetab("24 ",16,16,4,15,-1,null,null,ValTab24,512); + ht[25] = new huffcodetab("25 ",16,16,5,31,24,null,null,ValTab24,512); + ht[26] = new huffcodetab("26 ",16,16,6,63,24,null,null,ValTab24,512); + ht[27] = new huffcodetab("27 ",16,16,7,127,24,null,null,ValTab24,512); + ht[28] = new huffcodetab("28 ",16,16,8,255,24,null,null,ValTab24,512); + ht[29] = new huffcodetab("29 ",16,16,9,511,24,null,null,ValTab24,512); + ht[30] = new huffcodetab("30 ",16,16,11,2047,24,null,null,ValTab24,512); + ht[31] = new huffcodetab("31 ",16,16,13,8191,24,null,null,ValTab24,512); + ht[32] = new huffcodetab("32 ",1,16,0,0,-1,null,null,ValTab32,31); + ht[33] = new huffcodetab("33 ",1,16,0,0,-1,null,null,ValTab33,31); + } +} diff --git a/src/lwjgl/java/javazoom/jl/decoder/l3reorder.ser b/src/lwjgl/java/javazoom/jl/decoder/l3reorder.ser new file mode 100644 index 0000000..da216fc Binary files /dev/null and b/src/lwjgl/java/javazoom/jl/decoder/l3reorder.ser differ diff --git a/src/lwjgl/java/javazoom/jl/decoder/lin2au.ser b/src/lwjgl/java/javazoom/jl/decoder/lin2au.ser new file mode 100644 index 0000000..ec1c83d Binary files /dev/null and b/src/lwjgl/java/javazoom/jl/decoder/lin2au.ser differ diff --git a/src/lwjgl/java/javazoom/jl/decoder/readme.txt b/src/lwjgl/java/javazoom/jl/decoder/readme.txt new file mode 100644 index 0000000..7a765ec --- /dev/null +++ b/src/lwjgl/java/javazoom/jl/decoder/readme.txt @@ -0,0 +1,15 @@ + +TODO: + + +Implement high-level Player and Converter classes. + +Add MP1 and MP2 support and test. + +Add option to run each "stage" on own thread. +E.g. read & parse input, decode subbands, subband synthesis, audio output. + +Retrofit seek support (temporarily removed when reworking classes.) + + +Document and give example code. \ No newline at end of file diff --git a/src/lwjgl/java/javazoom/jl/decoder/sfd.ser b/src/lwjgl/java/javazoom/jl/decoder/sfd.ser new file mode 100644 index 0000000..440c7c6 Binary files /dev/null and b/src/lwjgl/java/javazoom/jl/decoder/sfd.ser differ diff --git a/src/lwjgl/java/javazoom/mp3spi/DecodedMpegAudioInputStream.java b/src/lwjgl/java/javazoom/mp3spi/DecodedMpegAudioInputStream.java new file mode 100644 index 0000000..b908f49 --- /dev/null +++ b/src/lwjgl/java/javazoom/mp3spi/DecodedMpegAudioInputStream.java @@ -0,0 +1,265 @@ +/* + * DecodedMpegAudioInputStream. + * + * JavaZOOM : mp3spi@javazoom.net + * http://www.javazoom.net + * + * Copyright (c) 2012 by fireandfuel from Cuina Team (http://www.cuina.byethost12.com/) + * + *----------------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *------------------------------------------------------------------------ + */ + +package javazoom.mp3spi; + +import java.io.IOException; +import java.io.InputStream; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; + +import tritonus.TAsynchronousFilteredAudioInputStream; + +import javazoom.jl.decoder.Bitstream; +import javazoom.jl.decoder.BitstreamException; +import javazoom.jl.decoder.Decoder; +import javazoom.jl.decoder.DecoderException; +import javazoom.jl.decoder.Header; +import javazoom.jl.decoder.Obuffer; + +/** + * Main decoder. + */ +public class DecodedMpegAudioInputStream extends TAsynchronousFilteredAudioInputStream +{ + private InputStream m_encodedStream; + private Bitstream m_bitstream; + private Decoder m_decoder; + private Header m_header; + private DMAISObuffer m_oBuffer; + + // Bytes info. + private long byteslength = -1; + private long currentByte = 0; + // Frame info. + private int frameslength = -1; + private long currentFrame = 0; + private int currentFramesize = 0; + + public DecodedMpegAudioInputStream(AudioFormat outputFormat, + AudioInputStream bufferedInputStream) + { + super(outputFormat, -1); + + try + { + // Try to find out inputstream length to allow skip. + byteslength = bufferedInputStream.available(); + } catch (IOException e) + { + byteslength = -1; + } + m_encodedStream = bufferedInputStream; + m_bitstream = new Bitstream(bufferedInputStream); + m_decoder = new Decoder(null); + // m_equalizer = new Equalizer(); + // m_equalizer_values = new float[32]; + // for (int b=0;b 0)) + frameslength = m_header.max_number_of_frames((int) byteslength); + } catch (BitstreamException e) + { + + byteslength = -1; + } + } + + public void execute()// if( reverseBytes ) + // reverseBytes( smallBuffer, 0, bytesRead ); + { + + try + { + // Following line hangs when FrameSize is available in AudioFormat. + Header header = null; + if(m_header == null) + header = m_bitstream.readFrame(); + else header = m_header; + + if(header == null) + { + + getCircularBuffer().close(); + return; + } + currentFrame++; + currentFramesize = header.calculate_framesize(); + currentByte = currentByte + currentFramesize; + // Obuffer decoderOutput = + m_decoder.decodeFrame(header, m_bitstream); + m_bitstream.closeFrame(); + getCircularBuffer().write(m_oBuffer.getBuffer(), 0, m_oBuffer.getCurrentBufferSize()); + m_oBuffer.reset(); + if(m_header != null) + m_header = null; + } catch (BitstreamException e) + { + + } catch (DecoderException e) + { + + } + + } + + public long skip(long bytes) + { + if((byteslength > 0) && (frameslength > 0)) + { + float ratio = bytes * 1.0f / byteslength * 1.0f; + long bytesread = skipFrames((long) (ratio * frameslength)); + currentByte = currentByte + bytesread; + m_header = null; + return bytesread; + } else return -1; + } + + /** + * Skip frames. You don't need to call it severals times, it will exactly + * skip given frames number. + * + * @param frames + * @return bytes length skipped matching to frames skipped. + */ + public long skipFrames(long frames) + { + + int framesRead = 0; + int bytesReads = 0; + try + { + for(int i = 0; i < frames; i++) + { + Header header = m_bitstream.readFrame(); + if(header != null) + { + int fsize = header.calculate_framesize(); + bytesReads = bytesReads + fsize; + } + m_bitstream.closeFrame(); + framesRead++; + } + } catch (BitstreamException e) + { + + } + + currentFrame = currentFrame + framesRead; + return bytesReads; + } + + private boolean isBigEndian() + { + return getFormat().isBigEndian(); + } + + public void close() throws IOException + { + super.close(); + m_encodedStream.close(); + } + + private class DMAISObuffer extends Obuffer + { + private int m_nChannels; + private byte[] m_abBuffer; + private int[] m_anBufferPointers; + private boolean m_bIsBigEndian; + + public DMAISObuffer(int nChannels) + { + m_nChannels = nChannels; + m_abBuffer = new byte[OBUFFERSIZE * nChannels]; + m_anBufferPointers = new int[nChannels]; + reset(); + m_bIsBigEndian = DecodedMpegAudioInputStream.this.isBigEndian(); + } + + public void append(int nChannel, short sValue) + { + byte bFirstByte; + byte bSecondByte; + if(m_bIsBigEndian) + { + bFirstByte = (byte) ((sValue >>> 8) & 0xFF); + bSecondByte = (byte) (sValue & 0xFF); + } else + // little endian + { + bFirstByte = (byte) (sValue & 0xFF); + bSecondByte = (byte) ((sValue >>> 8) & 0xFF); + } + m_abBuffer[m_anBufferPointers[nChannel]] = bFirstByte; + m_abBuffer[m_anBufferPointers[nChannel] + 1] = bSecondByte; + m_anBufferPointers[nChannel] += m_nChannels * 2; + } + + public void set_stop_flag() + { + } + + public void close() + { + } + + public void write_buffer(int nValue) + { + } + + public void clear_buffer() + { + } + + public byte[] getBuffer() + { + return m_abBuffer; + } + + public int getCurrentBufferSize() + { + return m_anBufferPointers[0]; + } + + public void reset() + { + for(int i = 0; i < m_nChannels; i++) + { + /* + * Points to byte location, implicitely assuming 16 bit samples. + */ + m_anBufferPointers[i] = i * 2; + } + } + } +} diff --git a/src/lwjgl/java/net/lax1dude/eaglercraft/MinecraftMain.java b/src/lwjgl/java/net/lax1dude/eaglercraft/MinecraftMain.java new file mode 100644 index 0000000..4195f47 --- /dev/null +++ b/src/lwjgl/java/net/lax1dude/eaglercraft/MinecraftMain.java @@ -0,0 +1,31 @@ +package net.lax1dude.eaglercraft; + +import java.lang.management.ManagementFactory; + +import javax.swing.JOptionPane; + +import net.minecraft.src.Minecraft; +import net.minecraft.src.ServerList; + +public class MinecraftMain { + + public static void main(String[] par0ArrayOfStr) { + + JOptionPane.showMessageDialog(null, "launch renderdoc (optionally) and press ok to continue", "eaglercraft: " + ManagementFactory.getRuntimeMXBean().getName(), JOptionPane.PLAIN_MESSAGE); + + EaglerAdapter.initializeContext(); + LocalStorageManager.loadStorage(); + + byte[] b = EaglerAdapter.loadLocalStorage("forced"); + if(b != null) { + ServerList.loadDefaultServers(Base64.encodeBase64String(b)); + } + if(par0ArrayOfStr.length > 0) { + EaglerAdapter.setServerToJoinOnLaunch(par0ArrayOfStr[0]); + } + + Minecraft mc = new Minecraft(); + mc.run(); + + } +} diff --git a/src/lwjgl/java/net/lax1dude/eaglercraft/adapter/EaglerAdapterImpl2.java b/src/lwjgl/java/net/lax1dude/eaglercraft/adapter/EaglerAdapterImpl2.java new file mode 100644 index 0000000..6d787a1 --- /dev/null +++ b/src/lwjgl/java/net/lax1dude/eaglercraft/adapter/EaglerAdapterImpl2.java @@ -0,0 +1,2025 @@ +package net.lax1dude.eaglercraft.adapter; + +import java.awt.BorderLayout; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.HeadlessException; +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +import javax.imageio.ImageIO; +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.filechooser.FileFilter; + +import org.java_websocket.client.WebSocketClient; +import org.java_websocket.handshake.ServerHandshake; +import org.json.JSONObject; +import org.lwjgl.LWJGLException; +import org.lwjgl.Sys; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; +import org.lwjgl.openal.AL; +import org.lwjgl.opengl.ARBDebugOutput; +import org.lwjgl.opengl.ARBDebugOutputCallback; +import org.lwjgl.opengl.ARBOcclusionQuery2; +import org.lwjgl.opengl.ContextAttribs; +import org.lwjgl.opengl.Display; +import org.lwjgl.opengl.DisplayMode; +import org.lwjgl.opengl.EXTTextureFilterAnisotropic; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL14; +import org.lwjgl.opengl.GL15; +import org.lwjgl.opengl.GL20; +import org.lwjgl.opengl.GL30; +import org.lwjgl.opengl.PixelFormat; +import org.lwjgl.util.glu.GLU; + +import de.cuina.fireandfuel.CodecJLayerMP3; +import net.lax1dude.eaglercraft.AssetRepository; +import net.lax1dude.eaglercraft.EaglerImage; +import net.lax1dude.eaglercraft.EaglerInputStream; +import net.lax1dude.eaglercraft.EarlyLoadScreen; +import net.lax1dude.eaglercraft.LANPeerEvent; +import net.lax1dude.eaglercraft.PKT; +import net.lax1dude.eaglercraft.RelayQuery; +import net.lax1dude.eaglercraft.RelayServerSocket; +import net.lax1dude.eaglercraft.RelayQuery.VersionMismatch; +import net.lax1dude.eaglercraft.RelayWorldsQuery; +import net.lax1dude.eaglercraft.ServerQuery; +import net.lax1dude.eaglercraft.Voice; +import net.lax1dude.eaglercraft.adapter.lwjgl.GameWindowListener; +import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket; +import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket07LocalWorlds.LocalWorld; +import net.minecraft.src.MathHelper; +import paulscode.sound.SoundSystem; +import paulscode.sound.SoundSystemConfig; +import paulscode.sound.libraries.LibraryLWJGLOpenAL; + +public class EaglerAdapterImpl2 { + + public static final boolean _wisWebGL() { + return false; + } + public static final boolean _wisAnisotropicPatched() { + return true; + } + public static final String _wgetShaderHeader() { + return "#version 150"; + } + + public static final InputStream loadResource(String path) { + byte[] file = loadResourceBytes(path); + if (file != null) { + return new EaglerInputStream(file); + } else { + return null; + } + } + + public static final boolean isSSLPage() { + return true; + } + + public static final String[] getIdentifier() { + return new String[0]; + } + + private static final boolean useEPKTest = false; + + public static final byte[] loadResourceBytes(String path) { + if(useEPKTest) { + return AssetRepository.getResource(path); + }else { + try { + InputStream stream; + try { + stream = new FileInputStream(new File("resources", path)); + } catch (FileNotFoundException e) { + return null; + } + byte[] targetArray = new byte[stream.available()]; + stream.read(targetArray); + stream.close(); + return targetArray; + } catch (IOException e) { + return null; + } + } + } + + public static final String fileContents(String path) { + byte[] contents = loadResourceBytes(path); + if(contents == null) { + return null; + }else { + return new String(contents, Charset.forName("UTF-8")); + } + } + + public static final String[] fileContentsLines(String path) { + String contents = fileContents(path); + if(contents == null) { + return null; + }else { + return contents.replace("\r\n", "\n").split("[\r\n]"); + } + } + + public static final void setDebugVar(String v, String s) { + + } + + public static final int _wGL_TEXTURE_2D = GL11.GL_TEXTURE_2D; + public static final int _wGL_DEPTH_TEST = GL11.GL_DEPTH_TEST; + public static final int _wGL_LEQUAL = GL11.GL_LEQUAL; + public static final int _wGL_GEQUAL = GL11.GL_GEQUAL; + public static final int _wGL_GREATER = GL11.GL_GREATER; + public static final int _wGL_LESS = GL11.GL_LESS; + public static final int _wGL_BACK = GL11.GL_BACK; + public static final int _wGL_FRONT = GL11.GL_FRONT; + public static final int _wGL_FRONT_AND_BACK = GL11.GL_FRONT_AND_BACK; + public static final int _wGL_COLOR_BUFFER_BIT = GL11.GL_COLOR_BUFFER_BIT; + public static final int _wGL_DEPTH_BUFFER_BIT = GL11.GL_DEPTH_BUFFER_BIT; + public static final int _wGL_BLEND = GL11.GL_BLEND; + public static final int _wGL_RGBA = GL11.GL_RGBA; + public static final int _wGL_RGB = GL11.GL_RGB; + public static final int _wGL_RGB8 = GL11.GL_RGB8; + public static final int _wGL_RGBA8 = GL11.GL_RGBA8; + public static final int _wGL_UNSIGNED_BYTE = GL11.GL_UNSIGNED_BYTE; + public static final int _wGL_UNSIGNED_SHORT = GL11.GL_UNSIGNED_SHORT; + public static final int _wGL_TEXTURE_WIDTH = GL11.GL_TEXTURE_WIDTH; + public static final int _wGL_SRC_ALPHA = GL11.GL_SRC_ALPHA; + public static final int _wGL_ONE_MINUS_SRC_ALPHA = GL11.GL_ONE_MINUS_SRC_ALPHA; + public static final int _wGL_ONE_MINUS_DST_COLOR = GL11.GL_ONE_MINUS_DST_COLOR; + public static final int _wGL_ONE_MINUS_SRC_COLOR = GL11.GL_ONE_MINUS_SRC_COLOR; + public static final int _wGL_ZERO = GL11.GL_ZERO; + public static final int _wGL_CULL_FACE = GL11.GL_CULL_FACE; + public static final int _wGL_TEXTURE_MIN_FILTER = GL11.GL_TEXTURE_MIN_FILTER; + public static final int _wGL_TEXTURE_MAG_FILTER = GL11.GL_TEXTURE_MAG_FILTER; + public static final int _wGL_LINEAR = GL11.GL_LINEAR; + public static final int _wGL_NEAREST_MIPMAP_LINEAR = GL11.GL_NEAREST_MIPMAP_LINEAR; + public static final int _wGL_LINEAR_MIPMAP_LINEAR = GL11.GL_LINEAR_MIPMAP_LINEAR; + public static final int _wGL_LINEAR_MIPMAP_NEAREST = GL11.GL_LINEAR_MIPMAP_NEAREST; + public static final int _wGL_NEAREST_MIPMAP_NEAREST = GL11.GL_NEAREST_MIPMAP_NEAREST; + public static final int _wGL_EQUAL = GL11.GL_EQUAL; + public static final int _wGL_SRC_COLOR = GL11.GL_SRC_COLOR; + public static final int _wGL_ONE = GL11.GL_ONE; + public static final int _wGL_NEAREST = GL11.GL_NEAREST; + public static final int _wGL_CLAMP = GL12.GL_CLAMP_TO_EDGE; + public static final int _wGL_TEXTURE_WRAP_S = GL11.GL_TEXTURE_WRAP_S; + public static final int _wGL_TEXTURE_WRAP_T = GL11.GL_TEXTURE_WRAP_T; + public static final int _wGL_TEXTURE_MAX_LEVEL = GL12.GL_TEXTURE_MAX_LEVEL; + public static final int _wGL_REPEAT = GL11.GL_REPEAT; + public static final int _wGL_DST_COLOR = GL11.GL_DST_COLOR; + public static final int _wGL_DST_ALPHA = GL11.GL_DST_ALPHA; + public static final int _wGL_FLOAT = GL11.GL_FLOAT; + public static final int _wGL_SHORT = GL11.GL_SHORT; + public static final int _wGL_TRIANGLES = GL11.GL_TRIANGLES; + public static final int _wGL_TRIANGLE_STRIP = GL11.GL_TRIANGLE_STRIP; + public static final int _wGL_TRIANGLE_FAN = GL11.GL_TRIANGLE_FAN; + public static final int _wGL_LINE_STRIP = GL11.GL_LINE_STRIP; + public static final int _wGL_LINES = GL11.GL_LINES; + public static final int _wGL_PACK_ALIGNMENT = GL11.GL_PACK_ALIGNMENT; + public static final int _wGL_UNPACK_ALIGNMENT = GL11.GL_UNPACK_ALIGNMENT; + public static final int _wGL_TEXTURE0 = GL13.GL_TEXTURE0; + public static final int _wGL_TEXTURE1 = GL13.GL_TEXTURE1; + public static final int _wGL_TEXTURE2 = GL13.GL_TEXTURE2; + public static final int _wGL_TEXTURE3 = GL13.GL_TEXTURE3; + public static final int _wGL_VIEWPORT = GL11.GL_VIEWPORT; + public static final int _wGL_VERTEX_SHADER = GL20.GL_VERTEX_SHADER; + public static final int _wGL_FRAGMENT_SHADER = GL20.GL_FRAGMENT_SHADER; + public static final int _wGL_ARRAY_BUFFER = GL15.GL_ARRAY_BUFFER; + public static final int _wGL_ELEMENT_ARRAY_BUFFER = GL15.GL_ELEMENT_ARRAY_BUFFER; + public static final int _wGL_STATIC_DRAW = GL15.GL_STATIC_DRAW; + public static final int _wGL_DYNAMIC_DRAW = GL15.GL_DYNAMIC_DRAW; + public static final int _wGL_STREAM_DRAW = GL15.GL_STREAM_DRAW; + public static final int _wGL_INVALID_ENUM = GL11.GL_INVALID_ENUM; + public static final int _wGL_INVALID_VALUE= GL11.GL_INVALID_VALUE; + public static final int _wGL_INVALID_OPERATION = GL11.GL_INVALID_OPERATION; + public static final int _wGL_OUT_OF_MEMORY = GL11.GL_OUT_OF_MEMORY; + public static final int _wGL_CONTEXT_LOST_WEBGL = -1; + public static final int _wGL_FRAMEBUFFER_COMPLETE = GL30.GL_FRAMEBUFFER_COMPLETE; + public static final int _wGL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT = GL30.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + public static final int _wGL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = GL30.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; + public static final int _wGL_COLOR_ATTACHMENT0 = GL30.GL_COLOR_ATTACHMENT0; + public static final int _wGL_DEPTH_STENCIL_ATTACHMENT = GL30.GL_DEPTH_STENCIL_ATTACHMENT; + public static final int _wGL_DEPTH_ATTACHMENT = GL30.GL_DEPTH_ATTACHMENT; + public static final int _wGL_DEPTH_COMPONENT32F = GL30.GL_DEPTH_COMPONENT32F; + public static final int _wGL_DEPTH_STENCIL = GL30.GL_DEPTH_STENCIL; + public static final int _wGL_DEPTH24_STENCIL8 = GL30.GL_DEPTH24_STENCIL8; + public static final int _wGL_UNSIGNED_INT_24_8 = GL30.GL_UNSIGNED_INT_24_8; + public static final int _wGL_UNSIGNED_INT = GL11.GL_UNSIGNED_INT; + public static int _wGL_ANY_SAMPLES_PASSED = -1; + public static final int _wGL_QUERY_RESULT = GL15.GL_QUERY_RESULT; + public static final int _wGL_QUERY_RESULT_AVAILABLE = GL15.GL_QUERY_RESULT_AVAILABLE; + public static int _wGL_TEXTURE_MAX_ANISOTROPY = -1; + public static final int _wGL_R8 = GL30.GL_R8; + public static final int _wGL_R32UI = GL30.GL_R32UI; + public static final int _wGL_RED = GL11.GL_RED; + public static final int _wGL_RENDERBUFFER = GL30.GL_RENDERBUFFER; + public static final int _wGL_MULTISAMPLE = GL13.GL_MULTISAMPLE; + public static final int _wGL_LINE_SMOOTH = GL11.GL_LINE_SMOOTH; + public static final int _wGL_DRAW_FRAMEBUFFER = GL30.GL_DRAW_FRAMEBUFFER; + public static final int _wGL_READ_FRAMEBUFFER = GL30.GL_READ_FRAMEBUFFER; + public static final int _wGL_FRAMEBUFFER = GL30.GL_FRAMEBUFFER; + public static final int _wGL_POLYGON_OFFSET_FILL = GL11.GL_POLYGON_OFFSET_FILL; + + public static final class TextureGL { + protected final int obj; + public int w = -1; + public int h = -1; + public boolean nearest = true; + public boolean anisotropic = false; + protected TextureGL(int obj) { + this.obj = obj; + } + } + public static final class BufferGL { + protected final int obj; + protected BufferGL(int obj) { + this.obj = obj; + } + } + public static final class ShaderGL { + protected final int obj; + protected ShaderGL(int obj) { + this.obj = obj; + } + } + public static final class ProgramGL { + protected final int obj; + protected ProgramGL(int obj) { + this.obj = obj; + } + } + public static final class UniformGL { + protected final int obj; + protected UniformGL(int obj) { + this.obj = obj; + } + } + public static final class BufferArrayGL { + protected final int obj; + public boolean isQuadBufferBound; + protected BufferArrayGL(int obj) { + this.obj = obj; + this.isQuadBufferBound = false; + } + } + public static final class FramebufferGL { + protected final int obj; + protected FramebufferGL(int obj) { + this.obj = obj; + } + } + public static final class RenderbufferGL { + protected final int obj; + protected RenderbufferGL(int obj) { + this.obj = obj; + } + } + public static final class QueryGL { + protected final int obj; + protected QueryGL(int obj) { + this.obj = obj; + } + } + + public static final void _wglEnable(int p1) { + GL11.glEnable(p1); + } + public static final void _wglClearDepth(float p1) { + GL11.glClearDepth(p1); + } + public static final void _wglDepthFunc(int p1) { + GL11.glDepthFunc(p1); + } + public static final void _wglCullFace(int p1) { + GL11.glCullFace(p1); + } + private static final int[] viewport = new int[4]; + public static final void _wglViewport(int p1, int p2, int p3, int p4) { + viewport[0] = p1; viewport[1] = p2; + viewport[2] = p3; viewport[3] = p4; + GL11.glViewport(p1, p2, p3, p4); + } + public static final void _wglClear(int p1) { + GL11.glClear(p1); + } + public static final void _wglClearColor(float p1, float p2, float p3, float p4) { + GL11.glClearColor(p1, p2, p3, p4); + } + public static final void _wglDisable(int p1) { + GL11.glDisable(p1); + } + public static final int _wglGetError() { + return GL11.glGetError(); + } + public static final void _wglFlush() { + + } + public static final void _wglTexImage2D(int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, ByteBuffer p9) { + GL11.glTexImage2D(p1, p2, p3, p4, p5, p6, p7, p8, p9); + } + public static final void _wglBlendFunc(int p1, int p2) { + GL11.glBlendFunc(p1, p2); + } + public static final void _wglBlendFuncSeparate(int p1, int p2, int p3, int p4) { + GL14.glBlendFuncSeparate(p1, p2, p3, p4); + } + public static final void _wglBlendColor(float r, float g, float b, float a) { + GL14.glBlendColor(r, g, b, a); + } + public static final void _wglDepthMask(boolean p1) { + GL11.glDepthMask(p1); + } + public static final void _wglColorMask(boolean p1, boolean p2, boolean p3, boolean p4) { + GL11.glColorMask(p1, p2, p3, p4); + } + public static final void _wglBindTexture(int p1, TextureGL p2) { + GL11.glBindTexture(p1, p2 == null ? 0 : p2.obj); + } + public static final void _wglCopyTexSubImage2D(int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8) { + GL11.glCopyTexSubImage2D(p1, p2, p3, p4, p5, p6, p7, p8); + } + public static final void _wglTexParameteri(int p1, int p2, int p3) { + GL11.glTexParameteri(p1, p2, p3); + } + public static final void _wglTexParameterf(int p1, int p2, int p3) { + GL11.glTexParameterf(p1, p2, p3); + } + public static final void _wglTexImage2D(int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, IntBuffer p9) { + GL11.glTexImage2D(p1, p2, p3, p4, p5, p6, p7, p8, p9); + } + public static final void _wglTexSubImage2D(int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, IntBuffer p9) { + GL11.glTexSubImage2D(p1, p2, p3, p4, p5, p6, p7, p8, p9); + } + public static final void _wglDeleteTextures(TextureGL p1) { + GL11.glDeleteTextures(p1.obj); + } + public static final void _wglDrawArrays(int p1, int p2, int p3) { + GL11.glDrawArrays(p1, p2, p3); + } + public static final void _wglDrawElements(int p1, int p2, int p3, int p4) { + GL11.glDrawElements(p1, p2, p3, p4); + } + public static final TextureGL _wglGenTextures() { + return new TextureGL(GL11.glGenTextures()); + } + public static final void _wglTexSubImage2D(int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, ByteBuffer p9) { + GL11.glTexSubImage2D(p1, p2, p3, p4, p5, p6, p7, p8, p9); + } + public static final void _wglTexImage3D(int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, ByteBuffer p10) { + GL12.glTexImage3D(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); + } + public static final void _wglTexParameterf(int p1, int p2, float p3) { + GL11.glTexParameterf(p1, p2, p3); + } + public static final void _wglActiveTexture(int p1) { + GL13.glActiveTexture(p1); + } + public static final String _wgluErrorString(int p1) { + return GLU.gluErrorString(p1); + } + public static final ProgramGL _wglCreateProgram() { + return new ProgramGL(GL20.glCreateProgram()); + } + public static final ShaderGL _wglCreateShader(int p1) { + return new ShaderGL(GL20.glCreateShader(p1)); + } + public static final void _wglAttachShader(ProgramGL p1, ShaderGL p2) { + GL20.glAttachShader(p1.obj, p2.obj); + } + public static final void _wglDetachShader(ProgramGL p1, ShaderGL p2) { + GL20.glDetachShader(p1.obj, p2.obj); + } + public static final void _wglCompileShader(ShaderGL p1) { + GL20.glCompileShader(p1.obj); + } + public static final void _wglLinkProgram(ProgramGL p1) { + GL20.glLinkProgram(p1.obj); + } + public static final void _wglShaderSource(ShaderGL p1, String p2) { + GL20.glShaderSource(p1.obj, p2); + } + public static final String _wglGetShaderInfoLog(ShaderGL p1) { + return GL20.glGetShaderInfoLog(p1.obj, 8192); + } + public static final String _wglGetProgramInfoLog(ProgramGL p1) { + return GL20.glGetProgramInfoLog(p1.obj, 8192); + } + public static final boolean _wglGetShaderCompiled(ShaderGL p1) { + return GL20.glGetShaderi(p1.obj, GL20.GL_COMPILE_STATUS) == GL11.GL_TRUE; + } + public static final boolean _wglGetProgramLinked(ProgramGL p1) { + return GL20.glGetProgrami(p1.obj, GL20.GL_LINK_STATUS) == GL11.GL_TRUE; + } + public static final void _wglDeleteShader(ShaderGL p1) { + GL20.glDeleteShader(p1.obj); + } + public static final void _wglDeleteProgram(ProgramGL p1) { + GL20.glDeleteProgram(p1.obj); + } + public static final BufferArrayGL _wglCreateVertexArray() { + return new BufferArrayGL(GL30.glGenVertexArrays()); + } + public static final void _wglDeleteVertexArray(BufferArrayGL p1) { + GL30.glDeleteVertexArrays(p1.obj); + } + public static final void _wglBindVertexArray(BufferArrayGL p1) { + GL30.glBindVertexArray(p1 == null ? 0 : p1.obj); + } + public static final BufferGL _wglCreateBuffer() { + return new BufferGL(GL15.glGenBuffers()); + } + public static final void _wglDeleteBuffer(BufferGL p1) { + GL15.glDeleteBuffers(p1.obj); + } + public static final void _wglBindBuffer(int p1, BufferGL p2) { + GL15.glBindBuffer(p1, p2 == null ? 0 : p2.obj); + } + public static final void _wglBufferData(int p1, Object p2, int p3) { + GL15.glBufferData(p1, (IntBuffer)p2, p3); + } + public static final void _wglBufferSubData(int p1, int p2, Object p3) { + GL15.glBufferSubData(p1, p2, (IntBuffer)p3); + } + public static final void _wglBufferData0(int p1, IntBuffer p2, int p3) { + GL15.glBufferData(p1, p2, p3); + } + public static final void _wglBufferData00(int p1, long len, int p3) { + GL15.glBufferData(p1, len, p3); + } + public static final void _wglBufferSubData0(int p1, int p2, IntBuffer p3) { + GL15.glBufferSubData(p1, p2, p3); + } + public static final void _wglBindAttribLocation(int p1, int p2, String p3) { + GL20.glBindAttribLocation(p1, p2, p3); + } + public static final void _wglEnableVertexAttribArray(int p1) { + GL20.glEnableVertexAttribArray(p1); + } + public static final void _wglDisableVertexAttribArray(int p1) { + GL20.glDisableVertexAttribArray(p1); + } + public static final UniformGL _wglGetUniformLocation(ProgramGL p1, String p2) { + int u = GL20.glGetUniformLocation(p1.obj, p2); + return u == -1 ? null : new UniformGL(u); + } + public static final void _wglBindAttributeLocation(ProgramGL p1, int p2, String p3) { + GL20.glBindAttribLocation(p1.obj, p2, p3); + } + public static final void _wglUniform1f(UniformGL p1, float p2) { + if(p1 != null) GL20.glUniform1f(p1.obj, p2); + } + public static final void _wglUniform2f(UniformGL p1, float p2, float p3) { + if(p1 != null) GL20.glUniform2f(p1.obj, p2, p3); + } + public static final void _wglUniform3f(UniformGL p1, float p2, float p3, float p4) { + if(p1 != null) GL20.glUniform3f(p1.obj, p2, p3, p4); + } + public static final void _wglUniform4f(UniformGL p1, float p2, float p3, float p4, float p5) { + if(p1 != null) GL20.glUniform4f(p1.obj, p2, p3, p4, p5); + } + public static final void _wglUniform1i(UniformGL p1, int p2) { + if(p1 != null) GL20.glUniform1i(p1.obj, p2); + } + public static final void _wglUniform2i(UniformGL p1, int p2, int p3) { + if(p1 != null) GL20.glUniform2i(p1.obj, p2, p3); + } + public static final void _wglUniform3i(UniformGL p1, int p2, int p3, int p4) { + if(p1 != null) GL20.glUniform3i(p1.obj, p2, p3, p4); + } + public static final void _wglUniform4i(UniformGL p1, int p2, int p3, int p4, int p5) { + if(p1 != null) GL20.glUniform4i(p1.obj, p2, p3, p4, p5); + } + private static final FloatBuffer matUpload = ByteBuffer.allocateDirect(16 << 2).order(ByteOrder.nativeOrder()).asFloatBuffer(); + public static final void _wglUniformMat2fv(UniformGL p1, float[] mat) { + matUpload.clear(); + matUpload.put(mat); + matUpload.flip(); + if(p1 != null) GL20.glUniformMatrix2(p1.obj, false, matUpload); + } + public static final void _wglUniformMat3fv(UniformGL p1, float[] mat) { + matUpload.clear(); + matUpload.put(mat); + matUpload.flip(); + if(p1 != null) GL20.glUniformMatrix3(p1.obj, false, matUpload); + } + public static final void _wglUniformMat4fv(UniformGL p1, float[] mat) { + matUpload.clear(); + matUpload.put(mat); + matUpload.flip(); + if(p1 != null) GL20.glUniformMatrix4(p1.obj, false, matUpload); + } + private static int currentProgram = 0; + public static final void _wglUseProgram(ProgramGL p1) { + int i = p1 == null ? 0 : p1.obj; + if(i != currentProgram) { + currentProgram = i; + GL20.glUseProgram(i); + } + } + public static final void _wglGetParameter(int p1, int size, int[] p3) { + if(p1 == _wGL_VIEWPORT) { + p3[0] = viewport[0]; p3[1] = viewport[1]; + p3[2] = viewport[2]; p3[3] = viewport[3]; + } + } + public static final void _wglPolygonOffset(float p1, float p2) { + GL11.glPolygonOffset(p1, p2); + } + public static final void _wglVertexAttribPointer(int p1, int p2, int p3, boolean p4, int p5, int p6) { + GL20.glVertexAttribPointer(p1, p2, p3, p4, p5, p6); + } + public static final void _wglBindFramebuffer(int p1, FramebufferGL p2) { + GL30.glBindFramebuffer(p1, p2 == null ? 0 : p2.obj); + } + public static final void _wglReadBuffer(int p1) { + GL11.glReadBuffer(p1); + } + public static final void _wglDrawBuffer(int p1) { + GL11.glDrawBuffer(p1); + } + public static final void _wglBlitFramebuffer(int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int p10) { + GL30.glBlitFramebuffer(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); + } + public static final FramebufferGL _wglCreateFramebuffer() { + return new FramebufferGL(GL30.glGenFramebuffers()); + } + public static final void _wglDeleteFramebuffer(FramebufferGL p1) { + GL30.glDeleteFramebuffers(p1.obj); + } + public static final void _wglFramebufferTexture2D(int p1, TextureGL p2) { + GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, p1, GL11.GL_TEXTURE_2D, p2.obj, 0); + } + public static final void _wglFramebufferTexture2D(int p1, TextureGL p2, int lvl) { + GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, p1, GL11.GL_TEXTURE_2D, p2.obj, lvl); + } + public static final RenderbufferGL _wglCreateRenderBuffer() { + return new RenderbufferGL(GL30.glGenRenderbuffers()); + } + public static final void _wglDeleteRenderbuffer(RenderbufferGL p1) { + GL30.glDeleteRenderbuffers(p1.obj); + } + public static final void _wglBindRenderbuffer(RenderbufferGL p1) { + GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, p1 == null ? 0 : p1.obj); + } + public static final void _wglRenderbufferStorage(int p1, int p2, int p3) { + GL30.glRenderbufferStorage(GL30.GL_RENDERBUFFER, p1, p2, p3); + } + public static final void _wglRenderbufferStorageMultisample(int p1, int p2, int p3, int p4) { + GL30.glRenderbufferStorageMultisample(GL30.GL_RENDERBUFFER, p1, p2, p3, p4); + } + public static final void _wglFramebufferRenderbuffer(int p1, RenderbufferGL p2) { + GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, p1, GL30.GL_RENDERBUFFER, p2.obj); + } + public static final QueryGL _wglCreateQuery() { + return new QueryGL(GL15.glGenQueries()); + } + public static final void _wglBeginQuery(int p1, QueryGL p2) { + GL15.glBeginQuery(p1, p2.obj); + } + public static final void _wglEndQuery(int p1) { + GL15.glEndQuery(p1); + } + public static final void _wglDeleteQuery(QueryGL p1) { + GL15.glDeleteQueries(p1.obj); + } + public static final int _wglGetQueryObjecti(QueryGL p1, int p2) { + return GL15.glGetQueryObjecti(p1.obj, p2); + } + public static final void _wglLineWidth(float p1) { + GL11.glLineWidth(p1); + } + public static final int _wglGetTexParameteri(int p1) { + return GL11.glGetTexParameteri(GL11.GL_TEXTURE_2D, p1); + } + public static final float _wglGetTexParameterf(int p1) { + return GL11.glGetTexParameterf(GL11.GL_TEXTURE_2D, p1); + } + public static final int _wglGetAttribLocation(ProgramGL p1, String p2) { + return GL20.glGetAttribLocation(p1.obj, p2); + } + + public static final EaglerImage loadPNG(byte[] data) { + try { + BufferedImage img = ImageIO.read(new EaglerInputStream(data)); + int[] pxls = img.getRGB(0, 0, img.getWidth(), img.getHeight(), null, 0, img.getWidth()); + return new EaglerImage(pxls, img.getWidth(), img.getHeight(), true); + } catch (IOException e) { + System.err.println("Could not load PNG file:"); + e.printStackTrace(); + return null; + } + } + + public static final boolean isVideoSupported() { + return false; + } + public static final void loadVideo(String src, boolean autoplay) { + throw new UnsupportedOperationException("Video is not supported in LWJGL runtime"); + } + public static final void loadVideo(String src, boolean autoplay, String setJavascriptPointer) { + throw new UnsupportedOperationException("Video is not supported in LWJGL runtime"); + } + public static final void loadVideo(String src, boolean autoplay, String setJavascriptPointer, String javascriptOnloadFunction) { + throw new UnsupportedOperationException("Video is not supported in LWJGL runtime"); + } + public static final void bufferVideo(String src, int ttl) { + throw new UnsupportedOperationException("Video is not supported in LWJGL runtime"); + } + public static final void unloadVideo() { + throw new UnsupportedOperationException("Video is not supported in LWJGL runtime"); + } + public static final boolean isVideoLoaded() { + throw new UnsupportedOperationException("Video is not supported in LWJGL runtime"); + } + public static final boolean isVideoPaused() { + throw new UnsupportedOperationException("Video is not supported in LWJGL runtime"); + } + public static final void setVideoPaused(boolean pause) { + throw new UnsupportedOperationException("Video is not supported in LWJGL runtime"); + } + public static final void setVideoLoop(boolean pause) { + throw new UnsupportedOperationException("Video is not supported in LWJGL runtime"); + } + public static final void setVideoVolume(float x, float y, float z, float v) { + throw new UnsupportedOperationException("Video is not supported in LWJGL runtime"); + } + public static final void updateVideoTexture() { + throw new UnsupportedOperationException("Video is not supported in LWJGL runtime"); + } + public static final void bindVideoTexture() { + throw new UnsupportedOperationException("Video is not supported in LWJGL runtime"); + } + public static final int getVideoWidth() { + throw new UnsupportedOperationException("Video is not supported in LWJGL runtime"); + } + public static final int getVideoHeight() { + throw new UnsupportedOperationException("Video is not supported in LWJGL runtime"); + } + public static final float getVideoCurrentTime() { + throw new UnsupportedOperationException("Video is not supported in LWJGL runtime"); + } + public static final void setVideoCurrentTime(float seconds) { + throw new UnsupportedOperationException("Video is not supported in LWJGL runtime"); + } + public static final float getVideoDuration() { + throw new UnsupportedOperationException("Video is not supported in LWJGL runtime"); + } + public static final void setVideoFrameRate(float seconds) { + throw new UnsupportedOperationException("Video is not supported in LWJGL runtime"); + } + + public static final int VIDEO_ERR_NONE = -1; + public static final int VIDEO_ERR_ABORTED = 1; + public static final int VIDEO_ERR_NETWORK = 2; + public static final int VIDEO_ERR_DECODE = 3; + public static final int VIDEO_ERR_SRC_NOT_SUPPORTED = 4; + + public static final int getVideoError() { + throw new UnsupportedOperationException("Video is not supported in LWJGL runtime"); + } + + public static final boolean isImageSupported() { + return false; + } + public static final void loadImage(String src) { + throw new UnsupportedOperationException("Image is not supported in LWJGL runtime"); + } + public static final void loadImage(String src, String setJavascriptPointer) { + throw new UnsupportedOperationException("Image is not supported in LWJGL runtime"); + } + public static final void loadImage(String src, String setJavascriptPointer, String javascriptOnloadFunction) { + throw new UnsupportedOperationException("Image is not supported in LWJGL runtime"); + } + public static final void bufferImage(String src, int ttl) { + throw new UnsupportedOperationException("Image is not supported in LWJGL runtime"); + } + public static final void unloadImage() { + throw new UnsupportedOperationException("Image is not supported in LWJGL runtime"); + } + public static final boolean isImageLoaded() { + throw new UnsupportedOperationException("Image is not supported in LWJGL runtime"); + } + public static final void updateImageTexture() { + throw new UnsupportedOperationException("Image is not supported in LWJGL runtime"); + } + public static final void bindImageTexture() { + throw new UnsupportedOperationException("Image is not supported in LWJGL runtime"); + } + public static final int getImageWidth() { + throw new UnsupportedOperationException("Image is not supported in LWJGL runtime"); + } + public static final int getImageHeight() { + throw new UnsupportedOperationException("Image is not supported in LWJGL runtime"); + } + public static final void setImageFrameRate(float seconds) { + throw new UnsupportedOperationException("Image is not supported in LWJGL runtime"); + } + + // ======================================================================================= + // ======================================================================================= + // ======================================================================================= + // ======================================================================================= + // ======================================================================================= + + private static Canvas daCanvas = null; + private static Frame eagler = null; + private static SoundSystem ss = null; + public static final void initializeContext() { + daCanvas = new Canvas(); + eagler = new Frame(); + eagler.setTitle("eaglercraft desktop runtime"); + eagler.setBackground(Color.BLACK); + JPanel var16 = new JPanel(); + eagler.setLayout(new BorderLayout()); + var16.setPreferredSize(new Dimension(854, 480)); + eagler.add(var16, "Center"); + eagler.pack(); + eagler.setLocationRelativeTo((Component) null); + eagler.setVisible(true); + eagler.addWindowListener(new GameWindowListener()); + eagler.removeAll(); + eagler.setLayout(new BorderLayout()); + eagler.add(daCanvas, "Center"); + eagler.validate(); + eagler.setVisible(true); + + try { + ContextAttribs contextAtrributes = new ContextAttribs(3, 2).withForwardCompatible(true).withProfileCore(true).withDebug(true); + Display.setParent(daCanvas); + Display.create((new PixelFormat()).withDepthBits(24), contextAtrributes); + } catch (LWJGLException var5) { + var5.printStackTrace(); + + try { + Thread.sleep(1000L); + } catch (InterruptedException var4) { + ; + } + + try { + Display.create(); + } catch (LWJGLException e) { + e.printStackTrace(); + } + } + + //if(!_wisWebGL()) { + // GL30.glBindVertexArray(GL30.glGenVertexArrays()); + //} + + EarlyLoadScreen.paintScreen(); + + try { + Mouse.create(); + Keyboard.create(); + } catch (LWJGLException var5) { + var5.printStackTrace(); + } + + if(useEPKTest) { + try { + InputStream stream = new FileInputStream(new File("out.epk")); + byte[] targetArray = new byte[stream.available()]; + stream.read(targetArray); + stream.close(); + AssetRepository.install(targetArray); + } catch(IOException e) { + e.printStackTrace(); + } + } + + Display.setTitle("eaglercraft desktop runtime"); + System.out.println("LWJGL Version: " + Sys.getVersion()); + + _wGL_ANY_SAMPLES_PASSED = ARBOcclusionQuery2.GL_ANY_SAMPLES_PASSED; + _wGL_TEXTURE_MAX_ANISOTROPY = EXTTextureFilterAnisotropic.GL_TEXTURE_MAX_ANISOTROPY_EXT; + + GL11.glEnable(ARBDebugOutput.GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); + ARBDebugOutput.glDebugMessageCallbackARB(new ARBDebugOutputCallback(new ARBDebugOutputCallback.Handler() { + + @Override + public void handleMessage(int arg0, int arg1, int arg2, int arg3, String arg4) { + if(arg3 == ARBDebugOutput.GL_DEBUG_SEVERITY_MEDIUM_ARB || arg3 == ARBDebugOutput.GL_DEBUG_SEVERITY_HIGH_ARB) { + StringBuilder b = new StringBuilder(); + b.append("[KHR DEBUG #"); b.append(arg2); b.append("] "); + switch(arg0) { + case ARBDebugOutput.GL_DEBUG_SOURCE_API_ARB: b.append("[API - "); break; + case ARBDebugOutput.GL_DEBUG_SOURCE_APPLICATION_ARB: b.append("[APPLICATION - "); break; + default: + case ARBDebugOutput.GL_DEBUG_SOURCE_OTHER_ARB: b.append("[OTHER - "); break; + case ARBDebugOutput.GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: b.append("[SHADER COMPILER - "); break; + case ARBDebugOutput.GL_DEBUG_SOURCE_THIRD_PARTY_ARB: b.append("[THIRD PARTY - "); break; + } + switch(arg1) { + case ARBDebugOutput.GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: b.append("DEPRECATED BEHAVIOR] "); break; + case ARBDebugOutput.GL_DEBUG_TYPE_ERROR_ARB: b.append("ERROR] "); break; + default: + case ARBDebugOutput.GL_DEBUG_TYPE_OTHER_ARB: b.append("OTHER] "); break; + case ARBDebugOutput.GL_DEBUG_TYPE_PERFORMANCE_ARB: b.append("PERFORMANCE] "); break; + case ARBDebugOutput.GL_DEBUG_TYPE_PORTABILITY_ARB: b.append("PORTABILITY] "); break; + case ARBDebugOutput.GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: b.append("UNDEFINED BEHAVIOR] "); break; + } + switch(arg3) { + default: + case ARBDebugOutput.GL_DEBUG_SEVERITY_LOW_ARB: b.append("[LOW Severity] "); break; + case ARBDebugOutput.GL_DEBUG_SEVERITY_MEDIUM_ARB: b.append("[MEDIUM Severity] "); break; + case ARBDebugOutput.GL_DEBUG_SEVERITY_HIGH_ARB: b.append("[SEVERE] "); break; + } + b.append(arg4); + System.err.println(b.toString()); + if(arg3 == ARBDebugOutput.GL_DEBUG_SEVERITY_HIGH_ARB) { + throw new RuntimeException("GL_DEBUG_SEVERITY_HIGH_ARB was thrown"); + } + } + } + + })); + + try { + SoundSystemConfig.addLibrary(LibraryLWJGLOpenAL.class); + SoundSystemConfig.setCodec("mp3", CodecJLayerMP3.class); + ss = new SoundSystem(); + }catch(Throwable t) { + t.printStackTrace(); + } + } + public static final void destroyContext() { + Display.destroy(); + Keyboard.destroy(); + Mouse.destroy(); + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + eagler.dispose(); + } + }); + if(ss != null) { + ss.cleanup(); + } + AL.destroy(); + } + public static final boolean isWindows() { + return System.getProperty("os.name").toLowerCase().contains("windows"); + } + public static final boolean mouseNext() { + return Mouse.next(); + } + public static final int mouseGetEventButton() { + return Mouse.getEventButton(); + } + public static final boolean mouseGetEventButtonState() { + return Mouse.getEventButtonState(); + } + public static final boolean mouseIsButtonDown(int p1) { + return Mouse.isButtonDown(p1); + } + public static final int mouseGetEventDWheel() { + return Mouse.getDWheel(); + } + public static final void mouseSetCursorPosition(int x, int y) { + Mouse.setCursorPosition(x, y); + } + public static final void mouseSetGrabbed(boolean grabbed) { + Mouse.setGrabbed(grabbed); + } + public static final boolean isPointerLocked() { + return Mouse.isGrabbed(); + } + public static final int mouseGetDX() { + return Mouse.getDX(); + } + public static final int mouseGetDY() { + return Mouse.getDY(); + } + public static final int mouseGetX() { + return Mouse.getX(); + } + public static final int mouseGetY() { + return Mouse.getY(); + } + public static final int mouseGetEventX() { + return Mouse.getEventX(); + } + public static final int mouseGetEventY() { + return Mouse.getEventY(); + } + public static final boolean keysNext() { + return Keyboard.next(); + } + public static final int getEventKey() { + return Keyboard.getEventKey(); + } + public static final char getEventChar() { + return Keyboard.getEventCharacter(); + } + public static final boolean getEventKeyState() { + return Keyboard.getEventKeyState(); + } + public static final boolean isKeyDown(int p1) { + return Keyboard.isKeyDown(p1); + } + public static final String getKeyName(int p1) { + return Keyboard.getKeyName(p1); + } + public static final void setFullscreen(boolean p1) { + try { + Display.setFullscreen(p1); + } catch (LWJGLException e) { + e.printStackTrace(); + } + } + public static final boolean shouldShutdown() { + return Display.isCloseRequested(); + } + public static final void updateDisplay(int fpsLimit, boolean vsync) { + if(vsync) { + Display.setVSyncEnabled(true); + Display.update(); + }else { + Display.setVSyncEnabled(false); + Display.sync(fpsLimit); + Display.update(); + } + } + public static final void enableRepeatEvents(boolean b) { + Keyboard.enableRepeatEvents(b); + } + public static final boolean isFocused() { + return Display.isActive(); + } + public static final int getScreenWidth() { + return Display.getDisplayMode().getWidth(); + } + public static final int getScreenHeight() { + return Display.getDisplayMode().getHeight(); + } + public static final int getCanvasWidth() { + return daCanvas.getWidth(); + } + public static final int getCanvasHeight() { + return daCanvas.getHeight(); + } + public static final float getContentScaling() { + return 1.0f; + } + public static final void setDisplaySize(int x, int y) { + try { + Display.setDisplayMode(new DisplayMode(x, y)); + } catch (LWJGLException e) { + e.printStackTrace(); + } + } + + private static final Set rateLimitedAddresses = new HashSet<>(); + private static final Set blockedAddresses = new HashSet<>(); + + private static WebSocketClient clientSocket = null; + private static final Object socketSync = new Object(); + + private static LinkedList readPackets = new LinkedList<>(); + + private static class EaglerSocketClient extends WebSocketClient { + + private Exception currentException = null; + private boolean wasAbleToConnect = false; + private String serverUriString; + private boolean socketIsAlive = false; + + public EaglerSocketClient(URI serverUri, String str) throws IOException, InterruptedException { + super(serverUri); + this.setTcpNoDelay(true); + this.setConnectionLostTimeout(5); + System.out.println("[ws] connecting to "+serverUri.toString()); + rateLimitStatus = null; + if(!this.connectBlocking(5, TimeUnit.SECONDS)) { + synchronized(socketSync) { + if(rateLimitStatus == null) { + if(blockedAddresses.contains(str)) { + rateLimitStatus = RateLimit.BLOCKED; + }else if(rateLimitedAddresses.contains(str)) { + rateLimitStatus = RateLimit.FAILED_POSSIBLY_LOCKED; + }else { + rateLimitStatus = RateLimit.FAILED; + } + } + } + throw new IOException("could not connect socket", currentException); + } + serverUriString = str; + } + + @Override + public void onClose(int arg0, String arg1, boolean arg2) { + synchronized(socketSync) { + readPackets.clear(); + System.out.println("[ws] disconnecting - " + currentException); + currentException = null; + if(!wasAbleToConnect && rateLimitStatus == null) { + if(blockedAddresses.contains(serverUriString)) { + rateLimitStatus = RateLimit.LOCKED; + }else if(rateLimitedAddresses.contains(serverUriString)) { + rateLimitStatus = RateLimit.FAILED_POSSIBLY_LOCKED; + }else { + rateLimitStatus = RateLimit.FAILED; + } + }else if(!socketIsAlive && (blockedAddresses.contains(serverUriString) || rateLimitedAddresses.contains(serverUriString))) { + rateLimitStatus = RateLimit.LOCKED; + } + } + } + + @Override + public void onError(Exception arg0) { + currentException = arg0; + } + + @Override + public void onMessage(String arg0) { + wasAbleToConnect = true; + synchronized(socketSync) { + if(arg0.equalsIgnoreCase("BLOCKED")) { + rateLimitedAddresses.add(serverUriString); + if(rateLimitStatus == null) { + rateLimitStatus = RateLimit.BLOCKED; + } + }else if(arg0.equalsIgnoreCase("LOCKED")) { + blockedAddresses.add(serverUriString); + rateLimitedAddresses.add(serverUriString); + if(rateLimitStatus == null) { + rateLimitStatus = RateLimit.NOW_LOCKED; + } + } + } + this.close(); + currentException = null; + } + + @Override + public void onMessage(ByteBuffer arg0) { + wasAbleToConnect = true; + synchronized(socketSync) { + readPackets.add(arg0.array()); + } + currentException = null; + } + + @Override + public void onOpen(ServerHandshake arg0) { + System.out.println("[ws] connected."); + } + + } + + public static final boolean startConnection(String uri) { + if(clientSocket != null) { + clientSocket.close(); + } + rateLimitStatus = null; + try { + clientSocket = new EaglerSocketClient(new URI(uri), uri); + return true; + }catch(InterruptedException e) { + clientSocket = null; + } catch (URISyntaxException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return false; + } + public static final void endConnection() { + synchronized(socketSync) { + if(clientSocket.isOpen()) { + clientSocket.close(); + } + clientSocket = null; + readPackets.clear(); + } + } + public static final boolean connectionOpen() { + return clientSocket != null && clientSocket.isOpen(); + } + public static final void writePacket(byte[] packet) { + if(clientSocket != null && clientSocket.isOpen()) { + clientSocket.send(ByteBuffer.wrap(packet)); + } + } + public static final byte[] readPacket() { + synchronized(socketSync) { + if(!readPackets.isEmpty()) { + return readPackets.remove(0); + } + } + return null; + } + private static RateLimit rateLimitStatus = null; + public static enum RateLimit { + NONE, FAILED, BLOCKED, FAILED_POSSIBLY_LOCKED, LOCKED, NOW_LOCKED; + } + public static final RateLimit getRateLimitStatus() { + RateLimit l = rateLimitStatus; + rateLimitStatus = null; + return l; + } + public static final void logRateLimit(String addr, RateLimit l) { + synchronized(socketSync) { + if(l == RateLimit.LOCKED) { + blockedAddresses.add(addr); + }else { + rateLimitedAddresses.add(addr); + } + } + } + public static final RateLimit checkRateLimitHistory(String addr) { + synchronized(socketSync) { + if(blockedAddresses.contains(addr)) { + return RateLimit.LOCKED; + }else if(rateLimitedAddresses.contains(addr)) { + return RateLimit.BLOCKED; + }else { + return RateLimit.NONE; + } + } + } + public static final byte[] loadLocalStorage(String key) { + try { + File f = new File("_eagstorage."+key+".dat"); + byte[] b = new byte[(int)f.length()]; + FileInputStream s = new FileInputStream(f); + s.read(b); + s.close(); + return b; + } catch (IOException e) { + return null; + } + } + public static final void saveLocalStorage(String key, byte[] data) { + try { + FileOutputStream f = new FileOutputStream(new File("_eagstorage."+key+".dat")); + f.write(data); + f.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + public static final void openLink(String url) { + try { + Class var3 = Class.forName("java.awt.Desktop"); + Object var4 = var3.getMethod("getDesktop", new Class[0]).invoke((Object) null, new Object[0]); + var3.getMethod("browse", new Class[] { URI.class }).invoke(var4, new Object[] { new URI(url) }); + } catch (Throwable var5) { + var5.printStackTrace(); + } + } + private static volatile boolean fileChooserOpen = false; + private static volatile byte[] fileChooserFile = null; + private static volatile String fileChooserName = null; + public static final void openFileChooser(final String ext, final String mime) { + EventQueue.invokeLater(new Runnable() { + + @Override + public void run() { + if(!fileChooserOpen) { + fileChooserOpen = true; + try { + JFileChooser yee = new JFileChooser(new File(System.getProperty("user.home"))); + yee.setDialogTitle("select a file"); + yee.setFileSelectionMode(JFileChooser.FILES_ONLY); + yee.setMultiSelectionEnabled(false); + + String[] exts = ext.split(",."); + yee.setFileFilter(new FileFilter() { + + @Override + public String getDescription() { + return String.join("/", exts)+" files"; + } + + @Override + public boolean accept(File f) { + if (f.isDirectory()) return true; + for (String e : exts) { + if (f.getName().endsWith("."+e)) return true; + } + return false; + } + }); + if(yee.showOpenDialog(eagler) == JFileChooser.APPROVE_OPTION) { + File f = yee.getSelectedFile(); + fileChooserName = f.getName(); + try { + byte[] b = new byte[(int)f.length()]; + FileInputStream s = new FileInputStream(f); + s.read(b); + s.close(); + fileChooserFile = b; + } catch (IOException e) { + fileChooserFile = new byte[0]; + } + }else { + fileChooserFile = new byte[0]; + } + }catch(Throwable t) { + fileChooserFile = new byte[0]; + } + fileChooserOpen = false; + } + } + + }); + } + public static final boolean getFileChooserResultAvailable() { + return fileChooserFile != null; + } + public static final byte[] getFileChooserResult() { + byte[] b = fileChooserFile; + fileChooserFile = null; + return b; + } + public static final String getFileChooserResultName() { + String s = fileChooserName; + fileChooserName = null; + return s; + } + public static final void clearFileChooserResult() { + fileChooserName = null; + fileChooserFile = null; + } + public static final void setListenerPos(float x, float y, float z, float vx, float vy, float vz, float pitch, float yaw) { + float var2 = MathHelper.cos(-yaw * 0.017453292F); + float var3 = MathHelper.sin(-yaw * 0.017453292F); + float var4 = -MathHelper.cos(pitch * 0.017453292F); + float var5 = MathHelper.sin(pitch * 0.017453292F); + ss.setListenerPosition(x, y, z); + ss.setListenerOrientation(-var3 * var4, -var5, -var2 * var4, 0.0f, 1.0f, 0.0f); + ss.setListenerVelocity(vx, vy, vz); + } + public static final void setPlaybackOffsetDelay(float f) { + // nah + } + public static final void setMasterVolume(float v) { + ss.setMasterVolume(v); + } + public static final void setMusicVolume(float v) { + // used in browser + } + private static int playbackId = 0; + public static final int beginPlayback(String fileName, float x, float y, float z, float volume, float pitch) { + return beginPlayback(fileName, x, y, z, volume, pitch, false); + } + public static final int beginPlayback(String fileName, float x, float y, float z, float volume, float pitch, boolean ayunamiAddedThisBoolean) { + int id = ++playbackId; + URL loc = null; + if((loc = getResourceURL(fileName)) != null) { + String name = "sound_"+id; + float var8 = 16.0F; + if (volume > 1.0F) { + var8 *= volume; + } + ss.newSource(false, name, loc, fileName, false, x, y, z, 2, var8); + ss.setTemporary(name, true); + ss.setPitch(name, pitch); + ss.setVolume(name, volume); + ss.play(name); + }else { + System.err.println("unknown sound event "+fileName); + } + return id; + } + public static final int beginPlaybackStatic(String fileName, float volume, float pitch) { + return beginPlaybackStatic(fileName, volume, pitch, false); + } + public static final int beginPlaybackStatic(String fileName, float volume, float pitch, boolean ayunamiAddedThisBoolean) { + int id = ++playbackId; + URL loc = null; + if((loc = getResourceURL(fileName)) != null) { + String name = "sound_"+id; + ss.newSource(false, name, loc, fileName, false, 0f, 0f, 0f, 0, 0f); + ss.setTemporary(name, true); + ss.setPitch(name, pitch); + ss.setVolume(name, volume); + ss.play(name); + }else { + System.err.println("unknown sound event "+fileName); + } + return id; + } + private static URL getResourceURL(String path) { + try { + File f = new File("resources", path); + if(f.exists()) { + return f.toURI().toURL(); + } + } catch (MalformedURLException e) { + e.printStackTrace(); + } + return null; + } + public static final void setPitch(int id, float pitch) { + String name = "sound_"+id; + if(ss.playing(name)) { + ss.setPitch(name, pitch); + } + } + public static final void setVolume(int id, float volume) { + String name = "sound_"+id; + if(ss.playing(name)) { + ss.setVolume(name, volume); + } + } + public static final void moveSound(int id, float x, float y, float z, float vx, float vy, float vz) { + String name = "sound_"+id; + if(ss.playing(name)) { + ss.setPosition(name, x, y, z); + ss.setVelocity(name, vx, vy, vz); + } + } + public static final void endSound(int id) { + String name = "sound_"+id; + if(ss.playing(name)) { + ss.stop(name); + } + } + public static final boolean isPlaying(int id) { + return ss.playing("sound_"+id); + } + public static final void fireTitleMusicEvent(boolean b, float f) { + // used in browser + } + public static final void openConsole() { + EventQueue.invokeLater(new Runnable() { + + @Override + public void run() { + JOptionPane.showMessageDialog(eagler, "not supported in lwjgl runtime", "eaglercraft", JOptionPane.ERROR_MESSAGE); + } + + }); + } + public static void clearVoiceAvailableStatus() { + + } + public static void setVoiceSignalHandler(Consumer signalHandler) { + + } + public static void handleVoiceSignal(byte[] data) { + + } + public static final boolean voiceAvailable() { + return false; + } + public static final boolean voiceAllowed() { + return false; + } + public static final boolean voiceRelayed() { + return false; + } + public static final void addNearbyPlayer(String username) { + + } + public static final void removeNearbyPlayer(String username) { + + } + public static final void updateVoicePosition(String username, double x, double y, double z) { + + } + public static final void sendInitialVoice() { + + } + public static final void sendVoiceRequestIfNeeded(String str) { + + } + public static final void cleanupNearbyPlayers(Set players) { + + } + private static Voice.VoiceChannel enabledChannel = Voice.VoiceChannel.NONE; + public static final void enableVoice(Voice.VoiceChannel enable) { + enabledChannel = enable; + } + public static final Voice.VoiceChannel getVoiceChannel() { + return enabledChannel; + } + public static final Voice.VoiceStatus getVoiceStatus() { + return enabledChannel == Voice.VoiceChannel.NONE ? Voice.VoiceStatus.DISCONNECTED : Voice.VoiceStatus.CONNECTED; + } + public static final void activateVoice(boolean talk) { + + } + private static int proximity = 16; + public static final void setVoiceProximity(int prox) { + proximity = prox; + } + public static final int getVoiceProximity() { + return proximity; + } + private static float volumeListen = 0.5f; + public static final void setVoiceListenVolume(float f) { + volumeListen = f; + } + public static final float getVoiceListenVolume() { + return volumeListen; + } + private static float volumeSpeak = 0.5f; + public static final void setVoiceSpeakVolume(float f) { + volumeSpeak = f; + } + public static final float getVoiceSpeakVolume() { + return volumeSpeak; + } + private static final Set emptySet = new HashSet<>(); + public static final Set getVoiceListening() { + return emptySet; + } + public static final Set getVoiceSpeaking() { + return emptySet; + } + public static final void setVoiceMuted(String username, boolean mute) { + + } + public static final Set getVoiceMuted() { + return emptySet; + } + private static final List emptyList = new ArrayList<>(); + public static final List getVoiceRecent() { + return emptyList; + } + public static final void tickVoice() { + + } + public static final void doJavascriptCoroutines() { + + } + public static final long maxMemory() { + return Runtime.getRuntime().maxMemory(); + } + public static final long totalMemory() { + return Runtime.getRuntime().totalMemory(); + } + public static final long freeMemory() { + return Runtime.getRuntime().freeMemory(); + } + public static final void exit() { + Runtime.getRuntime().halt(0); + } + public static final int _wArrayByteLength(Object obj) { + return ((IntBuffer)obj).remaining() * 4; + } + public static final Object _wCreateLowLevelIntBuffer(int len) { + return ByteBuffer.allocateDirect(len*4).order(ByteOrder.nativeOrder()).asIntBuffer(); + } + + private static final IntBuffer appendbuffer = (IntBuffer) _wCreateLowLevelIntBuffer(525000); + + public static final void _wAppendLowLevelBuffer(Object arr) { + if(appendbuffer.limit() != appendbuffer.capacity()) appendbuffer.clear(); + IntBuffer a = (IntBuffer)arr; + if(appendbuffer.remaining() >= a.remaining()) { + appendbuffer.put(a); + } + } + + public static final Object _wGetLowLevelBuffersAppended() { + appendbuffer.flip(); + return appendbuffer; + } + + public static final String getUserAgent() { + return "Desktop/" + System.getProperty("os.name"); + } + + public static final String getClipboard() { + try { + return (String)Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.stringFlavor); + } catch (HeadlessException | UnsupportedFlavorException | IOException e) { + return null; + } + } + + public static final void setClipboard(String str) { + StringSelection selection = new StringSelection(str); + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + clipboard.setContents(selection, selection); + } + + public static final void saveScreenshot() { + + } + + private static class ServerQueryImpl extends WebSocketClient implements ServerQuery { + + private final LinkedList queryResponses = new LinkedList<>(); + private final LinkedList queryResponsesBytes = new LinkedList<>(); + private final String type; + private boolean open; + private boolean alive; + private String serverUri; + private long pingStart; + private long pingTimer; + + private ServerQueryImpl(String type, URI serverUri, String serverUriString) throws IOException { + super(serverUri); + this.serverUri = serverUriString; + this.type = type; + this.open = true; + this.alive = false; + this.pingStart = -1l; + this.pingTimer = -1l; + this.setConnectionLostTimeout(5); + this.setTcpNoDelay(true); + this.connect(); + } + + @Override + public int responseAvailable() { + synchronized(queryResponses) { + return queryResponses.size(); + } + } + + @Override + public int responseBinaryAvailable() { + synchronized(queryResponsesBytes) { + return queryResponsesBytes.size(); + } + } + + @Override + public QueryResponse getResponse() { + synchronized(queryResponses) { + return queryResponses.size() > 0 ? queryResponses.remove(0) : null; + } + } + + @Override + public byte[] getBinaryResponse() { + synchronized(queryResponsesBytes) { + return queryResponsesBytes.size() > 0 ? queryResponsesBytes.remove(0) : null; + } + } + + @Override + public void onClose(int arg0, String arg1, boolean arg2) { + open = false; + if(!alive) { + synchronized(socketSync) { + if(EaglerAdapterImpl2.blockedAddresses.contains(serverUri)) { + queryResponses.add(new QueryResponse(true, pingTimer)); + }else if(EaglerAdapterImpl2.rateLimitedAddresses.contains(serverUri)) { + queryResponses.add(new QueryResponse(false, pingTimer)); + } + } + } + } + + @Override + public void onError(Exception arg0) { + System.err.println("WebSocket query error: " + arg0.toString()); + open = false; + this.close(); + } + + @Override + public void onMessage(String arg0) { + this.alive = true; + synchronized(queryResponses) { + if(pingTimer == -1) { + pingTimer = steadyTimeMillis() - pingStart; + } + if(arg0.equalsIgnoreCase("BLOCKED")) { + synchronized(socketSync) { + EaglerAdapterImpl2.rateLimitedAddresses.add(serverUri); + queryResponses.add(new QueryResponse(false, pingTimer)); + } + this.close(); + return; + }else if(arg0.equalsIgnoreCase("LOCKED")) { + synchronized(socketSync) { + EaglerAdapterImpl2.blockedAddresses.add(serverUri); + queryResponses.add(new QueryResponse(true, pingTimer)); + } + this.close(); + return; + }else { + try { + QueryResponse q = new QueryResponse(new JSONObject(arg0), pingTimer); + if(q.rateLimitStatus != null) { + synchronized(socketSync) { + if(q.rateLimitStatus == RateLimit.BLOCKED) { + EaglerAdapterImpl2.rateLimitedAddresses.add(serverUri); + }else if(q.rateLimitStatus == RateLimit.LOCKED) { + EaglerAdapterImpl2.blockedAddresses.add(serverUri); + } + } + this.close(); + } + queryResponses.add(q); + }catch(Throwable t) { + System.err.println("Query response parse error: " + t.toString()); + } + } + } + } + + @Override + public void onMessage(ByteBuffer arg0) { + this.alive = true; + synchronized(queryResponsesBytes) { + byte[] pkt = new byte[arg0.limit()]; + arg0.get(pkt); + queryResponsesBytes.add(pkt); + } + } + + @Override + public void onOpen(ServerHandshake arg0) { + send("Accept: " + type); + pingStart = steadyTimeMillis(); + } + + @Override + public boolean isQueryOpen() { + return open; + } + + } + + public static final ServerQuery openQuery(String type, String uri) { + try { + return new ServerQueryImpl(type, new URI(uri), uri); + }catch(Throwable t) { + System.err.println("WebSocket query error: " + t.toString()); + return null; + } + } + + private static String serverToJoinOnLaunch = null; + + public static final void setServerToJoinOnLaunch(String s) { + serverToJoinOnLaunch = s; + } + + public static final String getServerToJoinOnLaunch() { + return serverToJoinOnLaunch; + } + + public static final boolean isIntegratedServerAvailable() { + return false; //TODO: change to false + } + + public static final void beginLoadingIntegratedServer() { + throw new UnsupportedOperationException("Integrated server is not available in LWJGL eagleradapter"); + } + + public static final boolean isIntegratedServerAlive() { + return false; + } + + public static final void terminateIntegratedServer() { + throw new UnsupportedOperationException("Integrated server is not available in LWJGL eagleradapter"); + } + + public static final void enableChannel(String channel) { + throw new UnsupportedOperationException("Integrated server is not available in LWJGL eagleradapter"); + } + + public static final void disableChannel(String channel) { + throw new UnsupportedOperationException("Integrated server is not available in LWJGL eagleradapter"); + } + + public static final void sendToIntegratedServer(String channel, byte[] pkt) { + throw new UnsupportedOperationException("Integrated server is not available in LWJGL eagleradapter"); + } + + public static final PKT recieveFromIntegratedServer(String channel) { + throw new UnsupportedOperationException("Integrated server is not available in LWJGL eagleradapter"); + } + + public static final void downloadBytes(String str, byte[] dat) { + JOptionPane.showMessageDialog(null, "downloadBytes was called for file '" + str + "' with " + dat.length + " bytes"); + } + + /** + * I'm pretty sure my IntBuffers address this problem but if byte order glitches (such as corrupted textures) appear then change to true + */ + public static final boolean isBigEndian() { + return false; + } + + private static final RelayQuery dummyRelayQuery = new RelayQuery() { + + @Override + public boolean isQueryOpen() { + return false; + } + + @Override + public boolean isQueryFailed() { + return false; + } + + @Override + public void close() { + } + + @Override + public int getVersion() { + return 1; + } + + @Override + public String getComment() { + return "this is a dummy"; + } + + @Override + public String getBrand() { + return "lax1dude"; + } + + @Override + public long getPing() { + return 10l; + } + + @Override + public VersionMismatch getCompatible() { + return VersionMismatch.COMPATIBLE; + } + + @Override + public RateLimit isQueryRateLimit() { + return RateLimit.NONE; + } + + }; + + public static final RelayQuery openRelayQuery(String addr) { + return dummyRelayQuery; + } + + private static final RelayWorldsQuery dummyRelayWorldsQuery = new RelayWorldsQuery() { + + @Override + public boolean isQueryOpen() { + return false; + } + + @Override + public boolean isQueryFailed() { + return false; + } + + @Override + public RateLimit isQueryRateLimit() { + return RateLimit.NONE; + } + + @Override + public void close() { + + } + + @Override + public List getWorlds() { + return (List)((List)emptyList); + } + + @Override + public VersionMismatch getCompatible() { + return VersionMismatch.COMPATIBLE; + } + + }; + + public static final RelayWorldsQuery openRelayWorldsQuery(String addr) { + return dummyRelayWorldsQuery; + } + + private static final RelayServerSocket relaySocketDummy = new RelayServerSocket() { + + @Override + public boolean isOpen() { + return false; + } + + @Override + public boolean isClosed() { + return true; + } + + @Override + public void close() { + + } + + @Override + public boolean isFailed() { + return false; + } + + @Override + public Throwable getException() { + return null; + } + + @Override + public void writePacket(IPacket pkt) { + + } + + @Override + public IPacket readPacket() { + return null; + } + + @Override + public IPacket nextPacket() { + return null; + } + + @Override + public RateLimit getRatelimitHistory() { + return RateLimit.NONE; + } + + @Override + public String getURI() { + return "undefined"; + } + + }; + + public static final RelayServerSocket openRelayConnection(String addr, int timeout) { + return relaySocketDummy; + } + + public static final boolean glNeedsAnisotropicFix() { + return false; + } + + public static final boolean clientLANSupported() { + return false; + } + + public static final int clientLANReadyState() { + return 0; + } + + public static final void clientLANCloseConnection() { + throw new UnsupportedOperationException("LAN worlds are not available in LWJGL eagleradapter"); + } + + public static final void clientLANSendPacket(byte[] pkt) { + throw new UnsupportedOperationException("LAN worlds are not available in LWJGL eagleradapter"); + } + + public static final byte[] clientLANReadPacket() { + throw new UnsupportedOperationException("LAN worlds are not available in LWJGL eagleradapter"); + } + + public static final void clientLANSetICEServersAndConnect(String[] servers) { + throw new UnsupportedOperationException("LAN worlds are not available in LWJGL eagleradapter"); + } + + public static final void clearLANClientState() { + // no throw, just to be safe + } + + public static final String clientLANAwaitICECandidate() { + throw new UnsupportedOperationException("LAN worlds are not available in LWJGL eagleradapter"); + } + + public static final String clientLANAwaitDescription() { + throw new UnsupportedOperationException("LAN worlds are not available in LWJGL eagleradapter"); + } + + public static final boolean clientLANAwaitChannel() { + throw new UnsupportedOperationException("LAN worlds are not available in LWJGL eagleradapter"); + } + + public static final boolean clientLANClosed() { + throw new UnsupportedOperationException("LAN worlds are not available in LWJGL eagleradapter"); + } + + public static final void clientLANSetICECandidate(String candidate) { + throw new UnsupportedOperationException("LAN worlds are not available in LWJGL eagleradapter"); + } + + public static final void clientLANSetDescription(String description) { + throw new UnsupportedOperationException("LAN worlds are not available in LWJGL eagleradapter"); + } + + public static final boolean serverLANSupported() { + return false; + } + + public static final void serverLANInitializeServer(String[] servers) { + throw new UnsupportedOperationException("LAN worlds are not available in LWJGL eagleradapter"); + } + + public static final void serverLANCloseServer() { + + } + + public static final LANPeerEvent serverLANGetEvent(String clientId) { + throw new UnsupportedOperationException("LAN worlds are not available in LWJGL eagleradapter"); + } + + public static final void serverLANWritePacket(String peer, byte[] data) { + throw new UnsupportedOperationException("LAN worlds are not available in LWJGL eagleradapter"); + } + + public static final void serverLANCreatePeer(String peer) { + throw new UnsupportedOperationException("LAN worlds are not available in LWJGL eagleradapter"); + } + + public static final void serverLANPeerICECandidates(String peer, String iceCandidates) { + throw new UnsupportedOperationException("LAN worlds are not available in LWJGL eagleradapter"); + } + + public static final void serverLANPeerDescription(String peer, String description) { + throw new UnsupportedOperationException("LAN worlds are not available in LWJGL eagleradapter"); + } + + public static final void serverLANDisconnectPeer(String peer) { + throw new UnsupportedOperationException("LAN worlds are not available in LWJGL eagleradapter"); + } + + public static final int countPeers() { + return 0; + } + + public static final boolean anisotropicFilteringSupported() { + return true; + } + + public static final byte[] downloadURL(String url) { + return null; + } + + public static final long steadyTimeMillis() { + return System.nanoTime() / 1000000l; + } + + public static final long nanoTime() { + return System.nanoTime(); + } + + public static final void sleep(int millis) { + try { + Thread.sleep(millis); + }catch(InterruptedException ex) { + } + } + + public static final boolean immediateContinueSupported() { + return false; + } + + public static final void immediateContinue() { + // + } + + public static final List serverLANGetAllEvent(String clientId) { + return null; + } + +} diff --git a/src/lwjgl/java/net/lax1dude/eaglercraft/adapter/SimpleStorage.java b/src/lwjgl/java/net/lax1dude/eaglercraft/adapter/SimpleStorage.java new file mode 100644 index 0000000..cd0208b --- /dev/null +++ b/src/lwjgl/java/net/lax1dude/eaglercraft/adapter/SimpleStorage.java @@ -0,0 +1,50 @@ +package net.lax1dude.eaglercraft.adapter; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class SimpleStorage { + private static final Path directory; + private static final boolean available = true; + + public static boolean isAvailable() { + return available; + } + + static { + File file = new File("eagstorage"); + file.mkdirs(); + directory = file.toPath().toAbsolutePath(); + } + + public static byte[] get(String key) { + try { + return Files.readAllBytes(directory.resolve(key)); + } catch (IOException e) { + return null; + } + } + + public static Boolean set(String key, byte[] value) { + try { + if (value == null) { + Files.deleteIfExists(directory.resolve(key)); + } else { + Files.write(directory.resolve(key), value); + } + return Boolean.TRUE; + } catch (IOException e) { + return Boolean.FALSE; + } + } + + public static String[] list() { + try { + return Files.list(directory).map(Path::getFileName).toArray(String[]::new); + } catch (IOException e) { + return new String[0]; + } + } +} \ No newline at end of file diff --git a/src/lwjgl/java/net/lax1dude/eaglercraft/adapter/Tessellator.java b/src/lwjgl/java/net/lax1dude/eaglercraft/adapter/Tessellator.java new file mode 100644 index 0000000..63a5b45 --- /dev/null +++ b/src/lwjgl/java/net/lax1dude/eaglercraft/adapter/Tessellator.java @@ -0,0 +1,384 @@ +package net.lax1dude.eaglercraft.adapter; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.IntBuffer; + +import net.lax1dude.eaglercraft.EaglerAdapter; +import net.minecraft.src.MathHelper; + +public class Tessellator { + + /** The byte buffer used for GL allocation. */ + private ByteBuffer byteBuffer; + private IntBuffer intBuffer; + + /** Raw integer array. */ + private int[] rawBuffer; + + /** + * The number of vertices to be drawn in the next draw call. Reset to 0 between + * draw calls. + */ + private int vertexCount = 0; + + /** The first coordinate to be used for the texture. */ + private double textureU; + + /** The second coordinate to be used for the texture. */ + private double textureV; + private int brightness; + + /** The color (RGBA) value to be used for the following draw call. */ + private int color; + + /** + * Whether the current draw object for this tessellator has color values. + */ + private boolean hasColor = false; + + /** + * Whether the current draw object for this tessellator has texture coordinates. + */ + private boolean hasTexture = false; + private boolean hasBrightness = false; + + /** + * Whether the current draw object for this tessellator has normal values. + */ + private boolean hasNormals = false; + + /** The index into the raw buffer to be used for the next data. */ + private int rawBufferIndex = 0; + + /** + * The number of vertices manually added to the given draw call. This differs + * from vertexCount because it adds extra vertices when converting quads to + * triangles. + */ + private int addedVertices = 0; + + /** Disables all color information for the following draw call. */ + private boolean isColorDisabled = false; + + /** The draw mode currently being used by the tessellator. */ + private int drawMode; + + /** + * An offset to be applied along the x-axis for all vertices in this draw call. + */ + private double xOffset; + + /** + * An offset to be applied along the y-axis for all vertices in this draw call. + */ + private double yOffset; + + /** + * An offset to be applied along the z-axis for all vertices in this draw call. + */ + private double zOffset; + + /** The normal to be applied to the face being drawn. */ + private int normal; + + /** The static instance of the Tessellator. */ + public static final Tessellator instance = new Tessellator(525000); + + /** Whether this tessellator is currently in draw mode. */ + private boolean isDrawing = false; + + /** Whether we are currently using VBO or not. */ + private boolean useVBO = false; + + /** The size of the buffers used (in integers). */ + private int bufferSize; + + private Tessellator(int par1) { + this.bufferSize = par1; + this.byteBuffer = ByteBuffer.allocateDirect(par1 * 4).order(ByteOrder.nativeOrder()); + this.intBuffer = this.byteBuffer.asIntBuffer(); + this.rawBuffer = new int[par1]; + this.useVBO = false;// tryVBO && GLContext.getCapabilities().GL_ARB_vertex_buffer_object; + + //if (this.useVBO) { + //this.vertexBuffers = GLAllocation.createDirectIntBuffer(this.vboCount); + //ARBVertexBufferObject.glGenBuffersARB(this.vertexBuffers); + //} + } + + /** + * Draws the data set up in this tessellator and resets the state to prepare for + * new drawing. + */ + public int draw() { + if (!this.isDrawing) { + return 0; + } else { + this.isDrawing = false; + + if (this.vertexCount > 0) { + IntBuffer up = null; + this.intBuffer.clear(); + this.intBuffer.put(rawBuffer, 0, this.rawBufferIndex); + this.intBuffer.flip(); + up = this.intBuffer; + + if (this.hasTexture) { + EaglerAdapter.glEnableVertexAttrib(EaglerAdapter.GL_TEXTURE_COORD_ARRAY); + } + + if (this.hasColor) { + EaglerAdapter.glEnableVertexAttrib(EaglerAdapter.GL_COLOR_ARRAY); + } + + if (this.hasNormals) { + EaglerAdapter.glEnableVertexAttrib(EaglerAdapter.GL_NORMAL_ARRAY); + } + + if (this.hasBrightness) { + EaglerAdapter.glClientActiveTexture(EaglerAdapter.GL_TEXTURE1); + EaglerAdapter.glEnableVertexAttrib(EaglerAdapter.GL_TEXTURE_COORD_ARRAY); + EaglerAdapter.glClientActiveTexture(EaglerAdapter.GL_TEXTURE0); + } + + EaglerAdapter.glDrawArrays(this.drawMode, 0, this.vertexCount, up); + + if (this.hasTexture) { + EaglerAdapter.glDisableVertexAttrib(EaglerAdapter.GL_TEXTURE_COORD_ARRAY); + } + + if (this.hasColor) { + EaglerAdapter.glDisableVertexAttrib(EaglerAdapter.GL_COLOR_ARRAY); + } + + if (this.hasNormals) { + EaglerAdapter.glDisableVertexAttrib(EaglerAdapter.GL_NORMAL_ARRAY); + } + + if (this.hasBrightness) { + EaglerAdapter.glClientActiveTexture(EaglerAdapter.GL_TEXTURE1); + EaglerAdapter.glDisableVertexAttrib(EaglerAdapter.GL_TEXTURE_COORD_ARRAY); + EaglerAdapter.glClientActiveTexture(EaglerAdapter.GL_TEXTURE0); + } + } + + int var1 = this.rawBufferIndex * 4; + this.reset(); + return var1; + } + } + + /** + * Clears the tessellator state in preparation for new drawing. + */ + private void reset() { + this.vertexCount = 0; + this.rawBufferIndex = 0; + this.addedVertices = 0; + } + + /** + * Sets draw mode in the tessellator to draw quads. + */ + public void startDrawingQuads() { + this.startDrawing(EaglerAdapter.GL_QUADS); + } + + /** + * Resets tessellator state and prepares for drawing (with the specified draw + * mode). + */ + public void startDrawing(int par1) { + if (this.isDrawing) { + this.draw(); + } + this.isDrawing = true; + this.reset(); + this.drawMode = par1; + this.hasNormals = false; + this.hasColor = false; + this.hasTexture = false; + this.hasBrightness = false; + this.isColorDisabled = false; + } + + /** + * Sets the texture coordinates. + */ + public void setTextureUV(double par1, double par3) { + this.hasTexture = true; + this.textureU = par1; + this.textureV = par3; + } + + public void setBrightness(int par1) { + this.hasBrightness = true; + this.brightness = par1; + } + + /** + * Sets the RGB values as specified, converting from floats between 0 and 1 to + * integers from 0-255. + */ + public void setColorOpaque_F(float par1, float par2, float par3) { + this.setColorOpaque((int) (par1 * 255.0F), (int) (par2 * 255.0F), (int) (par3 * 255.0F)); + } + + /** + * Sets the RGBA values for the color, converting from floats between 0 and 1 to + * integers from 0-255. + */ + public void setColorRGBA_F(float par1, float par2, float par3, float par4) { + this.setColorRGBA((int) (par1 * 255.0F), (int) (par2 * 255.0F), (int) (par3 * 255.0F), (int) (par4 * 255.0F)); + } + + /** + * Sets the RGB values as specified, and sets alpha to opaque. + */ + public void setColorOpaque(int par1, int par2, int par3) { + this.setColorRGBA(par1, par2, par3, 255); + } + + /** + * Sets the RGBA values for the color. Also clamps them to 0-255. + */ + public void setColorRGBA(int par1, int par2, int par3, int par4) { + if (!this.isColorDisabled) { + if (par1 > 255) { + par1 = 255; + } + + if (par2 > 255) { + par2 = 255; + } + + if (par3 > 255) { + par3 = 255; + } + + if (par4 > 255) { + par4 = 255; + } + + if (par1 < 0) { + par1 = 0; + } + + if (par2 < 0) { + par2 = 0; + } + + if (par3 < 0) { + par3 = 0; + } + + if (par4 < 0) { + par4 = 0; + } + + this.hasColor = true; + this.color = par4 << 24 | par3 << 16 | par2 << 8 | par1; + } + } + + /** + * Adds a vertex specifying both x,y,z and the texture u,v for it. + */ + public void addVertexWithUV(double par1, double par3, double par5, double par7, double par9) { + this.setTextureUV(par7, par9); + this.addVertex(par1, par3, par5); + } + + /** + * Adds a vertex with the specified x,y,z to the current draw call. It will + * trigger a draw() if the buffer gets full. + */ + public void addVertex(double par1, double par3, double par5) { + if(this.addedVertices > 65534) return; + ++this.addedVertices; + + this.rawBuffer[this.rawBufferIndex + 0] = Float.floatToRawIntBits((float) (par1 + this.xOffset)); + this.rawBuffer[this.rawBufferIndex + 1] = Float.floatToRawIntBits((float) (par3 + this.yOffset)); + this.rawBuffer[this.rawBufferIndex + 2] = Float.floatToRawIntBits((float) (par5 + this.zOffset)); + + if (this.hasTexture) { + this.rawBuffer[this.rawBufferIndex + 3] = Float.floatToRawIntBits((float) this.textureU); + this.rawBuffer[this.rawBufferIndex + 4] = Float.floatToRawIntBits((float) this.textureV); + } + + if (this.hasColor) { + this.rawBuffer[this.rawBufferIndex + 5] = this.color; + } + + if (this.hasNormals) { + this.rawBuffer[this.rawBufferIndex + 6] = this.normal; + } + + if (this.hasBrightness) { + this.rawBuffer[this.rawBufferIndex + 7] = this.brightness; + } + + this.rawBufferIndex += 8; + ++this.vertexCount; + } + + /** + * Sets the color to the given opaque value (stored as byte values packed in an + * integer). + */ + public void setColorOpaque_I(int par1) { + int var2 = par1 >> 16 & 255; + int var3 = par1 >> 8 & 255; + int var4 = par1 & 255; + this.setColorOpaque(var2, var3, var4); + } + + /** + * Sets the color to the given color (packed as bytes in integer) and alpha + * values. + */ + public void setColorRGBA_I(int par1, int par2) { + int var3 = par1 >> 16 & 255; + int var4 = par1 >> 8 & 255; + int var5 = par1 & 255; + this.setColorRGBA(var3, var4, var5, par2); + } + + /** + * Disables colors for the current draw call. + */ + public void disableColor() { + this.isColorDisabled = true; + } + + /** + * Sets the normal for the current draw call. + */ + public void setNormal(float par1, float par2, float par3) { + this.hasNormals = true; + float len = (float) Math.sqrt(par1 * par1 + par2 * par2 + par3 * par3); + int var4 = (int)((par1 / len) * 127.0F) + 127; + int var5 = (int)((par2 / len) * 127.0F) + 127; + int var6 = (int)((par3 / len) * 127.0F) + 127; + this.normal = var4 & 255 | (var5 & 255) << 8 | (var6 & 255) << 16; + } + + /** + * Sets the translation for all vertices in the current draw call. + */ + public void setTranslation(double par1, double par3, double par5) { + this.xOffset = par1; + this.yOffset = par3; + this.zOffset = par5; + } + + /** + * Offsets the translation for all vertices in the current draw call. + */ + public void addTranslation(float par1, float par2, float par3) { + this.xOffset += (double) par1; + this.yOffset += (double) par2; + this.zOffset += (double) par3; + } +} diff --git a/src/lwjgl/java/net/lax1dude/eaglercraft/adapter/lwjgl/GameWindowListener.java b/src/lwjgl/java/net/lax1dude/eaglercraft/adapter/lwjgl/GameWindowListener.java new file mode 100644 index 0000000..ea9b232 --- /dev/null +++ b/src/lwjgl/java/net/lax1dude/eaglercraft/adapter/lwjgl/GameWindowListener.java @@ -0,0 +1,12 @@ +package net.lax1dude.eaglercraft.adapter.lwjgl; + +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +import net.minecraft.src.Minecraft; + +public final class GameWindowListener extends WindowAdapter { + public void windowClosing(WindowEvent par1WindowEvent) { + Minecraft.getMinecraft().shutdown(); + } +} diff --git a/src/lwjgl/java/net/lax1dude/eaglercraft/adapter/vfs/VFile.java b/src/lwjgl/java/net/lax1dude/eaglercraft/adapter/vfs/VFile.java new file mode 100644 index 0000000..280e5dd --- /dev/null +++ b/src/lwjgl/java/net/lax1dude/eaglercraft/adapter/vfs/VFile.java @@ -0,0 +1,81 @@ +package net.lax1dude.eaglercraft.adapter.vfs; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.stream.Stream; + +public class VFile extends File { + + public VFile(String pathname) { + super(pathname); + } + + public VFile(String parent, String child) { + super(parent, child); + } + + public VFile(File parent, String child) { + super(parent, child); + } + + public VFile(String parent, String child, String child2) { + super(new VFile(parent, child), child2); + } + + public InputStream getInputStream() { + try { + return Files.newInputStream(this.toPath()); + } catch (IOException e) { + return null; + } + } + + public String[] getAllLines() { + try { + return Files.readAllLines(this.toPath(), StandardCharsets.UTF_8).toArray(new String[0]); + } catch (IOException e) { + return null; + } + } + + public String getAllChars() { + try { + return new String(Files.readAllBytes(this.toPath()), StandardCharsets.UTF_8); + } catch (IOException e) { + return null; + } + } + + public boolean setAllChars(String chars) { + return setAllBytes(chars.getBytes(StandardCharsets.UTF_8)); + } + + public boolean setAllBytes(byte[] bytes) { + try { + File f = this.getParentFile(); + if (f != null) { + f.mkdirs(); + } + Files.write(this.toPath(), bytes); + return true; + } catch (IOException e) { + return false; + } + } + + public int deleteAll() { + try (Stream pathStream = Files.walk(this.toPath())) { + pathStream.sorted(Comparator.reverseOrder()) + .map(Path::toFile) + .forEach(File::delete); + return 1; + } catch (IOException e) { + return 0; + } + } +} diff --git a/src/lwjgl/java/paulscode/sound/Channel.java b/src/lwjgl/java/paulscode/sound/Channel.java new file mode 100644 index 0000000..af0efa4 --- /dev/null +++ b/src/lwjgl/java/paulscode/sound/Channel.java @@ -0,0 +1,270 @@ +package paulscode.sound; + +import java.util.LinkedList; +import javax.sound.sampled.AudioFormat; + +/** + * The Channel class is the base class which can be extended for + * library-specific channels. It is also used in the "no-sound" library. + * A channel is a reserved sound-card voice through which sources are played + * back. Channels can be either streaming channels or normal (non-streaming) + * ones. For consistant naming conventions, each sub-class should have the + * name prefix "Channel". + *

+ * SoundSystem License:

+ * You are free to use this library for any purpose, commercial or otherwise. + * You may modify this library or source code, and distribute it any way you + * like, provided the following conditions are met: + *
+ * 1) You may not falsely claim to be the author of this library or any + * unmodified portion of it. + *
+ * 2) You may not copyright this library or a modified version of it and then + * sue me for copyright infringement. + *
+ * 3) If you modify the source code, you must clearly document the changes + * made before redistributing the modified source code, so other users know + * it is not the original code. + *
+ * 4) You are not required to give me credit for this library in any derived + * work, but if you do, you must also mention my website: + * http://www.paulscode.com + *
+ * 5) I the author will not be responsible for any damages (physical, + * financial, or otherwise) caused by the use if this library or any part + * of it. + *
+ * 6) I the author do not guarantee, warrant, or make any representations, + * either expressed or implied, regarding the use of this library or any + * part of it. + *

+ * Author: Paul Lamb + *
+ * http://www.paulscode.com + *
+ */ +public class Channel +{ +/** + * The library class associated with this type of channel. + */ + protected Class libraryType = Library.class; + +/** + * Global identifier for the type of channel (normal or streaming). Possible + * values for this varriable can be found in the + * {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} class. + */ + public int channelType; + +/** + * Processes status messages, warnings, and error messages. + */ + private SoundSystemLogger logger; + +/** + * Whatever source is attached to this channel. + */ + public Source attachedSource = null; + +/** + * Cumulative counter of the buffers played then unqued. + */ + public int buffersUnqueued = 0; + +/** + * Constructor: Takes channelType identifier as a paramater. Possible values + * for channel type can be found in the + * {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} class. + * @param type Type of channel (normal or streaming). + */ + public Channel( int type ) + { + // grab a handle to the message logger: + logger = SoundSystemConfig.getLogger(); + + channelType = type; + } + +/** + * Shuts the channel down and removes references to all instantiated objects. + */ + public void cleanup() + { + logger = null; + } + +/** + * Queues up the initial byte[] buffers of data to be streamed. + * @param bufferList List of the first buffers to be played for a streaming source. + * @return False if an error occurred or if end of stream was reached. + */ + public boolean preLoadBuffers( LinkedList bufferList ) + { + return true; + } + +/** + * Queues up a byte[] buffer of data to be streamed. + * @param buffer The next buffer to be played for a streaming source. + * @return False if an error occurred or if the channel is shutting down. + */ + public boolean queueBuffer( byte[] buffer ) + { + return false; + } + +/** + * Feeds raw data to the stream. + * @param buffer Buffer containing raw audio data to stream. + * @return Number of prior buffers that have been processed. + */ + public int feedRawAudioData( byte[] buffer ) + { + return 1; + } + +/** + * Returns the number of queued byte[] buffers that have finished playing. + * @return Number of buffers processed. + */ + public int buffersProcessed() + { + return 0; + } + +/** + * Calculates the number of milliseconds since the channel began playing. + * @return Milliseconds, or -1 if unable to calculate. + */ + public float millisecondsPlayed() + { + return -1; + } +/** + * Plays the next queued byte[] buffer. This method is run from the seperate + * {@link paulscode.sound.StreamThread StreamThread}. + * @return False when no more buffers are left to process. + */ + public boolean processBuffer() + { + return false; + } + +/** + * Sets the channel up to receive the specified audio format. + */ + public void setAudioFormat( AudioFormat audioFormat ) + {} + +/** + * Dequeues all previously queued data. + */ + public void flush() + {} + +/** + * Stops the channel, dequeues any queued data, and closes the channel. + */ + public void close() + {} + +/** + * Plays the currently attached normal source, opens this channel up for + * streaming, or resumes playback if this channel was paused. + */ + public void play() + {} + +/** + * Temporarily stops playback for this channel. + */ + public void pause() + {} + +/** + * Stops playback for this channel and rewinds the attached source to the + * beginning. + */ + public void stop() + {} + +/** + * Rewinds the attached source to the beginning. Stops the source if it was + * paused. + */ + public void rewind() + {} + +/** + * Used to determine if a channel is actively playing a source. This method + * will return false if the channel is paused or stopped and when no data is + * queued to be streamed. + * @return True if this channel is playing a source. + */ + public boolean playing() + { + return false; + } + +/** + * Returns the name of the class. + * @return "Channel" + library title. + */ + public String getClassName() + { + String libTitle = SoundSystemConfig.getLibraryTitle( libraryType ); + + if( libTitle.equals( "No Sound" ) ) + return "Channel"; + else + return "Channel" + libTitle; + } + +/** + * Prints a message. + * @param message Message to print. + */ + protected void message( String message ) + { + logger.message( message, 0 ); + } + +/** + * Prints an important message. + * @param message Message to print. + */ + protected void importantMessage( String message ) + { + logger.importantMessage( message, 0 ); + } + +/** + * Prints the specified message if error is true. + * @param error True or False. + * @param message Message to print if error is true. + * @return True if error is true. + */ + protected boolean errorCheck( boolean error, String message ) + { + return logger.errorCheck( error, getClassName(), message, 0 ); + } + +/** + * Prints an error message. + * @param message Message to print. + */ + protected void errorMessage( String message ) + { + logger.errorMessage( getClassName(), message, 0 ); + } + +/** + * Prints an exception's error message followed by the stack trace. + * @param e Exception containing the information to print. + */ + protected void printStackTrace( Exception e ) + { + logger.printStackTrace( e, 1 ); + } +} diff --git a/src/lwjgl/java/paulscode/sound/CommandObject.java b/src/lwjgl/java/paulscode/sound/CommandObject.java new file mode 100644 index 0000000..11107af --- /dev/null +++ b/src/lwjgl/java/paulscode/sound/CommandObject.java @@ -0,0 +1,603 @@ +package paulscode.sound; + +/** + * The CommandObject class is used to store arguments in the SoundSystem's + * Command Queue. Queued CommandObjects are then processed by the + * {@link paulscode.sound.CommandThread CommandThread}. Commands are queued + * and executed in the background, so it is unlikely that the user will ever + * need to use this class. + *

+ * SoundSystem License:

+ * You are free to use this library for any purpose, commercial or otherwise. + * You may modify this library or source code, and distribute it any way you + * like, provided the following conditions are met: + *
+ * 1) You may not falsely claim to be the author of this library or any + * unmodified portion of it. + *
+ * 2) You may not copyright this library or a modified version of it and then + * sue me for copyright infringement. + *
+ * 3) If you modify the source code, you must clearly document the changes + * made before redistributing the modified source code, so other users know + * it is not the original code. + *
+ * 4) You are not required to give me credit for this library in any derived + * work, but if you do, you must also mention my website: + * http://www.paulscode.com + *
+ * 5) I the author will not be responsible for any damages (physical, + * financial, or otherwise) caused by the use if this library or any part + * of it. + *
+ * 6) I the author do not guarantee, warrant, or make any representations, + * either expressed or implied, regarding the use of this library or any + * part of it. + *

+ * Author: Paul Lamb + *
+ * http://www.paulscode.com + *
+ */ +public class CommandObject +{ +/** + * Global identifier for the command to initialize the current sound library. + */ + public static final int INITIALIZE = 1; +/** + * Global identifier for the command to pre-load a sound file. + */ + public static final int LOAD_SOUND = 2; +/** + * Global identifier for the command to pre-load a sound file. + */ + public static final int LOAD_DATA = 3; +/** + * Global identifier for the command to remove a sound file from memory. + */ + public static final int UNLOAD_SOUND = 4; +/** + * Global identifier for the command to queue a sound file. + */ + public static final int QUEUE_SOUND = 5; +/** + * Global identifier for the command to dequeue a sound file. + */ + public static final int DEQUEUE_SOUND = 6; +/** + * Global identifier for the command to fade-out transition a source. + */ + public static final int FADE_OUT = 7; +/** + * Global identifier for the command to fade-out/in transition a source. + */ + public static final int FADE_OUT_IN = 8; +/** + * Global identifier for the command to check volume levels of fading sources. + */ + public static final int CHECK_FADE_VOLUMES = 9; +/** + * Global identifier for the command to create a new source. + */ + public static final int NEW_SOURCE = 10; +/** + * Global identifier for the command to create a new raw data stream. + */ + public static final int RAW_DATA_STREAM = 11; +/** + * Global identifier for the command to create a source and immediately play it. + */ + public static final int QUICK_PLAY = 12; +/** + * Global identifier for the command to set a source's position in 3D space. + */ + public static final int SET_POSITION = 13; +/** + * Global identifier for the command to change a source's volume. + */ + public static final int SET_VOLUME = 14; +/** + * Global identifier for the command to change a source's pitch. + */ + public static final int SET_PITCH = 15; +/** + * Global identifier for the command to change a source's priority. + */ + public static final int SET_PRIORITY = 16; +/** + * Global identifier for the command to tell a source whether or not to loop. + */ + public static final int SET_LOOPING = 17; +/** + * Global identifier for the command to set a source's attenuation model. + */ + public static final int SET_ATTENUATION = 18; +/** + * Global identifier for the command to set a source's fade distance or rolloff + * factor. + */ + public static final int SET_DIST_OR_ROLL = 19; +/** + * Global identifier for the command to change the Doppler factor. + */ + public static final int CHANGE_DOPPLER_FACTOR = 20; +/** + * Global identifier for the command to change the Doppler velocity. + */ + public static final int CHANGE_DOPPLER_VELOCITY = 21; +/** + * Global identifier for the command to set a source's velocity. + */ + public static final int SET_VELOCITY = 22; +/** + * Global identifier for the command to set a source's velocity. + */ + public static final int SET_LISTENER_VELOCITY = 23; +/** + * Global identifier for the command to play a source. + */ + public static final int PLAY = 24; +/** + * Global identifier for the command to play a source. + */ + public static final int FEED_RAW_AUDIO_DATA = 25; +/** + * Global identifier for the command to pause a source. + */ + public static final int PAUSE = 26; +/** + * Global identifier for the command to stop a source. + */ + public static final int STOP = 27; +/** + * Global identifier for the command to rewind a source. + */ + public static final int REWIND = 28; +/** + * Global identifier for the command to flush all queued data. + */ + public static final int FLUSH = 29; +/** + * Global identifier for the command to cull a source. + */ + public static final int CULL = 30; +/** + * Global identifier for the command to activate a source. + */ + public static final int ACTIVATE = 31; +/** + * Global identifier for the command to set a source as permanant or temporary. + */ + public static final int SET_TEMPORARY = 32; +/** + * Global identifier for the command to delete a source. + */ + public static final int REMOVE_SOURCE = 33; +/** + * Global identifier for the command to move the listner. + */ + public static final int MOVE_LISTENER = 34; +/** + * Global identifier for the command to set the listener's position. + */ + public static final int SET_LISTENER_POSITION = 35; +/** + * Global identifier for the command to turn the listener. + */ + public static final int TURN_LISTENER = 36; +/** + * Global identifier for the command to set the listener's turn angle. + */ + public static final int SET_LISTENER_ANGLE = 37; +/** + * Global identifier for the command to change the listener's orientation. + */ + public static final int SET_LISTENER_ORIENTATION = 38; +/** + * Global identifier for the command to change the master volume. + */ + public static final int SET_MASTER_VOLUME = 39; +/** + * Global identifier for the command to create a new library. + */ + public static final int NEW_LIBRARY = 40; + +/** + * Any buffer required for a command. + */ + public byte[] buffer; +/** + * Any int arguments required for a command. + */ + public int[] intArgs; +/** + * Any float arguments required for a command. + */ + public float[] floatArgs; +/** + * Any long arguments required for a command. + */ + public long[] longArgs; +/** + * Any boolean arguments required for a command. + */ + public boolean[] boolArgs; +/** + * Any String arguments required for a command. + */ + public String[] stringArgs; + +/** + * Any Class arguments required for a command. + */ + public Class[] classArgs; + +/** + * Any Object arguments required for a command. + */ + public Object[] objectArgs; + +/** + * Which command to execute. + */ + public int Command; + +/** + * Constructor used to create a command which doesn't require any arguments. + * @param cmd Which command to execute. + */ + public CommandObject( int cmd ) + { + Command = cmd; + } +/** + * Constructor used to create a command which requires one integer argument. + * @param cmd Which command to execute. + * @param i The integer argument needed to execute this command. + */ + public CommandObject( int cmd, int i ) + { + Command = cmd; + intArgs = new int[1]; + intArgs[0] = i; + } +/** + * Constructor used to create a command which requires one Library Class + * argument. + * @param cmd Which command to execute. + * @param c The Library Class argument needed to execute this command. + */ + public CommandObject( int cmd, Class c ) + { + Command = cmd; + classArgs = new Class[1]; + classArgs[0] = c; + } +/** + * Constructor used to create a command which requires one float argument. + * @param cmd Which command to execute. + * @param f The float argument needed to execute this command. + */ + public CommandObject( int cmd, float f ) + { + Command = cmd; + floatArgs = new float[1]; + floatArgs[0] = f; + } +/** + * Constructor used to create a command which requires one String argument. + * @param cmd Which command to execute. + * @param s The String argument needed to execute this command. + */ + public CommandObject( int cmd, String s ) + { + Command = cmd; + stringArgs = new String[1]; + stringArgs[0] = s; + } +/** + * Constructor used to create a command which requires one Object argument. + * @param cmd Which command to execute. + * @param o The Object argument needed to execute this command. + */ + public CommandObject( int cmd, Object o ) + { + Command = cmd; + objectArgs = new Object[1]; + objectArgs[0] = o; + } +/** + * Constructor used to create a command which requires one String argument and + * one Object argument. + * @param cmd Which command to execute. + * @param s The String argument needed to execute this command. + * @param o The Object argument needed to execute this command. + */ + public CommandObject( int cmd, String s, Object o ) + { + Command = cmd; + stringArgs = new String[1]; + stringArgs[0] = s; + objectArgs = new Object[1]; + objectArgs[0] = o; + } +/** + * Constructor used to create a command which requires one String argument and + * one byte buffer argument. + * @param cmd Which command to execute. + * @param s The String argument needed to execute this command. + * @param buff The byte buffer argument needed to execute this command. + */ + public CommandObject( int cmd, String s, byte[] buff ) + { + Command = cmd; + stringArgs = new String[1]; + stringArgs[0] = s; + buffer = buff; + } +/** + * Constructor used to create a command which requires one String argument, one + * Object argument, and one long argument. + * @param cmd Which command to execute. + * @param s The String argument needed to execute this command. + * @param o The Object argument needed to execute this command. + * @param l The long argument needed to execute this command. + */ + public CommandObject( int cmd, String s, Object o, long l ) + { + Command = cmd; + stringArgs = new String[1]; + stringArgs[0] = s; + objectArgs = new Object[1]; + objectArgs[0] = o; + longArgs = new long[1]; + longArgs[0] = l; + } +/** + * Constructor used to create a command which requires one String argument, one + * Object argument, and two long arguments. + * @param cmd Which command to execute. + * @param s The String argument needed to execute this command. + * @param o The Object argument needed to execute this command. + * @param l1 The first long argument needed to execute this command. + * @param l2 The second long argument needed to execute this command. + */ + public CommandObject( int cmd, String s, Object o, long l1, long l2 ) + { + Command = cmd; + stringArgs = new String[1]; + stringArgs[0] = s; + objectArgs = new Object[1]; + objectArgs[0] = o; + longArgs = new long[2]; + longArgs[0] = l1; + longArgs[1] = l2; + } +/** + * Constructor used to create a command which requires two String arguments. + * @param cmd Which command to execute. + * @param s1 The first String argument needed to execute this command. + * @param s2 The second String argument needed to execute this command. + */ + public CommandObject( int cmd, String s1, String s2 ) + { + Command = cmd; + stringArgs = new String[2]; + stringArgs[0] = s1; + stringArgs[1] = s2; + } +/** + * Constructor used to create a command which requires a String and an int as + * arguments. + * @param cmd Which command to execute. + * @param s The String argument needed to execute this command. + * @param i The integer argument needed to execute this command. + */ + public CommandObject( int cmd, String s, int i ) + { + Command = cmd; + intArgs = new int[1]; + stringArgs = new String[1]; + intArgs[0] = i; + stringArgs[0] = s; + } +/** + * Constructor used to create a command which requires a String and a float as + * arguments. + * @param cmd Which command to execute. + * @param s The String argument needed to execute this command. + * @param f The float argument needed to execute this command. + */ + public CommandObject( int cmd, String s, float f ) + { + Command = cmd; + floatArgs = new float[1]; + stringArgs = new String[1]; + floatArgs[0] = f; + stringArgs[0] = s; + } +/** + * Constructor used to create a command which requires a String and a boolean + * as arguments. + * @param cmd Which command to execute. + * @param s The String argument needed to execute this command. + * @param b The boolean argument needed to execute this command. + */ + public CommandObject( int cmd, String s, boolean b ) + { + Command = cmd; + boolArgs = new boolean[1]; + stringArgs = new String[1]; + boolArgs[0] = b; + stringArgs[0] = s; + } +/** + * Constructor used to create a command which requires three float arguments. + * @param cmd Which command to execute. + * @param f1 The first float argument needed to execute this command. + * @param f2 The second float argument needed to execute this command. + * @param f3 The third float argument needed to execute this command. + */ + public CommandObject( int cmd, float f1, float f2, float f3 ) + { + Command = cmd; + floatArgs = new float[3]; + floatArgs[0] = f1; + floatArgs[1] = f2; + floatArgs[2] = f3; + } +/** + * Constructor used to create a command which a String and three float + * arguments. + * @param cmd Which command to execute. + * @param s The String argument needed to execute this command. + * @param f1 The first float argument needed to execute this command. + * @param f2 The second float argument needed to execute this command. + * @param f3 The third float argument needed to execute this command. + */ + public CommandObject( int cmd, String s, float f1, float f2, float f3 ) + { + Command = cmd; + floatArgs = new float[3]; + stringArgs = new String[1]; + floatArgs[0] = f1; + floatArgs[1] = f2; + floatArgs[2] = f3; + stringArgs[0] = s; + } +/** + * Constructor used to create a command which requires six float arguments. + * @param cmd Which command to execute. + * @param f1 The first float argument needed to execute this command. + * @param f2 The second float argument needed to execute this command. + * @param f3 The third float argument needed to execute this command. + * @param f4 The fourth float argument needed to execute this command. + * @param f5 The fifth float argument needed to execute this command. + * @param f6 The sixth float argument needed to execute this command. + */ + public CommandObject( int cmd, float f1, float f2, float f3, float f4, + float f5, float f6 ) + { + Command = cmd; + floatArgs = new float[6]; + floatArgs[0] = f1; + floatArgs[1] = f2; + floatArgs[2] = f3; + floatArgs[3] = f4; + floatArgs[4] = f5; + floatArgs[5] = f6; + } +/** + * Constructor used to create a command which requires several arguments. + * @param cmd Which command to execute. + * @param b1 The first boolean argument needed to execute this command. + * @param b2 The second boolean argument needed to execute this command. + * @param b3 The third boolean argument needed to execute this command. + * @param s The String argument needed to execute this command. + * @param o The Object argument needed to execute this command. + * @param f1 The first float argument needed to execute this command. + * @param f2 The second float argument needed to execute this command. + * @param f3 The third float argument needed to execute this command. + * @param i The integer argument needed to execute this command. + * @param f4 The fourth float argument needed to execute this command. + */ + public CommandObject( int cmd, + boolean b1, boolean b2, boolean b3, + String s, Object o, + float f1, float f2, float f3, + int i, float f4 ) + { + Command = cmd; + intArgs = new int[1]; + floatArgs = new float[4]; + boolArgs = new boolean[3]; + stringArgs = new String[1]; + objectArgs = new Object[1]; + intArgs[0] = i; + floatArgs[0] = f1; + floatArgs[1] = f2; + floatArgs[2] = f3; + floatArgs[3] = f4; + boolArgs[0] = b1; + boolArgs[1] = b2; + boolArgs[2] = b3; + stringArgs[0] = s; + objectArgs[0] = o; + } +/** + * Constructor used to create a command which requires several arguments. + * @param cmd Which command to execute. + * @param b1 The first boolean argument needed to execute this command. + * @param b2 The second boolean argument needed to execute this command. + * @param b3 The third boolean argument needed to execute this command. + * @param s The String argument needed to execute this command. + * @param o The Object argument needed to execute this command. + * @param f1 The first float argument needed to execute this command. + * @param f2 The second float argument needed to execute this command. + * @param f3 The third float argument needed to execute this command. + * @param i The integer argument needed to execute this command. + * @param f4 The fourth float argument needed to execute this command. + * @param b4 The fourth boolean argument needed to execute this command. + */ + public CommandObject( int cmd, + boolean b1, boolean b2, boolean b3, + String s, + Object o, + float f1, float f2, float f3, + int i, float f4, boolean b4 ) + { + Command = cmd; + intArgs = new int[1]; + floatArgs = new float[4]; + boolArgs = new boolean[4]; + stringArgs = new String[1]; + objectArgs = new Object[1]; + intArgs[0] = i; + floatArgs[0] = f1; + floatArgs[1] = f2; + floatArgs[2] = f3; + floatArgs[3] = f4; + boolArgs[0] = b1; + boolArgs[1] = b2; + boolArgs[2] = b3; + boolArgs[3] = b4; + stringArgs[0] = s; + objectArgs[0] = o; + } +/** + * Constructor used to create a command which requires several arguments. + * @param cmd Which command to execute. + * @param o The Object argument needed to execute this command. + * @param b The first boolean argument needed to execute this command. + * @param s The String argument needed to execute this command. + * @param f1 The first float argument needed to execute this command. + * @param f2 The second float argument needed to execute this command. + * @param f3 The third float argument needed to execute this command. + * @param i The integer argument needed to execute this command. + * @param f4 The fourth float argument needed to execute this command. + */ + public CommandObject( int cmd, + Object o, + boolean b, + String s, + float f1, float f2, float f3, + int i, + float f4 ) + { + Command = cmd; + intArgs = new int[1]; + floatArgs = new float[4]; + boolArgs = new boolean[1]; + stringArgs = new String[1]; + objectArgs = new Object[1]; + intArgs[0] = i; + floatArgs[0] = f1; + floatArgs[1] = f2; + floatArgs[2] = f3; + floatArgs[3] = f4; + boolArgs[0] = b; + stringArgs[0] = s; + objectArgs[0] = o; + } +} diff --git a/src/lwjgl/java/paulscode/sound/CommandThread.java b/src/lwjgl/java/paulscode/sound/CommandThread.java new file mode 100644 index 0000000..f0c81af --- /dev/null +++ b/src/lwjgl/java/paulscode/sound/CommandThread.java @@ -0,0 +1,178 @@ +package paulscode.sound; + +import net.lax1dude.eaglercraft.EaglerAdapter; + +/** + * The CommandThread class is designed to move all command processing into a + * single thread to be run in the background and avoid conflicts between + * threads. Commands are processed in the order that they were queued. The + * arguements for each command are stored in a + * {@link paulscode.sound.CommandObject CommandObject}. The Command Queue is + * located in the {@link paulscode.sound.SoundSystem SoundSystem} class. + * Calling kill() stops the thread, and this should be immediatly followed + * by a call to interrupt() to wake up the thread so it may end. This class + * also checks for temporary sources that are finished playing, and removes + * them. + * + * NOTE: The command thread is created automatically by the sound system, so it + * is unlikely that the user would ever need to use this class. + *

+ * SoundSystem License:

+ * You are free to use this library for any purpose, commercial or otherwise. + * You may modify this library or source code, and distribute it any way you + * like, provided the following conditions are met: + *
+ * 1) You may not falsely claim to be the author of this library or any + * unmodified portion of it. + *
+ * 2) You may not copyright this library or a modified version of it and then + * sue me for copyright infringement. + *
+ * 3) If you modify the source code, you must clearly document the changes + * made before redistributing the modified source code, so other users know + * it is not the original code. + *
+ * 4) You are not required to give me credit for this library in any derived + * work, but if you do, you must also mention my website: + * http://www.paulscode.com + *
+ * 5) I the author will not be responsible for any damages (physical, + * financial, or otherwise) caused by the use if this library or any part + * of it. + *
+ * 6) I the author do not guarantee, warrant, or make any representations, + * either expressed or implied, regarding the use of this library or any + * part of it. + *

+ * Author: Paul Lamb + *
+ * http://www.paulscode.com + *
+ */ +public class CommandThread extends SimpleThread +{ +/** + * Processes status messages, warnings, and error messages. + */ + protected SoundSystemLogger logger; + +/** + * Handle to the Sound System. This is where the Command Queue is located. + */ + private SoundSystem soundSystem; + +/** + * Name of this class. + */ + protected String className = "CommandThread"; + +/** + * Constructor: Takes a handle to the SoundSystem object as a parameter. + * @param s Handle to the SoundSystem. +*/ + public CommandThread( SoundSystem s ) + { + // grab a handle to the message logger: + logger = SoundSystemConfig.getLogger(); + + soundSystem = s; + } + +/** + * Shuts the thread down and removes references to all instantiated objects. + * NOTE: Method alive() will return false when cleanup() has finished. + */ + @Override + protected void cleanup() + { + kill(); + + logger = null; + soundSystem = null; + + super.cleanup(); // Important! + } + +/** + * The main loop for processing commands. The Command Thread starts out + * asleep, and it sleeps again after it finishes processing commands, so it + * must be interrupted when commands are queued for processing. + */ + @Override + public void run() + { + long previousTime = EaglerAdapter.steadyTimeMillis(); + long currentTime = previousTime; + + if( soundSystem == null ) + { + errorMessage( "SoundSystem was null in method run().", 0 ); + cleanup(); + return; + } + + // Start out asleep: + snooze( 3600000 ); + + while( !dying() ) + { + // Perform user-specific source management: + soundSystem.ManageSources(); + + // Process all queued commands: + soundSystem.CommandQueue( null ); + + // Remove temporary sources every ten seconds: + currentTime = EaglerAdapter.steadyTimeMillis(); + if( (!dying()) && ((currentTime - previousTime) > 10000) ) + { + previousTime = currentTime; + soundSystem.removeTemporarySources(); + } + + // Wait for more commands: + if( !dying() ) + snooze( 3600000 ); + } + + cleanup(); // Important! + } + +/** + * Prints a message. + * @param message Message to print. + */ + protected void message( String message, int indent ) + { + logger.message( message, indent ); + } + +/** + * Prints an important message. + * @param message Message to print. + */ + protected void importantMessage( String message, int indent ) + { + logger.importantMessage( message, indent ); + } + +/** + * Prints the specified message if error is true. + * @param error True or False. + * @param message Message to print if error is true. + * @return True if error is true. + */ + protected boolean errorCheck( boolean error, String message ) + { + return logger.errorCheck( error, className, message, 0 ); + } + +/** + * Prints an error message. + * @param message Message to print. + */ + protected void errorMessage( String message, int indent ) + { + logger.errorMessage( className, message, indent ); + } +} diff --git a/src/lwjgl/java/paulscode/sound/FilenameURL.java b/src/lwjgl/java/paulscode/sound/FilenameURL.java new file mode 100644 index 0000000..96b48dc --- /dev/null +++ b/src/lwjgl/java/paulscode/sound/FilenameURL.java @@ -0,0 +1,153 @@ +package paulscode.sound; + +import java.net.URL; + +/** + * The FilenameURL class is designed to associate a String filename/identifier + * with a URL. Handles either case where user supplies a String path or user + * supplies a URL instance. + *

+ * SoundSystem License:

+ * You are free to use this library for any purpose, commercial or otherwise. + * You may modify this library or source code, and distribute it any way you + * like, provided the following conditions are met: + *
+ * 1) You may not falsely claim to be the author of this library or any + * unmodified portion of it. + *
+ * 2) You may not copyright this library or a modified version of it and then + * sue me for copyright infringement. + *
+ * 3) If you modify the source code, you must clearly document the changes + * made before redistributing the modified source code, so other users know + * it is not the original code. + *
+ * 4) You are not required to give me credit for this library in any derived + * work, but if you do, you must also mention my website: + * http://www.paulscode.com + *
+ * 5) I the author will not be responsible for any damages (physical, + * financial, or otherwise) caused by the use if this library or any part + * of it. + *
+ * 6) I the author do not guarantee, warrant, or make any representations, + * either expressed or implied, regarding the use of this library or any + * part of it. + *

+ * Author: Paul Lamb + *
+ * http://www.paulscode.com + *
+ */ +public class FilenameURL +{ +/** + * Processes status messages, warnings, and error messages. + */ + private SoundSystemLogger logger; + +/** + * Filename or identifier for the file. + */ + private String filename = null; + +/** + * URL interface to the file. + */ + private URL url = null; + +/** + * Constructor: Saves handles to the url and identifier. The identifier should + * look like a filename, and it must have the correct extension so SoundSystem + * knows what format to use for the file referenced by the URL instance. + * @param url URL interface to a file. + * @param identifier Identifier (filename) for the file. + */ + public FilenameURL( URL url, String identifier ) + { + // grab a handle to the message logger: + logger = SoundSystemConfig.getLogger(); + + filename = identifier; + this.url = url; + } + +/** + * Constructor: Saves a handle to the filename (used later to generate a URL + * instance). The file may either be located within the + * JAR or at an online location. If the file is online, filename must begin + * with "http://", since that is how SoundSystem recognizes URL names. + * @param filename Name of the file. + */ + public FilenameURL( String filename ) + { + // grab a handle to the message logger: + logger = SoundSystemConfig.getLogger(); + + this.filename = filename; + url = null; + } + +/** + * Returns the filename/identifier. + * @return Filename or identifier for the file. + */ + public String getFilename() + { + return filename; + } + +/** + * Returns the URL interface to the file. If a URL was not originally specified + * in the constructor, then the first time this method is called it creates a + * URL instance using the previously specified filename. + * @return URL interface to the file. + */ + public URL getURL() + { + if( url == null ) + { + // Check if the file is online or inside the JAR: + if( filename.matches( SoundSystemConfig.PREFIX_URL ) ) + { + // Online + try + { + url = new URL( filename ); + } + catch( Exception e ) + { + errorMessage( "Unable to access online URL in " + + "method 'getURL'" ); + printStackTrace( e ); + return null; + } + } + else + { + // Inside the JAR + url = getClass().getClassLoader().getResource( + SoundSystemConfig.getSoundFilesPackage() + filename ); + } + } + return url; + } + +/** + * Prints an error message. + * @param message Message to print. + */ + private void errorMessage( String message ) + { + logger.errorMessage( "MidiChannel", message, 0 ); + } + +/** + * Prints an exception's error message followed by the stack trace. + * @param e Exception containing the information to print. + */ + private void printStackTrace( Exception e ) + { + logger.printStackTrace( e, 1 ); + } +} diff --git a/src/lwjgl/java/paulscode/sound/ICodec.java b/src/lwjgl/java/paulscode/sound/ICodec.java new file mode 100644 index 0000000..9385445 --- /dev/null +++ b/src/lwjgl/java/paulscode/sound/ICodec.java @@ -0,0 +1,119 @@ +package paulscode.sound; + +import java.net.URL; +import javax.sound.sampled.AudioFormat; + +/** + * The ICodec interface provides a common interface for SoundSystem to use + * for accessing external codec libraries. + *

+ * SoundSystem License:

+ * You are free to use this library for any purpose, commercial or otherwise. + * You may modify this library or source code, and distribute it any way you + * like, provided the following conditions are met: + *
+ * 1) You may not falsely claim to be the author of this library or any + * unmodified portion of it. + *
+ * 2) You may not copyright this library or a modified version of it and then + * sue me for copyright infringement. + *
+ * 3) If you modify the source code, you must clearly document the changes + * made before redistributing the modified source code, so other users know + * it is not the original code. + *
+ * 4) You are not required to give me credit for this library in any derived + * work, but if you do, you must also mention my website: + * http://www.paulscode.com + *
+ * 5) I the author will not be responsible for any damages (physical, + * financial, or otherwise) caused by the use if this library or any part + * of it. + *
+ * 6) I the author do not guarantee, warrant, or make any representations, + * either expressed or implied, regarding the use of this library or any + * part of it. + *

+ * Author: Paul Lamb + *
+ * http://www.paulscode.com + *
+ */ +public interface ICodec +{ +/** + * Should tell derived classes when they may need to reverse the byte order of + * the data before returning it in the read() and readAll() methods. The + * reason for the reversBytOrder method is because some external codec + * libraries produce audio data in a format that some external audio libraries + * require to be reversed. Derivatives of the Library and Source classes for + * audio libraries which require this type of data to be reversed should call + * the reverseByteOrder() method for all instances of ICodec that they use. + * Derivatives of the ICodec interface for codec libraries which which produce + * this type of data should use the reverseByteOrder() method to know when the + * data needs to be reversed before returning it in the read() and readAll() + * methods. If a particular codec library does not produce this type of data, + * its derived ICodec class may disregard any calls to the reverseByteOrder() + * method. + * @param b True if the calling audio library requires byte-reversal by some codec libraries. + */ + public void reverseByteOrder( boolean b ); + +/** + * Should make any preperations required before reading from the audio stream. + * If another stream is already opened, it should be closed and a new audio + * stream opened in its place. This method is used internally by SoundSystem + * not only to initialize a stream, but also to rewind streams and to switch + * stream sources on the fly. + * @return False if an error occurred or if end of stream was reached. + */ + public boolean initialize( URL url ); + +/** + * Should return false if the stream is busy initializing. To prevent bad + * data from being returned by this method, derived classes should internally + * synchronize with any elements used by both the initialized() and initialize() + * methods. + * @return True if steam is initialized. + */ + public boolean initialized(); + +/** + * Should read in one stream buffer worth of audio data. See + * {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more + * information about accessing and changing default settings. + * @return The audio data wrapped into a SoundBuffer context. + */ + public SoundBuffer read(); + +/** + * Should read in all the audio data from the stream (up to the default + * "maximum file size". See + * {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more + * information about accessing and changing default settings. + * @return the audio data wrapped into a SoundBuffer context. + */ + public SoundBuffer readAll(); + +/** + * Should return false if there is still more data available to be read in. To + * prevent bad data from being returned by this method, derived classes should + * internally synchronize with any elements used in both the endOfStream() and + * the read() or readAll() methods. + * @return True if end of stream was reached. + */ + public boolean endOfStream(); + +/** + * Should close any open streams and remove references to all instantiated + * objects. + */ + public void cleanup(); + +/** + * Should return the audio format of the data being returned by the read() and + * readAll() methods. + * @return Information wrapped into an AudioFormat context. + */ + public AudioFormat getAudioFormat(); +} diff --git a/src/lwjgl/java/paulscode/sound/IStreamListener.java b/src/lwjgl/java/paulscode/sound/IStreamListener.java new file mode 100644 index 0000000..6f767f4 --- /dev/null +++ b/src/lwjgl/java/paulscode/sound/IStreamListener.java @@ -0,0 +1,11 @@ +package paulscode.sound; + +public interface IStreamListener +{ + /** + * Notifies implementation that an End Of Stream was reached. + * @param sourcename String identifier of the source which reached the EOS. + * @param queueSize Number of items left the the stream's play queue, or zero if none. + */ + public void endOfStream( String sourcename, int queueSize ); +} diff --git a/src/lwjgl/java/paulscode/sound/Library.java b/src/lwjgl/java/paulscode/sound/Library.java new file mode 100644 index 0000000..79011db --- /dev/null +++ b/src/lwjgl/java/paulscode/sound/Library.java @@ -0,0 +1,1615 @@ +package paulscode.sound; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import javax.sound.sampled.AudioFormat; + +/** + * The Library class is the class from which all library types are extended. + * It provides generic methods for interfacing with the audio libraries + * supported by the SoundSystem. Specific libraries should extend this class + * and override the necessary methods. For consistant naming conventions, each + * sub-class should have the name prefix "Library". + * + * This class may also be used as the "No Sound Library" (i.e. silent mode) if + * no other audio libraries are supported by the host machine, or to mute all + * sound. + *

+ * SoundSystem License:

+ * You are free to use this library for any purpose, commercial or otherwise. + * You may modify this library or source code, and distribute it any way you + * like, provided the following conditions are met: + *
+ * 1) You may not falsely claim to be the author of this library or any + * unmodified portion of it. + *
+ * 2) You may not copyright this library or a modified version of it and then + * sue me for copyright infringement. + *
+ * 3) If you modify the source code, you must clearly document the changes + * made before redistributing the modified source code, so other users know + * it is not the original code. + *
+ * 4) You are not required to give me credit for this library in any derived + * work, but if you do, you must also mention my website: + * http://www.paulscode.com + *
+ * 5) I the author will not be responsible for any damages (physical, + * financial, or otherwise) caused by the use if this library or any part + * of it. + *
+ * 6) I the author do not guarantee, warrant, or make any representations, + * either expressed or implied, regarding the use of this library or any + * part of it. + *

+ * Author: Paul Lamb + *
+ * http://www.paulscode.com + *
+ */ +public class Library +{ +/** + * Processes status messages, warnings, and error messages. + */ + private SoundSystemLogger logger; + +/** + * Position and orientation of the listener. + */ + protected ListenerData listener; + +/** + * Map containing sound file data for easy lookup by filename / identifier. + */ + protected HashMap bufferMap = null; + +/** + * Map containing all created sources for easy look-up by name. + */ + protected HashMap sourceMap; // (name, source data) pairs + +/** + * Interface through which MIDI files can be played. + */ + private MidiChannel midiChannel; + +/** + * Array containing maximum number of non-streaming audio channels. + */ + protected List streamingChannels; + +/** + * Array containing maximum number of non-streaming audio channels. + */ + protected List normalChannels; + +/** + * Source name last played on each streaming channel. + */ + private String[] streamingChannelSourceNames; + +/** + * Source name last played on each non-streaming channel. + */ + private String[] normalChannelSourceNames; + +/** + * Increments through the steaming channel list as new sources are played. + */ + private int nextStreamingChannel = 0; + +/** + * Increments through the non-steaming channel list as new sources are played. + */ + private int nextNormalChannel = 0; + +/** + * Handles processing for all streaming sources. + */ + protected StreamThread streamThread; + +/** + * Whether or not the library requires reversal of audio data byte order. + */ + protected boolean reverseByteOrder = false; + +/** + * Constructor: Instantiates the source map and listener information. NOTES: + * The 'super()' method should be at the top of constructors for all extended + * classes. The varriable 'libraryType' should be given a new value in the + * constructors for all extended classes. + */ + public Library() throws SoundSystemException + { + // grab a handle to the message logger: + logger = SoundSystemConfig.getLogger(); + + // instantiate the buffer map: + bufferMap = new HashMap(); + + // instantiate the source map: + sourceMap = new HashMap(); + + listener = new ListenerData( 0.0f, 0.0f, 0.0f, // position + 0.0f, 0.0f, -1.0f, // look-at direction + 0.0f, 1.0f, 0.0f, // up direction + 0.0f ); // angle + + streamingChannels = new LinkedList(); + normalChannels = new LinkedList(); + streamingChannelSourceNames = new String[ + SoundSystemConfig.getNumberStreamingChannels() ]; + normalChannelSourceNames = new String[ + SoundSystemConfig.getNumberNormalChannels() ]; + + streamThread = new StreamThread(); + streamThread.start(); + } + + +/* ########################################################################## */ +/* BEGIN OVERRIDE METHODS */ +/* */ +/* The following methods should be overrided as required */ +/* ########################################################################## */ + +/** + * Stops all sources, shuts down sound library, and removes references to all + * instantiated objects. + */ + public void cleanup() + { + streamThread.kill(); + streamThread.interrupt(); + + // wait up to 5 seconds for stream thread to end: + for( int i = 0; i < 50; i++ ) + { + if( !streamThread.alive() ) + break; + try + { + Thread.sleep(100); + } + catch(Exception e) + {} + } + + if( streamThread.alive() ) + { + errorMessage( "Stream thread did not die!" ); + message( "Ignoring errors... continuing clean-up." ); + } + + if( midiChannel != null ) + { + midiChannel.cleanup(); + midiChannel = null; + } + + Channel channel = null; + if( streamingChannels != null ) + { + while( !streamingChannels.isEmpty() ) + { + channel = streamingChannels.remove(0); + channel.close(); + channel.cleanup(); + channel = null; + } + streamingChannels.clear(); + streamingChannels = null; + } + if( normalChannels != null ) + { + while( !normalChannels.isEmpty() ) + { + channel = normalChannels.remove(0); + channel.close(); + channel.cleanup(); + channel = null; + } + normalChannels.clear(); + normalChannels = null; + } + + Set keys = sourceMap.keySet(); + Iterator iter = keys.iterator(); + String sourcename; + Source source; + + // loop through and cleanup all the sources: + while( iter.hasNext() ) + { + sourcename = iter.next(); + source = sourceMap.get( sourcename ); + if( source != null ) + source.cleanup(); + } + sourceMap.clear(); + sourceMap = null; + + listener = null; + streamThread = null; + } + +/** + * Initializes the sound library. + */ + public void init() throws SoundSystemException + { + Channel channel = null; + + // create the streaming channels: + for( int x = 0; x < SoundSystemConfig.getNumberStreamingChannels(); x++ ) + { + channel = createChannel( SoundSystemConfig.TYPE_STREAMING ); + if( channel == null ) + break; + streamingChannels.add( channel ); + } + // create the non-streaming channels: + for( int x = 0; x < SoundSystemConfig.getNumberNormalChannels(); x++ ) + { + channel = createChannel( SoundSystemConfig.TYPE_NORMAL ); + if( channel == null ) + break; + normalChannels.add( channel ); + } + } + +/** + * Checks if the no-sound library type is compatible. + * @return True or false. + */ + public static boolean libraryCompatible() + { + return true; // the no-sound library is always compatible. + } + +/** + * Creates a new channel of the specified type (normal or streaming). Possible + * values for channel type can be found in the + * {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} class. + * @param type Type of channel. + * @return The new channel. + */ + protected Channel createChannel( int type ) + { + return new Channel( type ); + } + +/** + * Pre-loads a sound into memory. + * @param filenameURL Filename/URL of the sound file to load. + * @return True if the sound loaded properly. + */ + public boolean loadSound( FilenameURL filenameURL ) + { + return true; + } + +/** + * Saves the specified sample data, under the specified identifier. This + * identifier can be later used in place of 'filename' parameters to reference + * the sample data. + * @param buffer the sample data and audio format to save. + * @param identifier What to call the sample. + * @return True if there weren't any problems. + */ + public boolean loadSound( SoundBuffer buffer, String identifier ) + { + return true; + } + +/** + * Returns the filenames of all previously loaded sounds. + * @return LinkedList of String filenames. + */ + public LinkedList getAllLoadedFilenames() + { + LinkedList filenames = new LinkedList(); + Set keys = bufferMap.keySet(); + Iterator iter = keys.iterator(); + + // loop through and update the volume of all sources: + while( iter.hasNext() ) + { + filenames.add( iter.next() ); + } + + return filenames; + } + +/** + * Returns the sourcenames of all sources. + * @return LinkedList of String sourcenames. + */ + public LinkedList getAllSourcenames() + { + LinkedList sourcenames = new LinkedList(); + Set keys = sourceMap.keySet(); + Iterator iter = keys.iterator(); + + if( midiChannel != null ) + sourcenames.add( midiChannel.getSourcename() ); + + // loop through and update the volume of all sources: + while( iter.hasNext() ) + { + sourcenames.add( iter.next() ); + } + + return sourcenames; + } + +/** + * Removes a pre-loaded sound from memory. This is a good method to use for + * freeing up memory after a large sound file is no longer needed. NOTE: the + * source will remain in memory after this method has been called, for as long + * as the sound is attached to an existing source. + * @param filename Filename/identifier of the sound file to unload. + */ + public void unloadSound( String filename ) + { + bufferMap.remove( filename ); + } + +/** + * Opens a direct line for streaming audio data. + * @param audioFormat Format that the data will be in. + * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename. + * @param posX X position for this source. + * @param posY Y position for this source. + * @param posZ Z position for this source. + * @param attModel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel". + */ + public void rawDataStream( AudioFormat audioFormat, boolean priority, + String sourcename, float posX, float posY, + float posZ, int attModel, float distOrRoll ) + { + sourceMap.put( sourcename, + new Source( audioFormat, priority, sourcename, posX, + posY, posZ, attModel, distOrRoll ) ); + } + +/** + * Creates a new source using the specified information. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param toStream Setting this to true will load the sound in pieces rather than all at once. + * @param toLoop Should this source loop, or play only once. + * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename. + * @param filenameURL Filename/URL of the sound file to play at this source. + * @param posX X position for this source. + * @param posY Y position for this source. + * @param posZ Z position for this source. + * @param attModel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel". + */ + public void newSource( boolean priority, boolean toStream, boolean toLoop, + String sourcename, FilenameURL filenameURL, + float posX, float posY, float posZ, int attModel, + float distOrRoll ) + { + sourceMap.put( sourcename, + new Source( priority, toStream, toLoop, sourcename, + filenameURL, null, posX, posY, posZ, + attModel, distOrRoll, false ) ); + } + +/** + * Creates and immediately plays a new source that will be removed when it + * finishes playing. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param toStream Setting this to true will load the sound in pieces rather than all at once. + * @param toLoop Should this source loop, or play only once. + * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename. + * @param filenameURL The filename/URL of the sound file to play at this source. + * @param posX X position for this source. + * @param posY Y position for this source. + * @param posZ Z position for this source. + * @param attModel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel". + */ + public void quickPlay( boolean priority, boolean toStream, boolean toLoop, + String sourcename, FilenameURL filenameURL, + float posX, float posY, float posZ, int attModel, + float distOrRoll, boolean tmp ) + { + sourceMap.put( sourcename, + new Source( priority, toStream, toLoop, sourcename, + filenameURL, null, posX, posY, posZ, + attModel, distOrRoll, tmp ) ); + } + +/** + * + * Defines whether or not the source should be removed after it finishes + * playing. + * @param sourcename The source's name. + * @param temporary True or False. + */ + public void setTemporary( String sourcename, boolean temporary ) + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) + mySource.setTemporary( temporary ); + } + +/** + * Changes the specified source's position. + * @param sourcename The source's name. + * @param x Destination X coordinate. + * @param y Destination Y coordinate. + * @param z Destination Z coordinate. + */ + public void setPosition( String sourcename, float x, float y, float z ) + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) + mySource.setPosition( x, y, z ); + } + +/** + * Sets the specified source's priority factor. A priority source will not be + * overriden if there are too many sources playing at once. + * @param sourcename The source's name. + * @param pri True or False. + */ + public void setPriority( String sourcename, boolean pri ) + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) + mySource.setPriority( pri ); + } + +/** + * Sets the specified source's looping parameter. If parameter lp is false, + * the source will play once and stop. + * @param sourcename The source's name. + * @param lp True or False. + */ + public void setLooping( String sourcename, boolean lp ) + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) + mySource.setLooping( lp ); + } + +/** + * Sets the specified source's attenuation model. + * @param sourcename The source's name. + * @param model Attenuation model to use. + */ + public void setAttenuation( String sourcename, int model ) + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) + mySource.setAttenuation( model ); + } + +/** + * Sets the specified source's fade distance or rolloff factor. + * @param sourcename The source's name. + * @param dr Fade distance or rolloff factor. + */ + public void setDistOrRoll( String sourcename, float dr) + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) + mySource.setDistOrRoll( dr ); + } + +/** + * Sets the specified source's velocity, for use in Doppler effect. + * @param sourcename The source's name. + * @param x Velocity along world x-axis. + * @param y Velocity along world y-axis. + * @param z Velocity along world z-axis. + */ + public void setVelocity( String sourcename, float x, float y, float z ) + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) + mySource.setVelocity( x, y, z ); + } + +/** + * Sets the listener's velocity, for use in Doppler effect. + * @param x Velocity along world x-axis. + * @param y Velocity along world y-axis. + * @param z Velocity along world z-axis. + */ + public void setListenerVelocity( float x, float y, float z ) + { + listener.setVelocity( x, y, z ); + } + +/** + * Notifies the underlying library that the Doppler parameters have changed. + */ + public void dopplerChanged() + {} + +/** + * Returns the number of miliseconds since the specified source began playing. + * @return miliseconds, or -1 if not playing or unable to calculate + */ + public float millisecondsPlayed( String sourcename ) + { + if( sourcename == null || sourcename.equals( "" ) ) + { + errorMessage( "Sourcename not specified in method " + + "'millisecondsPlayed'" ); + return -1; + } + + if( midiSourcename( sourcename ) ) + { + errorMessage( "Unable to calculate milliseconds for MIDI source." ); + return -1; + } + else + { + Source source = sourceMap.get( sourcename ); + if( source == null ) + { + errorMessage( "Source '" + sourcename + "' not found in " + + "method 'millisecondsPlayed'" ); + } + return source.millisecondsPlayed(); + } + } +/** + * Feeds raw data through the specified source. The source must be a + * streaming source and it can not be already associated with a file or URL to + * stream from. + * @param sourcename Name of the streaming source to play from. + * @param buffer Byte buffer containing raw audio data to stream. + * @return Number of prior buffers that have been processed, or -1 if unable to queue the buffer (if the source was culled, for example). + */ + public int feedRawAudioData( String sourcename, byte[] buffer ) + { + if( sourcename == null || sourcename.equals( "" ) ) + { + errorMessage( "Sourcename not specified in method " + + "'feedRawAudioData'" ); + return -1; + } + + if( midiSourcename( sourcename ) ) + { + errorMessage( "Raw audio data can not be fed to the " + + "MIDI channel." ); + return -1; + } + else + { + Source source = sourceMap.get( sourcename ); + if( source == null ) + { + errorMessage( "Source '" + sourcename + "' not found in " + + "method 'feedRawAudioData'" ); + } + return feedRawAudioData( source, buffer ); + } + } + +/** + * Feeds raw data through the specified source. The source must be a + * streaming source and it can not be already associated with a file or URL to + * stream from. + * @param source Streaming source to play from. + * @param buffer Byte buffer containing raw audio data to stream. + * @return Number of prior buffers that have been processed, or -1 if unable to queue the buffer (if the source was culled, for example). + */ + public int feedRawAudioData( Source source, byte[] buffer ) + { + if( source == null ) + { + errorMessage( "Source parameter null in method " + + "'feedRawAudioData'" ); + return -1; + } + if( !source.toStream ) + { + errorMessage( "Only a streaming source may be specified in " + + "method 'feedRawAudioData'" ); + return -1; + } + if( !source.rawDataStream ) + { + errorMessage( "Streaming source already associated with a " + + "file or URL in method'feedRawAudioData'" ); + return -1; + } + + if( !source.playing() || source.channel == null ) + { + Channel channel; + if( source.channel != null && ( source.channel.attachedSource == + source ) ) + channel = source.channel; + else + channel = getNextChannel( source ); + + int processed = source.feedRawAudioData( channel, buffer ); + channel.attachedSource = source; + streamThread.watch( source ); + streamThread.interrupt(); + return processed; + } + + return( source.feedRawAudioData( source.channel, buffer ) ); + } + +/** + * Looks up the specified source and plays it. + * @param sourcename Name of the source to play. + */ + public void play( String sourcename ) + { + if( sourcename == null || sourcename.equals( "" ) ) + { + errorMessage( "Sourcename not specified in method 'play'" ); + return; + } + + if( midiSourcename( sourcename ) ) + { + midiChannel.play(); + } + else + { + Source source = sourceMap.get( sourcename ); + if( source == null ) + { + errorMessage( "Source '" + sourcename + "' not found in " + + "method 'play'" ); + } + play( source ); + } + } + +/** + * Plays the specified source. + * @param source The source to play. + */ + public void play( Source source ) + { + if( source == null ) + return; + + // raw data streams will automatically play when data is sent to them, + // so no need to do anything here. + if( source.rawDataStream ) + return; + + if( !source.active() ) + return; + + if( !source.playing() ) + { + Channel channel = getNextChannel( source ); + + if( source != null && channel != null ) + { + if( source.channel != null && + source.channel.attachedSource != source ) + source.channel = null; + channel.attachedSource = source; + source.play( channel ); + if( source.toStream ) + { + streamThread.watch( source ); + streamThread.interrupt(); + } + } + } + } + +/** + * Stops the specified source. + * @param sourcename The source's name. + */ + public void stop( String sourcename ) + { + if( sourcename == null || sourcename.equals( "" ) ) + { + errorMessage( "Sourcename not specified in method 'stop'" ); + return; + } + if( midiSourcename( sourcename ) ) + { + midiChannel.stop(); + } + else + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) + mySource.stop(); + } + } + +/** + * Pauses the specified source. + * @param sourcename The source's name. + */ + public void pause( String sourcename ) + { + if( sourcename == null || sourcename.equals( "" ) ) + { + errorMessage( "Sourcename not specified in method 'stop'" ); + return; + } + if( midiSourcename( sourcename ) ) + { + midiChannel.pause(); + } + else + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) + mySource.pause(); + } + } + +/** + * Rewinds the specified source. + * @param sourcename The source's name. + */ + public void rewind( String sourcename ) + { + if( midiSourcename( sourcename ) ) + { + midiChannel.rewind(); + } + else + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) + mySource.rewind(); + } + } + +/** + * Clears all previously queued data from a stream. + * @param sourcename The source's name. + */ + public void flush( String sourcename ) + { + if( midiSourcename( sourcename ) ) + errorMessage( "You can not flush the MIDI channel" ); + else + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) + mySource.flush(); + } + } + +/** + * Culls the specified source. A culled source will not play until it has been + * activated again. + * @param sourcename The source's name. + */ + public void cull( String sourcename ) + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) + mySource.cull(); + } + +/** + * Activates a previously culled source, so it can be played again. + * @param sourcename The source's name. + */ + public void activate( String sourcename ) + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) + { + mySource.activate(); + if( mySource.toPlay ) + play( mySource ); + } + } + +/** + * Sets the overall volume to the specified value, affecting all sources. + * @param value New volume, float value ( 0.0f - 1.0f ). + */ + public void setMasterVolume( float value ) + { + SoundSystemConfig.setMasterGain( value ); + if( midiChannel != null ) + midiChannel.resetGain(); + } + +/** + * Manually sets the specified source's volume. + * @param sourcename The source's name. + * @param value A float value ( 0.0f - 1.0f ). + */ + public void setVolume( String sourcename, float value ) + { + if( midiSourcename( sourcename ) ) + { + midiChannel.setVolume( value ); + } + else + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) + { + float newVolume = value; + if( newVolume < 0.0f ) + newVolume = 0.0f; + else if( newVolume > 1.0f ) + newVolume = 1.0f; + + mySource.sourceVolume = newVolume; + mySource.positionChanged(); + } + } + } + +/** + * Returns the current volume of the specified source, or zero if the specified + * source was not found. + * @param sourcename Source to read volume from. + * @return Float value representing the source volume (0.0f - 1.0f). + */ + public float getVolume( String sourcename ) + { + if( midiSourcename( sourcename ) ) + { + return midiChannel.getVolume(); + } + else + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) + return mySource.sourceVolume; + else + return 0.0f; + } + } + +/** + * Manually sets the specified source's pitch. + * @param sourcename The source's name. + * @param value A float value ( 0.5f - 2.0f ). + */ + public void setPitch( String sourcename, float value ) + { + if( !midiSourcename( sourcename ) ) + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) + { + float newPitch = value; + if( newPitch < 0.5f ) + newPitch = 0.5f; + else if( newPitch > 2.0f ) + newPitch = 2.0f; + + mySource.setPitch( newPitch ); + mySource.positionChanged(); + } + } + } + +/** + * Returns the pitch of the specified source. + * @param sourcename The source's name. + * @return Float value representing the source pitch (0.5f - 2.0f). + */ + public float getPitch( String sourcename ) + { + if( !midiSourcename( sourcename ) ) + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) + return mySource.getPitch(); + } + return 1.0f; + } + +/** + * Moves the listener relative to the current position. + * @param x X offset. + * @param y Y offset. + * @param z Z offset. + */ + public void moveListener( float x, float y, float z ) + { + setListenerPosition( listener.position.x + x, listener.position.y + y, + listener.position.z + z ); + } + +/** + * Changes the listener's position. + * @param x Destination X coordinate. + * @param y Destination Y coordinate. + * @param z Destination Z coordinate. + */ + public void setListenerPosition( float x, float y, float z ) + { + // update listener's position + listener.setPosition( x, y, z ); + + Set keys = sourceMap.keySet(); + Iterator iter = keys.iterator(); + String sourcename; + Source source; + + // loop through and update the volume of all sources: + while( iter.hasNext() ) + { + sourcename = iter.next(); + source = sourceMap.get( sourcename ); + if( source != null ) + source.positionChanged(); + } + } + +/** + * Turn the listener 'angle' radians counterclockwise around the y-Axis, + * relative to the current angle. + * @param angle Angle in radians. + */ + public void turnListener( float angle ) + { + setListenerAngle( listener.angle + angle ); + + Set keys = sourceMap.keySet(); + Iterator iter = keys.iterator(); + String sourcename; + Source source; + + // loop through and update the volume of all sources: + while( iter.hasNext() ) + { + sourcename = iter.next(); + source = sourceMap.get( sourcename ); + if( source != null ) + source.positionChanged(); + } + } + +/** + * Changes the listeners orientation to the specified 'angle' radians + * counterclockwise around the y-Axis. + * @param angle Angle in radians. + */ + public void setListenerAngle( float angle ) + { + listener.setAngle( angle ); + + Set keys = sourceMap.keySet(); + Iterator iter = keys.iterator(); + String sourcename; + Source source; + + // loop through and update the volume of all sources: + while( iter.hasNext() ) + { + sourcename = iter.next(); + source = sourceMap.get( sourcename ); + if( source != null ) + source.positionChanged(); + } + } + +/** + * Changes the listeners orientation using the specified coordinates. + * @param lookX X element of the look-at direction. + * @param lookY Y element of the look-at direction. + * @param lookZ Z element of the look-at direction. + * @param upX X element of the up direction. + * @param upY Y element of the up direction. + * @param upZ Z element of the up direction. + */ + public void setListenerOrientation( float lookX, float lookY, float lookZ, + float upX, float upY, float upZ ) + { + listener.setOrientation( lookX, lookY, lookZ, upX, upY, upZ ); + + Set keys = sourceMap.keySet(); + Iterator iter = keys.iterator(); + String sourcename; + Source source; + + // loop through and update the volume of all sources: + while( iter.hasNext() ) + { + sourcename = iter.next(); + source = sourceMap.get( sourcename ); + if( source != null ) + source.positionChanged(); + } + } + +/** + * Changes the listeners position and orientation using the specified listener + * data. + * @param l Listener data to use. + */ + public void setListenerData( ListenerData l ) + { + listener.setData( l ); + } + +/** + * Creates sources based on the source map provided. + * @param srcMap Sources to copy. + */ + public void copySources( HashMap srcMap ) + { + if( srcMap == null ) + return; + Set keys = srcMap.keySet(); + Iterator iter = keys.iterator(); + String sourcename; + Source srcData; + + // remove any existing sources before starting: + sourceMap.clear(); + + // loop through and copy all the sources: + while( iter.hasNext() ) + { + sourcename = iter.next(); + srcData = srcMap.get( sourcename ); + if( srcData != null ) + { + loadSound( srcData.filenameURL ); + sourceMap.put( sourcename, new Source( srcData, null ) ); + } + } + } + +/** + * Stops and deletes the specified source. + * @param sourcename The source's name. + */ + public void removeSource( String sourcename ) + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) { + // if this is a streaming source just mark it removed - https://github.com/MinecraftForge/MinecraftForge/pull/4765 + if ( mySource.toStream ) + mySource.removed = true; + else + mySource.cleanup(); // end the source, free memory + } + sourceMap.remove( sourcename ); + } + +/** + * Searches for and removes all temporary sources that have finished playing. + */ + public void removeTemporarySources() + { + Set keys = sourceMap.keySet(); + Iterator iter = keys.iterator(); + String sourcename; + Source srcData; + + // loop through and cleanup all the sources: + while( iter.hasNext() ) + { + sourcename = iter.next(); + srcData = sourceMap.get( sourcename ); + if( (srcData != null) && (srcData.temporary) + && (!srcData.playing()) ) + { + srcData.cleanup(); // end the source, free memory + iter.remove(); + } + } + } + +/* ########################################################################## */ +/* END OVERRIDE METHODS */ +/* ########################################################################## */ + +/** + * Returns a handle to the next available channel. If the specified + * source is a normal source, a normal channel is returned, and if it is a + * streaming source, then a streaming channel is returned. If all channels of + * the required type are currently playing, then the next channel playing a + * non-priority source is returned. If no channels are available (i.e. they + * are all playing priority sources) then getNextChannel returns null. + * @param source Source to find a channel for. + * @return The next available channel, or null. + */ + private Channel getNextChannel( Source source ) + { + if( source == null ) + return null; + + String sourcename = source.sourcename; + if( sourcename == null ) + return null; + + int x; + int channels; + int nextChannel; + List channelList; + String[] sourceNames; + String name; + + if( source.toStream ) + { + nextChannel = nextStreamingChannel; + channelList = streamingChannels; + sourceNames = streamingChannelSourceNames; + } + else + { + nextChannel = nextNormalChannel; + channelList = normalChannels; + sourceNames = normalChannelSourceNames; + } + + channels = channelList.size(); + + // Check if this source is already on a channel: + for( x = 0; x < channels; x++ ) + { + if( sourcename.equals( sourceNames[x] ) ) + return channelList.get( x ); + } + + int n = nextChannel; + Source src; + // Play on the next new or non-playing channel: + for( x = 0; x < channels; x++ ) + { + name = sourceNames[n]; + if( name == null ) + src = null; + else + src = sourceMap.get( name ); + + if( src == null || !src.playing() ) + { + if( source.toStream ) + { + nextStreamingChannel = n + 1; + if( nextStreamingChannel >= channels ) + nextStreamingChannel = 0; + } + else + { + nextNormalChannel = n + 1; + if( nextNormalChannel >= channels ) + nextNormalChannel = 0; + } + sourceNames[n] = sourcename; + return channelList.get( n ); + } + n++; + if( n >= channels ) + n = 0; + } + + n = nextChannel; + // Play on the next non-priority channel: + for( x = 0; x < channels; x++ ) + { + name = sourceNames[n]; + if( name == null ) + src = null; + else + src = sourceMap.get( name ); + + if( src == null || !src.playing() || !src.priority ) + { + if( source.toStream ) + { + nextStreamingChannel = n + 1; + if( nextStreamingChannel >= channels ) + nextStreamingChannel = 0; + } + else + { + nextNormalChannel = n + 1; + if( nextNormalChannel >= channels ) + nextNormalChannel = 0; + } + sourceNames[n] = sourcename; + return channelList.get( n ); + } + n++; + if( n >= channels ) + n = 0; + } + + return null; + } + +/** + * Plays all sources whose 'toPlay' varriable is true but are not currently + * playing (such as sources which were culled while looping and then + * reactivated). + */ + public void replaySources() + { + Set keys = sourceMap.keySet(); + Iterator iter = keys.iterator(); + String sourcename; + Source source; + + // loop through and cleanup all the sources: + while( iter.hasNext() ) + { + sourcename = iter.next(); + source = sourceMap.get( sourcename ); + if( source != null ) + { + if( source.toPlay && !source.playing() ) + { + play( sourcename ); + source.toPlay = false; + } + } + } + } + +/** + * If the specified source is a streaming source or MIDI source, this method + * queues up the next sound to play when the previous playback ends. This + * method has no effect on non-streaming sources. + * @param sourcename Source identifier. + * @param filenameURL Filename/URL of the sound file to play next. + */ + public void queueSound( String sourcename, FilenameURL filenameURL ) + { + if( midiSourcename( sourcename ) ) + { + midiChannel.queueSound( filenameURL ); + } + else + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) + mySource.queueSound( filenameURL ); + } + } + +/** + * Removes the first occurrence of the specified filename from the specified + * source's list of sounds to play when previous playback ends. This method + * has no effect on non-streaming sources. + * @param sourcename Source identifier. + * @param filename Filename/identifier of the sound file to remove from the queue. + */ + public void dequeueSound( String sourcename, String filename ) + { + if( midiSourcename( sourcename ) ) + { + midiChannel.dequeueSound( filename ); + } + else + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) + mySource.dequeueSound( filename ); + } + } + +/** + * Fades out the volume of whatever the specified source is currently playing, + * then begins playing the specified file at the source's previously + * assigned volume level. If the filenameURL parameter is null or empty, the + * specified source will simply fade out and stop. The miliseconds parameter + * must be non-negative or zero. This method will remove anything that is + * currently in the specified source's list of queued sounds that would have + * played next when the current sound finished playing. This method may only + * be used for streaming and MIDI sources. + * @param sourcename Name of the source to fade out. + * @param filenameURL Filename/URL of the sound file to play next, or null for none. + * @param milis Number of miliseconds the fadeout should take. + */ + public void fadeOut( String sourcename, FilenameURL filenameURL, + long milis ) + { + if( midiSourcename( sourcename ) ) + { + midiChannel.fadeOut( filenameURL, milis ); + } + else + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) + mySource.fadeOut( filenameURL, milis ); + } + } + +/** + * Fades out the volume of whatever the specified source is currently playing, + * then fades the volume back in playing the specified file. Final volume + * after fade-in completes will be equal to the source's previously assigned + * volume level. The filenameURL parameter may not be null or empty. The + * miliseconds parameters must be non-negative or zero. This method will + * remove anything that is currently in the specified source's list of queued + * sounds that would have played next when the current sound finished playing. + * This method may only be used for streaming and MIDI sources. + * @param sourcename Name of the source to fade out/in. + * @param filenameURL Filename/URL of the sound file to play next, or null for none. + * @param milisOut Number of miliseconds the fadeout should take. + * @param milisIn Number of miliseconds the fadein should take. + */ + public void fadeOutIn( String sourcename, FilenameURL filenameURL, + long milisOut, long milisIn ) + { + if( midiSourcename( sourcename ) ) + { + midiChannel.fadeOutIn( filenameURL, milisOut, milisIn ); + } + else + { + Source mySource = sourceMap.get( sourcename ); + if( mySource != null ) + mySource.fadeOutIn( filenameURL, milisOut, milisIn ); + } + } + +/** + * Makes sure the current volume levels of streaming sources and MIDI are + * correct. This method is designed to help reduce the "jerky" fading behavior + * that happens when using some library and codec pluggins (such as + * LibraryJavaSound and CodecJOrbis). This method has no effect on normal + * "non-streaming" sources. It would normally be called somewhere in the main + * "game loop". IMPORTANT: To optimize frame-rates, do not call this method + * for every frame. It is better to just call this method at some acceptable + * "granularity" (play around with different granularities to find what sounds + * acceptable for a particular situation). + */ + public void checkFadeVolumes() + { + if( midiChannel != null ) + midiChannel.resetGain(); + Channel c; + Source s; + for( int x = 0; x < streamingChannels.size(); x++ ) + { + c = streamingChannels.get( x ); + if( c != null ) + { + s = c.attachedSource; + if( s != null ) + s.checkFadeOut(); + } + } + c = null; + s = null; + } + +/** + * Loads the specified MIDI file, and saves the source information about it. + * @param toLoop Midi file should loop or play once. + * @param sourcename Source identifier. + * @param filenameURL Filename/URL of the MIDI file to load. + */ + public void loadMidi( boolean toLoop, String sourcename, + FilenameURL filenameURL ) + { + if( filenameURL == null ) + { + errorMessage( "Filename/URL not specified in method 'loadMidi'." ); + return; + } + + if( !filenameURL.getFilename().matches( + SoundSystemConfig.EXTENSION_MIDI ) ) + { + errorMessage( "Filename/identifier doesn't end in '.mid' or" + + "'.midi' in method loadMidi." ); + return; + } + + if( midiChannel == null ) + { + midiChannel = new MidiChannel( toLoop, sourcename, filenameURL ); + } + else + { + midiChannel.switchSource( toLoop, sourcename, filenameURL ); + } + } + +/** + * Unloads the current Midi file. + */ + public void unloadMidi() + { + if( midiChannel != null ) + midiChannel.cleanup(); + midiChannel = null; + } + +/** + * Checks if the sourcename matches the midi source. + * @param sourcename Source identifier. + * @return True if sourcename and midi sourcename match. + */ + public boolean midiSourcename( String sourcename ) + { + if( midiChannel == null || sourcename == null ) + return false; + + if( midiChannel.getSourcename() == null || sourcename.equals( "" ) ) + return false; + + if( sourcename.equals( midiChannel.getSourcename() ) ) + return true; + + return false; + } + +/** + * + * Returns the Source object identified by the specified name. + * @param sourcename The source's name. + * @return The source, or null if not found. + */ + public Source getSource( String sourcename ) + { + return sourceMap.get( sourcename ); + } + +/** + * + * Returns a handle to the MIDI channel, or null if one does not exist. + * @return The MIDI channel. + */ + public MidiChannel getMidiChannel() + { + return midiChannel; + } + +/** + * + * Specifies the MIDI channel to use. + * @param c New MIDI channel. + */ + public void setMidiChannel( MidiChannel c ) + { + if( midiChannel != null && midiChannel != c ) + midiChannel.cleanup(); + + midiChannel = c; + } + +/** + * Tells all the sources that the listener has moved. + */ + public void listenerMoved() + { + Set keys = sourceMap.keySet(); + Iterator iter = keys.iterator(); + String sourcename; + Source srcData; + + // loop through and copy all the sources: + while( iter.hasNext() ) + { + sourcename = iter.next(); + srcData = sourceMap.get( sourcename ); + if( srcData != null ) + { + srcData.listenerMoved(); + } + } + } + +/** + * Returns the sources map. + * @return Map of all sources. + */ + public HashMap getSources() + { + return sourceMap; + } + +/** + * Returns information about the listener. + * @return A ListenerData object. + */ + public ListenerData getListenerData() + { + return listener; + } + +/** + * Indicates whether or not this library requires some codecs to reverse-order + * the audio data they generate. + * @return True if audio data should be reverse-ordered. + */ + public boolean reverseByteOrder() + { + return reverseByteOrder; + } +/** + * Returns the short title of this library type. + * @return A short title. + */ + public static String getTitle() + { + return "No Sound"; + } + +/** + * Returns a longer description of this library type. + * @return A longer description. + */ + public static String getDescription() + { + return "Silent Mode"; + } + +/** + * Returns the name of the class. + * @return "Library" + library title. + */ + public String getClassName() + { + return "Library"; + } + +/** + * Prints a message. + * @param message Message to print. + */ + protected void message( String message ) + { + logger.message( message, 0 ); + } + +/** + * Prints an important message. + * @param message Message to print. + */ + protected void importantMessage( String message ) + { + logger.importantMessage( message, 0 ); + } + +/** + * Prints the specified message if error is true. + * @param error True or False. + * @param message Message to print if error is true. + * @return True if error is true. + */ + protected boolean errorCheck( boolean error, String message ) + { + return logger.errorCheck( error, getClassName(), message, 0 ); + } + +/** + * Prints an error message. + * @param message Message to print. + */ + protected void errorMessage( String message ) + { + logger.errorMessage( getClassName(), message, 0 ); + } + +/** + * Prints an exception's error message followed by the stack trace. + * @param e Exception containing the information to print. + */ + protected void printStackTrace( Exception e ) + { + logger.printStackTrace( e, 1 ); + } +} diff --git a/src/lwjgl/java/paulscode/sound/ListenerData.java b/src/lwjgl/java/paulscode/sound/ListenerData.java new file mode 100644 index 0000000..af24b3c --- /dev/null +++ b/src/lwjgl/java/paulscode/sound/ListenerData.java @@ -0,0 +1,282 @@ +package paulscode.sound; + +/** + * The listenerData class is used to store information about the + * listener's position and orientation. A ListenerData object can be obtained + * using SoundSystem's getListenerData() method. See + * {@link paulscode.sound.Vector3D Vector3D} for more information about 3D + * coordinates and vectors. + *

+ * SoundSystem License:

+ * You are free to use this library for any purpose, commercial or otherwise. + * You may modify this library or source code, and distribute it any way you + * like, provided the following conditions are met: + *
+ * 1) You may not falsely claim to be the author of this library or any + * unmodified portion of it. + *
+ * 2) You may not copyright this library or a modified version of it and then + * sue me for copyright infringement. + *
+ * 3) If you modify the source code, you must clearly document the changes + * made before redistributing the modified source code, so other users know + * it is not the original code. + *
+ * 4) You are not required to give me credit for this library in any derived + * work, but if you do, you must also mention my website: + * http://www.paulscode.com + *
+ * 5) I the author will not be responsible for any damages (physical, + * financial, or otherwise) caused by the use if this library or any part + * of it. + *
+ * 6) I the author do not guarantee, warrant, or make any representations, + * either expressed or implied, regarding the use of this library or any + * part of it. + *

+ * Author: Paul Lamb + *
+ * http://www.paulscode.com + *
+ */ +public class ListenerData +{ +/** + * Listener's position in 3D space + */ + public Vector3D position; +/** + * A normalized vector indicating the direction the listener is facing + */ + public Vector3D lookAt; +/** + * A normalized vector indicating the up direction + */ + public Vector3D up; +/** + * Listener's velocity in world-space + */ + public Vector3D velocity; + +/** + * Used for easy rotation along the x/z plane (for use in a first-person + * shooter type of application). + */ + public float angle = 0.0f; + +/** + * Constructor: Set this listener data to the origin facing along the z-axis + */ + public ListenerData() + { + position = new Vector3D( 0.0f, 0.0f, 0.0f ); + lookAt = new Vector3D( 0.0f, 0.0f, -1.0f ); + up = new Vector3D( 0.0f, 1.0f, 0.0f ); + velocity = new Vector3D( 0.0f, 0.0f, 0.0f ); + angle = 0.0f; + } + +/** + * Constructor: Set this listener data to the specified values for position and + * orientation. + * @param pX Listener's X coordinate. + * @param pY Listener's Y coordinate. + * @param pZ Listener's Z coordinate. + * @param lX X element of the look-at direction. + * @param lY Y element of the look-at direction. + * @param lZ Z element of the look-at direction. + * @param uX X element of the up direction. + * @param uY Y element of the up direction. + * @param uZ Z element of the up direction. + * @param a Angle in radians that the listener is turned counterclockwise around the y-axis. + */ + public ListenerData( float pX, float pY, float pZ, float lX, float lY, + float lZ, float uX, float uY, float uZ, float a ) + { + position = new Vector3D( pX, pY, pZ ); + lookAt = new Vector3D( lX, lY, lZ ); + up = new Vector3D( uX, uY, uZ ); + velocity = new Vector3D( 0.0f, 0.0f, 0.0f ); + angle = a; + } + +/** + * Constructor: Set this listener data to the specified values for position and + * orientation. + * @param p Position of the listener in 3D space. + * @param l Normalized vector indicating the direction which the listener is facing. + * @param u Normalized vector indicating the up direction. + * @param a Angle in radians that the listener is turned counterclockwise around the y-axis. + */ + public ListenerData( Vector3D p, Vector3D l, Vector3D u, float a ) + { + position = p.clone(); + lookAt = l.clone(); + up = u.clone(); + velocity = new Vector3D( 0.0f, 0.0f, 0.0f ); + angle = a; + } + +/** + * Change this listener data using the specified coordinates for position and + * orientation. + * @param pX Listener's X coordinate. + * @param pY Listener's Y coordinate. + * @param pZ Listener's Z coordinate. + * @param lX X element of the look-at direction. + * @param lY Y element of the look-at direction. + * @param lZ Z element of the look-at direction. + * @param uX X element of the up direction. + * @param uY Y element of the up direction. + * @param uZ Z element of the up direction. + * @param a Angle in radians that the listener is turned counterclockwise around the y-axis. + */ + public void setData( float pX, float pY, float pZ, float lX, float lY, + float lZ, float uX, float uY, float uZ, float a ) + { + position.x = pX; + position.y = pY; + position.z = pZ; + lookAt.x = lX; + lookAt.y = lY; + lookAt.z = lZ; + up.x = uX; + up.y = uY; + up.z = uZ; + angle = a; + } + +/** + * Change this listener data using the specified 3D vectors for position and + * orientation. + * @param p Position of the listener in 3D space. + * @param l Normalized vector indicating the direction which the listener is facing. + * @param u Normalized vector indicating the up direction. + * @param a Angle in radians that the listener is turned counterclockwise around the y-axis. + */ + public void setData( Vector3D p, Vector3D l, Vector3D u, float a ) + { + position.x = p.x; + position.y = p.y; + position.z = p.z; + lookAt.x = l.x; + lookAt.y = l.y; + lookAt.z = l.z; + up.x = u.x; + up.y = u.y; + up.z = u.z; + angle = a; + } + +/** + * Change this listener data to match the specified listener data. + * @param l Listener data to use. + */ + public void setData( ListenerData l ) + { + position.x = l.position.x; + position.y = l.position.y; + position.z = l.position.z; + lookAt.x = l.lookAt.x; + lookAt.y = l.lookAt.y; + lookAt.z = l.lookAt.z; + up.x = l.up.x; + up.y = l.up.y; + up.z = l.up.z; + angle = l.angle; + } + +/** + * Change this listener's position using the specified coordinates. + * @param x Listener's X coordinate. + * @param y Listener's Y coordinate. + * @param z Listener's Z coordinate. + */ + public void setPosition( float x, float y, float z ) + { + position.x = x; + position.y = y; + position.z = z; + } + +/** + * Change this listener's position using the specified vector. + * @param p New position. + */ + public void setPosition( Vector3D p ) + { + position.x = p.x; + position.y = p.y; + position.z = p.z; + } + +/** + * Changes the listeners orientation using the specified coordinates. + * @param lX X element of the look-at direction. + * @param lY Y element of the look-at direction. + * @param lZ Z element of the look-at direction. + * @param uX X element of the up direction. + * @param uY Y element of the up direction. + * @param uZ Z element of the up direction. + */ + public void setOrientation( float lX, float lY, float lZ, + float uX, float uY, float uZ ) + { + lookAt.x = lX; + lookAt.y = lY; + lookAt.z = lZ; + up.x = uX; + up.y = uY; + up.z = uZ; + } + +/** + * Changes the listeners orientation using the specified vectors. + * @param l Normalized vector representing the look-at direction. + * @param u Normalized vector representing the up direction. + */ + public void setOrientation( Vector3D l, Vector3D u ) + { + lookAt.x = l.x; + lookAt.y = l.y; + lookAt.z = l.z; + up.x = u.x; + up.y = u.y; + up.z = u.z; + } + +/** + * Change this listener's velocity in world-space. + * @param v New velocity. + */ + public void setVelocity( Vector3D v ) + { + velocity.x = v.x; + velocity.y = v.y; + velocity.z = v.z; + } + +/** + * Change this listener's velocity in world-space. + * @param x New velocity along world x-axis. + * @param y New velocity along world y-axis. + * @param z New velocity along world z-axis. + */ + public void setVelocity( float x, float y, float z ) + { + velocity.x = x; + velocity.y = y; + velocity.z = z; + } + +/** + * Sets the listener's angle counterclockwise around the y-axis. + * @param a Angle in radians. + */ + public void setAngle( float a ) + { + angle = a; + lookAt.x = -1.0f * (float) Math.sin( angle ); + lookAt.z = -1.0f * (float) Math.cos( angle ); + } +} diff --git a/src/lwjgl/java/paulscode/sound/MidiChannel.java b/src/lwjgl/java/paulscode/sound/MidiChannel.java new file mode 100644 index 0000000..a607421 --- /dev/null +++ b/src/lwjgl/java/paulscode/sound/MidiChannel.java @@ -0,0 +1,1603 @@ +package paulscode.sound; + +import java.io.IOException; +import java.net.URL; +import java.util.LinkedList; +import java.util.ListIterator; + +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MetaEventListener; +import javax.sound.midi.MetaMessage; +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Receiver; +import javax.sound.midi.Sequence; +import javax.sound.midi.Sequencer; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.Synthesizer; + +import net.lax1dude.eaglercraft.EaglerAdapter; + +/** + * The MidiChannel class provides an interface for playing MIDI files, using + * the JavaSound API. For more information about the JavaSound API, visit + * http://java.sun.com/products/java-media/sound/ + *

+ * SoundSystem License:

+ * You are free to use this library for any purpose, commercial or otherwise. + * You may modify this library or source code, and distribute it any way you + * like, provided the following conditions are met: + *
+ * 1) You may not falsely claim to be the author of this library or any + * unmodified portion of it. + *
+ * 2) You may not copyright this library or a modified version of it and then + * sue me for copyright infringement. + *
+ * 3) If you modify the source code, you must clearly document the changes + * made before redistributing the modified source code, so other users know + * it is not the original code. + *
+ * 4) You are not required to give me credit for this library in any derived + * work, but if you do, you must also mention my website: + * http://www.paulscode.com + *
+ * 5) I the author will not be responsible for any damages (physical, + * financial, or otherwise) caused by the use if this library or any part + * of it. + *
+ * 6) I the author do not guarantee, warrant, or make any representations, + * either expressed or implied, regarding the use of this library or any + * part of it. + *

+ * Author: Paul Lamb + *
+ * http://www.paulscode.com + *
+ */ +public class MidiChannel implements MetaEventListener +{ +/** + * Processes status messages, warnings, and error messages. + */ + private SoundSystemLogger logger; + +/** + * Filename/URL to the file: + */ + private FilenameURL filenameURL; + +/** + * Unique source identifier for this MIDI source. + */ + private String sourcename; + +/** + * Global identifier for the MIDI "change volume" event. + */ + private static final int CHANGE_VOLUME = 7; + +/** + * Global identifier for the MIDI "end of track" event. + */ + private static final int END_OF_TRACK = 47; + +/** + * Used to return a current value from one of the synchronized + * boolean-interface methods. + */ + private static final boolean GET = false; + +/** + * Used to set the value in one of the synchronized boolean-interface methods. + */ + private static final boolean SET = true; + +/** + * Used when a parameter for one of the synchronized boolean-interface methods + * is not aplicable. + */ + private static final boolean XXX = false; + +/** + * Runs the assigned sequence, passing information on to the synthesizer for + * playback. + */ + private Sequencer sequencer = null; + +/** + * Converts MIDI events into audio. + */ + private Synthesizer synthesizer = null; + +/** + * Converts MIDI events into audio if there is no default Synthesizer. + */ + private MidiDevice synthDevice = null; + +/** + * Sequence of MIDI events defining sound. + */ + private Sequence sequence = null; + +/** + * Should playback loop or play only once. + */ + private boolean toLoop = true; + +/** + * Playback volume, float value (0.0f - 1.0f). + */ + private float gain = 1.0f; + +/** + * True while sequencer is busy being set up. + */ + private boolean loading = true; + +/** + * The list of MIDI files to play when the current sequence finishes. + */ + private LinkedList sequenceQueue = null; + +/** + * Ensures that only one thread accesses the sequenceQueue at a time. + */ + private final Object sequenceQueueLock = new Object(); + +/** + * Specifies the gain factor used for the fade-out effect, or -1 when + * playback is not currently fading out. + */ + protected float fadeOutGain = -1.0f; + +/** + * Specifies the gain factor used for the fade-in effect, or 1 when + * playback is not currently fading in. + */ + protected float fadeInGain = 1.0f; + +/** + * Specifies the number of miliseconds it should take to fade out. + */ + protected long fadeOutMilis = 0; + +/** + * Specifies the number of miliseconds it should take to fade in. + */ + protected long fadeInMilis = 0; + +/** + * System time in miliseconds when the last fade in/out volume check occurred. + */ + protected long lastFadeCheck = 0; + +/** + * Used for fading in and out effects. + */ + private FadeThread fadeThread = null; + +/** + * Constructor: Defines the basic source information. + * @param toLoop Should playback loop or play only once? + * @param sourcename Unique identifier for this source. + * @param filename Name of the MIDI file to play. + */ + public MidiChannel( boolean toLoop, String sourcename, String filename ) + { + // let others know we are busy loading: + loading( SET, true ); + + // grab a handle to the message logger: + logger = SoundSystemConfig.getLogger(); + + // save information about the source: + filenameURL( SET, new FilenameURL( filename ) ); + sourcename( SET, sourcename ); + setLooping( toLoop ); + + // initialize the MIDI channel: + init(); + + // finished loading: + loading( SET, false ); + } + +/** + * Constructor: Defines the basic source information. The fourth parameter, + * 'identifier' should look like a filename, and it must have the correct + * extension (.mid or .midi). + * @param toLoop Should playback loop or play only once? + * @param sourcename Unique identifier for this source. + * @param midiFile URL to the MIDI file to play. + * @param identifier Filename/identifier for the MIDI file. + */ + public MidiChannel( boolean toLoop, String sourcename, URL midiFile, + String identifier ) + { + // let others know we are busy loading + loading( SET, true ); + + // grab a handle to the message logger: + logger = SoundSystemConfig.getLogger(); + + // save information about the source: + filenameURL( SET, new FilenameURL( midiFile, identifier ) ); + sourcename( SET, sourcename ); + setLooping( toLoop ); + + // initialize the MIDI channel: + init(); + + // finished loading: + loading( SET, false ); + } + +/** + * Constructor: Defines the basic source information. + * @param toLoop Should playback loop or play only once? + * @param sourcename Unique identifier for this source. + * @param midiFilenameURL Filename/URL to the MIDI file to play. + */ + public MidiChannel( boolean toLoop, String sourcename, + FilenameURL midiFilenameURL ) + { + // let others know we are busy loading + loading( SET, true ); + + // grab a handle to the message logger: + logger = SoundSystemConfig.getLogger(); + + // save information about the source: + filenameURL( SET, midiFilenameURL ); + sourcename( SET, sourcename ); + setLooping( toLoop ); + + // initialize the MIDI channel: + init(); + + // finished loading: + loading( SET, false ); + } + +/** + * Initializes the sequencer, loads the sequence, and sets up the synthesizer. + */ + private void init() + { + // Load a sequencer: + getSequencer(); + + // Load the sequence to play: + setSequence( filenameURL( GET, null).getURL() ); + + // Load a synthesizer to play the sequence on: + getSynthesizer(); + + // Ensure the initial volume is correct: + // (TODO: doesn't always work??) + resetGain(); + } + +/** + * Shuts the channel down and removes references to all instantiated objects. + */ + public void cleanup() + { + loading( SET, true ); + setLooping( true ); + + if( sequencer != null ) + { + try + { + sequencer.stop(); + sequencer.close(); + sequencer.removeMetaEventListener( this ); + } + catch( Exception e ) + {} + } + + logger = null; + sequencer = null; + synthesizer = null; + sequence = null; + + synchronized( sequenceQueueLock ) + { + if( sequenceQueue != null ) + sequenceQueue.clear(); + sequenceQueue = null; + } + + // End the fade effects thread if it exists: + if( fadeThread != null ) + { + boolean killException = false; + try + { + fadeThread.kill(); // end the fade effects thread. + fadeThread.interrupt(); // wake the thread up so it can end. + } + catch( Exception e ) + { + killException = true; + } + + if( !killException ) + { + // wait up to 5 seconds for fade effects thread to end: + for( int i = 0; i < 50; i++ ) + { + if( !fadeThread.alive() ) + break; + try{Thread.sleep( 100 );}catch(InterruptedException e){} + } + } + + // Let user know if there was a problem ending the fade thread + if( killException || fadeThread.alive() ) + { + errorMessage( "MIDI fade effects thread did not die!" ); + message( "Ignoring errors... continuing clean-up." ); + } + } + + fadeThread = null; + + loading( SET, false ); + } + +/** + * Queues up the next MIDI sequence to play when the previous sequence ends. + * @param filenameURL MIDI sequence to play next. + */ + public void queueSound( FilenameURL filenameURL ) + { + if( filenameURL == null ) + { + errorMessage( "Filename/URL not specified in method 'queueSound'" ); + return; + } + + synchronized( sequenceQueueLock ) + { + if( sequenceQueue == null ) + sequenceQueue = new LinkedList(); + sequenceQueue.add( filenameURL ); + } + } + +/** + * Removes the first occurrence of the specified filename/identifier from the + * list of MIDI sequences to play when the previous sequence ends. + * @param filename Filename or identifier of a MIDI sequence to remove from the + * queue. + */ + public void dequeueSound( String filename ) + { + if( filename == null || filename.equals( "" ) ) + { + errorMessage( "Filename not specified in method 'dequeueSound'" ); + return; + } + + synchronized( sequenceQueueLock ) + { + if( sequenceQueue != null ) + { + ListIterator i = sequenceQueue.listIterator(); + while( i.hasNext() ) + { + if( i.next().getFilename().equals( filename ) ) + { + i.remove(); + break; + } + } + } + } + } + +/** + * Fades out the volume of whatever sequence is currently playing, then + * begins playing the specified MIDI file at the previously assigned + * volume level. If the filenameURL parameter is null or empty, playback will + * simply fade out and stop. The miliseconds parameter must be non-negative or + * zero. This method will remove anything that is currently in the list of + * queued MIDI sequences that would have played next when current playback + * finished. + * @param filenameURL MIDI file to play next, or null for none. + * @param milis Number of miliseconds the fadeout should take. + */ + public void fadeOut( FilenameURL filenameURL, long milis ) + { + if( milis < 0 ) + { + errorMessage( "Miliseconds may not be negative in method " + + "'fadeOut'." ); + return; + } + + fadeOutMilis = milis; + fadeInMilis = 0; + fadeOutGain = 1.0f; + lastFadeCheck = EaglerAdapter.steadyTimeMillis(); + + synchronized( sequenceQueueLock ) + { + if( sequenceQueue != null ) + sequenceQueue.clear(); + + if( filenameURL != null ) + { + if( sequenceQueue == null ) + sequenceQueue = new LinkedList(); + sequenceQueue.add( filenameURL ); + } + } + if( fadeThread == null ) + { + fadeThread = new FadeThread(); + fadeThread.start(); + } + fadeThread.interrupt(); + } + +/** + * Fades out the volume of whatever sequence is currently playing, then + * fades the volume back in playing the specified MIDI file. Final volume + * after fade-in completes will be equal to the previously assigned volume + * level. The filenameURL parameter may not be null or empty. The miliseconds + * parameters must be non-negative or zero. This method will remove anything + * that is currently in the list of queued MIDI sequences that would have + * played next when current playback finished. + * @param filenameURL MIDI file to play next, or null for none. + * @param milisOut Number of miliseconds the fadeout should take. + * @param milisIn Number of miliseconds the fadein should take. + */ + public void fadeOutIn( FilenameURL filenameURL, long milisOut, + long milisIn ) + { + if( filenameURL == null ) + { + errorMessage( "Filename/URL not specified in method 'fadeOutIn'." ); + return; + } + if( milisOut < 0 || milisIn < 0 ) + { + errorMessage( "Miliseconds may not be negative in method " + + "'fadeOutIn'." ); + return; + } + + fadeOutMilis = milisOut; + fadeInMilis = milisIn; + fadeOutGain = 1.0f; + lastFadeCheck = EaglerAdapter.steadyTimeMillis(); + + synchronized( sequenceQueueLock ) + { + if( sequenceQueue == null ) + sequenceQueue = new LinkedList(); + sequenceQueue.clear(); + sequenceQueue.add( filenameURL ); + } + if( fadeThread == null ) + { + fadeThread = new FadeThread(); + fadeThread.start(); + } + fadeThread.interrupt(); + } + +/** + * Resets this source's volume if it is fading out or in. Returns true if this + * source is currently in the process of fading out. When fade-out completes, + * this method transitions the source to the next sound in the sound sequence + * queue if there is one. This method has no effect on non-streaming sources. + * @return True if this source is in the process of fading out. + */ + private synchronized boolean checkFadeOut() + { + if( fadeOutGain == -1.0f && fadeInGain == 1.0f ) + return false; + + long currentTime = EaglerAdapter.steadyTimeMillis(); + long milisPast = currentTime - lastFadeCheck; + lastFadeCheck = currentTime; + + if( fadeOutGain >= 0.0f ) + { + if( fadeOutMilis == 0 ) + { + fadeOutGain = 0.0f; + fadeInGain = 0.0f; + if( !incrementSequence() ) + stop(); + rewind(); + resetGain(); + return false; + } + else + { + float fadeOutReduction = ((float)milisPast) / ((float)fadeOutMilis); + + fadeOutGain -= fadeOutReduction; + if( fadeOutGain <= 0.0f ) + { + fadeOutGain = -1.0f; + fadeInGain = 0.0f; + if( !incrementSequence() ) + stop(); + rewind(); + resetGain(); + return false; + } + } + resetGain(); + return true; + } + + if( fadeInGain < 1.0f ) + { + fadeOutGain = -1.0f; + if( fadeInMilis == 0 ) + { + fadeOutGain = -1.0f; + fadeInGain = 1.0f; + } + else + { + float fadeInIncrease = ((float)milisPast) / ((float)fadeInMilis); + fadeInGain += fadeInIncrease; + if( fadeInGain >= 1.0f ) + { + fadeOutGain = -1.0f; + fadeInGain = 1.0f; + } + } + resetGain(); + } + + return false; + } + +/** + * Removes the next sequence from the queue and assigns it to the sequencer. + * @return True if there was something in the queue. + */ + private boolean incrementSequence() + { + synchronized( sequenceQueueLock ) + { + // Is there a queue, and if so, is there anything in it: + if( sequenceQueue != null && sequenceQueue.size() > 0 ) + { + // grab the next filename/URL from the queue: + filenameURL( SET, sequenceQueue.remove( 0 ) ); + + // Let everyone know we are busy loading: + loading( SET, true ); + + // Check if we have a sequencer: + if( sequencer == null ) + { + // nope, try and get one now: + getSequencer(); + } + else + { + // We have a sequencer. Stop it now: + sequencer.stop(); + // rewind to the beginning: + sequencer.setMicrosecondPosition( 0 ); + // Stop listening for a moment: + sequencer.removeMetaEventListener( this ); + // wait a bit for the sequencer to shut down and rewind: + try{ Thread.sleep( 100 ); }catch( InterruptedException e ){} + } + // We need to have a sequencer at this point: + if( sequencer == null ) + { + errorMessage( "Unable to set the sequence in method " + + "'incrementSequence', because there wasn't " + + "a sequencer to use." ); + + // Finished loading: + loading( SET, false ); + + // failure: + return false; + } + // set the new sequence to be played: + setSequence( filenameURL( GET, null ).getURL() ); + // start playing again: + sequencer.start(); + // make sure we play at the correct volume: + // (TODO: This doesn't always work??) + resetGain(); + // start listening for end of track event again: + sequencer.addMetaEventListener( this ); + + // Finished loading: + loading( SET, false ); + + // We successfully moved to the next sequence: + return true; + } + } + + // Nothing left to load + return false; + } + +/** + * Plays the MIDI file from the beginning, or from where it left off if it was + * paused. + */ + public void play() + { + if( !loading() ) + { + // Make sure there is a sequencer: + if( sequencer == null ) + return; + + try + { + // start playing: + sequencer.start(); + // event will be sent when end of track is reached: + sequencer.addMetaEventListener( this ); + } + catch( Exception e ) + { + errorMessage( "Exception in method 'play'" ); + printStackTrace( e ); + SoundSystemException sse = new SoundSystemException( + e.getMessage() ); + SoundSystem.setException( sse ); + } + } + } + +/** + * Stops playback and rewinds to the beginning. + */ + public void stop() + { + if( !loading() ) + { + // Make sure there is a sequencer: + if( sequencer == null ) + return; + + try + { + // stop playback: + sequencer.stop(); + // rewind to the beginning: + sequencer.setMicrosecondPosition( 0 ); + // No need to listen any more: + sequencer.removeMetaEventListener( this ); + } + catch( Exception e ) + { + errorMessage( "Exception in method 'stop'" ); + printStackTrace( e ); + SoundSystemException sse = new SoundSystemException( + e.getMessage() ); + SoundSystem.setException( sse ); + } + } + } + +/** + * Temporarily stops playback without rewinding. + */ + public void pause() + { + if( !loading() ) + { + // Make sure there is a sequencer: + if( sequencer == null ) + return; + + try + { + //stop playback. Will resume from this location next play. + sequencer.stop(); + } + catch( Exception e ) + { + errorMessage( "Exception in method 'pause'" ); + printStackTrace( e ); + SoundSystemException sse = new SoundSystemException( + e.getMessage() ); + SoundSystem.setException( sse ); + } + } + } + +/** + * Returns playback to the beginning. + */ + public void rewind() + { + if( !loading() ) + { + // Make sure there is a sequencer: + if( sequencer == null ) + return; + + try + { + // rewind to the beginning: + sequencer.setMicrosecondPosition( 0 ); + } + catch( Exception e ) + { + errorMessage( "Exception in method 'rewind'" ); + printStackTrace( e ); + SoundSystemException sse = new SoundSystemException( + e.getMessage() ); + SoundSystem.setException( sse ); + } + } + } + +/** + * Changes the volume of MIDI playback. + * @param value Float value (0.0f - 1.0f). + */ + public void setVolume( float value ) + { + gain = value; + resetGain(); + } + +/** + * Returns the current volume for the MIDI source. + * @return Float value (0.0f - 1.0f). + */ + public float getVolume() + { + return gain; + } + +/** + * Changes the basic information about the MIDI source. This method removes + * any queued filenames/URLs from the list of MIDI sequences that would have + * played after the current sequence ended. + * @param toLoop Should playback loop or play only once? + * @param sourcename Unique identifier for this source. + * @param filename Name of the MIDI file to play. + */ + public void switchSource( boolean toLoop, String sourcename, + String filename ) + { + // Let everyone know we are busy loading: + loading( SET, true ); + + // save information about the source: + filenameURL( SET, new FilenameURL( filename ) ); + sourcename( SET, sourcename ); + setLooping( toLoop ); + + reset(); + + // Finished loading: + loading( SET, false ); + } + +/** + * Changes the basic information about the MIDI source. This method removes + * any queued filenames/URLs from the list of MIDI sequences that would have + * played after the current sequence ended. The fourth parameter, + * 'identifier' should look like a filename, and it must have the correct + * extension (.mid or .midi). + * @param toLoop Should playback loop or play only once? + * @param sourcename Unique identifier for this source. + * @param midiFile URL to the MIDI file to play. + * @param identifier Filename/identifier for the MIDI file. + */ + public void switchSource( boolean toLoop, String sourcename, URL midiFile, + String identifier ) + { + // Let everyone know we are busy loading: + loading( SET, true ); + + // save information about the source: + filenameURL( SET, new FilenameURL( midiFile, identifier ) ); + sourcename( SET, sourcename ); + setLooping( toLoop ); + + reset(); + + // Finished loading: + loading( SET, false ); + } + +/** + * Changes the basic information about the MIDI source. This method removes + * any queued filenames/URLs from the list of MIDI sequences that would have + * played after the current sequence ended. + * @param toLoop Should playback loop or play only once? + * @param sourcename Unique identifier for this source. + * @param filenameURL Filename/URL of the MIDI file to play. + */ + public void switchSource( boolean toLoop, String sourcename, + FilenameURL filenameURL ) + { + // Let everyone know we are busy loading: + loading( SET, true ); + + // save information about the source: + filenameURL( SET, filenameURL ); + sourcename( SET, sourcename ); + setLooping( toLoop ); + + reset(); + + // Finished loading: + loading( SET, false ); + } + +/** + * Stops and rewinds the sequencer, and resets the sequence. + */ + private void reset() + { + synchronized( sequenceQueueLock ) + { + if( sequenceQueue != null ) + sequenceQueue.clear(); + } + + // Check if we have a sequencer: + if( sequencer == null ) + { + // nope, try and get one now: + getSequencer(); + } + else + { + // We have a sequencer. Stop it now: + sequencer.stop(); + // rewind to the beginning: + sequencer.setMicrosecondPosition( 0 ); + // Stop listening for a moment: + sequencer.removeMetaEventListener( this ); + // wait a bit for the sequencer to shut down and rewind: + try{ Thread.sleep( 100 ); }catch( InterruptedException e ){} + } + // We need to have a sequencer at this point: + if( sequencer == null ) + { + errorMessage( "Unable to set the sequence in method " + + "'reset', because there wasn't " + + "a sequencer to use." ); + return; + } + + // set the new sequence to be played: + setSequence( filenameURL( GET, null ).getURL() ); + // start playing again: + sequencer.start(); + // make sure we play at the correct volume: + // (TODO: This doesn't always work??) + resetGain(); + // start listening for end of track event again: + sequencer.addMetaEventListener( this ); + } + +/** + * Sets the value of boolean 'toLoop'. + * @param value True or False. + */ + public void setLooping( boolean value ) + { + toLoop( SET, value ); + } + +/** + * Returns the value of boolean 'toLoop'. + * @return True while looping. + */ + public boolean getLooping() + { + return toLoop( GET, XXX ); + } + +/** + * Sets or returns the value of boolean 'toLoop'. + * @param action GET or SET. + * @param value New value if action == SET, or XXX if action == GET. + * @return True while looping. + */ + private synchronized boolean toLoop( boolean action, boolean value ) + { + if( action == SET ) + toLoop = value; + return toLoop; + } + +/** + * Check if a MIDI file is in the process of loading. + */ + public boolean loading() + { + return( loading( GET, XXX ) ); + } + +/** + * Sets or returns the value of boolean 'loading'. + * @param action GET or SET. + * @param value New value if action == SET, or XXX if action == GET. + * @return True while a MIDI file is in the process of loading. + */ + private synchronized boolean loading( boolean action, boolean value ) + { + if( action == SET ) + loading = value; + return loading; + } + +/** + * Defines the unique identifier for this source + * @param value New source name. + */ + public void setSourcename( String value ) + { + sourcename( SET, value ); + } + +/** + * Returns the unique identifier for this source. + * @return The source's name. + */ + public String getSourcename() + { + return sourcename( GET, null ); + } + +/** + * Sets or returns the value of String 'sourcename'. + * @param action GET or SET. + * @param value New value if action == SET, or null if action == GET. + * @return The source's name. + */ + private synchronized String sourcename( boolean action, String value ) + { + if( action == SET ) + sourcename = value; + return sourcename; + } + +/** + * Defines which MIDI file to play. + * @param value Path to the MIDI file. + */ + public void setFilenameURL( FilenameURL value ) + { + filenameURL( SET, value ); + } + +/** + * Returns the filename/identifier of the MIDI file being played. + * @return Filename of identifier of the MIDI file. + */ + public String getFilename() + { + return filenameURL( GET, null ).getFilename(); + } + +/** + * Returns the MIDI file being played. + * @return Filename/URL of the MIDI file. + */ + public FilenameURL getFilenameURL() + { + return filenameURL( GET, null ); + } + +/** + * Sets or returns the value of filenameURL. + * @param action GET or SET. + * @param value New value if action == SET, or null if action == GET. + * @return Path to the MIDI file. + */ + private synchronized FilenameURL filenameURL( boolean action, + FilenameURL value ) + { + if( action == SET ) + filenameURL = value; + return filenameURL; + } + +/** + * Called when MIDI events occur. + * @param message Meta mssage describing the MIDI event. + */ + public void meta( MetaMessage message ) + { + if( message.getType() == END_OF_TRACK ) + { + // Generate an EOS event: + SoundSystemConfig.notifyEOS( sourcename, sequenceQueue.size() ); + + // check if we should loop or not: + if( toLoop ) + { + // looping + // Check if playback is in the process of fading out. + if( !checkFadeOut() ) + { + // Not fading out, progress to the next MIDI sequence if + // any are queued. + if( !incrementSequence() ) + { + try + { + // Rewind to the beginning. + sequencer.setMicrosecondPosition( 0 ); + sequencer.start(); + // Make sure playback volume is correct. + resetGain(); + } + catch( Exception e ){} + } + } + else if( sequencer != null ) + { + try + { + // Rewind to the beginning. + sequencer.setMicrosecondPosition( 0 ); + sequencer.start(); + // Make sure playback volume is correct. + resetGain(); + } + catch( Exception e ){} + } + } + else + { + //non-looping + if( !checkFadeOut() ) + { + if( !incrementSequence() ) + { + try + { + // stop playback: + sequencer.stop(); + // rewind to the beginning: + sequencer.setMicrosecondPosition( 0 ); + // stop looping: + sequencer.removeMetaEventListener( this ); + } + catch( Exception e ){} + } + } + else + { + try + { + // stop playback: + sequencer.stop(); + // rewind to the beginning: + sequencer.setMicrosecondPosition( 0 ); + // stop looping: + sequencer.removeMetaEventListener( this ); + } + catch( Exception e ){} + } + } + } + } + +/** + * Resets playback volume to the correct level. + */ + public void resetGain() + { + // make sure the value for gain is valid (between 0 and 1) + if( gain < 0.0f ) + gain = 0.0f; + if( gain > 1.0f ) + gain = 1.0f; + + int midiVolume = (int) ( gain * SoundSystemConfig.getMasterGain() + * (float) Math.abs( fadeOutGain ) * fadeInGain + * 127.0f ); + if( synthesizer != null ) + { + javax.sound.midi.MidiChannel[] channels = synthesizer.getChannels(); + for( int c = 0; channels != null && c < channels.length; c++ ) + { + channels[c].controlChange( CHANGE_VOLUME, midiVolume ); + } + } + else if( synthDevice != null ) + { + try + { + ShortMessage volumeMessage = new ShortMessage(); + for( int i = 0; i < 16; i++ ) + { + volumeMessage.setMessage( ShortMessage.CONTROL_CHANGE, i, + CHANGE_VOLUME, midiVolume ); + synthDevice.getReceiver().send( volumeMessage, -1 ); + } + } + catch( Exception e ) + { + errorMessage( "Error resetting gain on MIDI device" ); + printStackTrace( e ); + } + } + else if( sequencer != null && sequencer instanceof Synthesizer ) + { + synthesizer = (Synthesizer) sequencer; + javax.sound.midi.MidiChannel[] channels = synthesizer.getChannels(); + for( int c = 0; channels != null && c < channels.length; c++ ) + { + channels[c].controlChange( CHANGE_VOLUME, midiVolume ); + } + } + else + { + try + { + Receiver receiver = MidiSystem.getReceiver(); + ShortMessage volumeMessage= new ShortMessage(); + for( int c = 0; c < 16; c++ ) + { + volumeMessage.setMessage( ShortMessage.CONTROL_CHANGE, c, + CHANGE_VOLUME, midiVolume ); + receiver.send( volumeMessage, -1 ); + } + } + catch( Exception e ) + { + errorMessage( "Error resetting gain on default receiver" ); + printStackTrace( e ); + } + } + } + +/** + * Attempts to load the default sequencer. If it fails, then other common + * sequencers are tried. If none can be loaded, then variable 'sequencer' + * remains null. + */ + private void getSequencer() + { + try + { + sequencer = MidiSystem.getSequencer(); + if( sequencer != null ) + { + try + { + sequencer.getTransmitter(); + } + catch( MidiUnavailableException mue ) + { + message( "Unable to get a transmitter from the " + + "default MIDI sequencer" ); + } + sequencer.open(); + } + } + catch( MidiUnavailableException mue ) + { + message( "Unable to open the default MIDI sequencer" ); + sequencer = null; + } + catch( Exception e ) + { + if( e instanceof InterruptedException ) + { + message( "Caught InterruptedException while attempting to " + + "open the default MIDI sequencer. Trying again." ); + sequencer = null; + } + try + { + sequencer = MidiSystem.getSequencer(); + if( sequencer != null ) + { + try + { + sequencer.getTransmitter(); + } + catch( MidiUnavailableException mue ) + { + message( "Unable to get a transmitter from the " + + "default MIDI sequencer" ); + } + sequencer.open(); + } + } + catch( MidiUnavailableException mue ) + { + message( "Unable to open the default MIDI sequencer" ); + sequencer = null; + } + catch( Exception e2 ) + { + message( "Unknown error opening the default MIDI sequencer" ); + sequencer = null; + } + } + + if( sequencer == null ) + sequencer = openSequencer( "Real Time Sequencer" ); + if( sequencer == null ) + sequencer = openSequencer( "Java Sound Sequencer"); + if( sequencer == null ) + { + errorMessage( "Failed to find an available MIDI sequencer" ); + return; + } + } + +/** + * Loads the MIDI sequence form the specified URL, and sets the sequence. If + * variable 'sequencer' is null or an error occurs, then variable 'sequence' + * remains null. + * @param midiSource URL to a MIDI file. + */ + private void setSequence( URL midiSource ) + { + if( sequencer == null ) + { + errorMessage( "Unable to update the sequence in method " + + "'setSequence', because variable 'sequencer' " + + "is null" ); + return; + } + + if( midiSource == null ) + { + errorMessage( "Unable to load Midi file in method 'setSequence'." ); + return; + } + + try + { + sequence = MidiSystem.getSequence( midiSource ); + } + catch( IOException ioe ) + { + errorMessage( "Input failed while reading from MIDI file in " + + "method 'setSequence'." ); + printStackTrace( ioe ); + return; + } + catch( InvalidMidiDataException imde ) + { + errorMessage( "Invalid MIDI data encountered, or not a MIDI " + + "file in method 'setSequence' (1)." ); + printStackTrace( imde ); + return; + } + if( sequence == null ) + { + errorMessage( "MidiSystem 'getSequence' method returned null " + + "in method 'setSequence'." ); + } + else + { + try + { + sequencer.setSequence( sequence ); + } + catch( InvalidMidiDataException imde ) + { + errorMessage( "Invalid MIDI data encountered, or not a MIDI " + + "file in method 'setSequence' (2)." ); + printStackTrace( imde ); + return; + } + catch( Exception e ) + { + errorMessage( "Problem setting sequence from MIDI file in " + + "method 'setSequence'." ); + printStackTrace( e ); + return; + } + } + } + +/** + * First attempts to load the specified "override MIDI synthesizer" if one was + * defined. If none was defined or unable to use it, then attempts to load the + * default synthesizer. If that fails, then other common synthesizers are + * attempted. If none can be loaded, then MIDI is not possible on this system. + */ + private void getSynthesizer() + { + if( sequencer == null ) + { + errorMessage( "Unable to load a Synthesizer in method " + + "'getSynthesizer', because variable 'sequencer' " + + "is null" ); + return; + } + + // Check if an alternate MIDI synthesizer was specified to use + String overrideMIDISynthesizer = + SoundSystemConfig.getOverrideMIDISynthesizer(); + if( overrideMIDISynthesizer != null + && !overrideMIDISynthesizer.equals( "" ) ) + { + // Try and open the specified device: + synthDevice = openMidiDevice( overrideMIDISynthesizer ); + // See if we got it: + if( synthDevice != null ) + { + // Got it, try and link it to the sequencer: + try + { + sequencer.getTransmitter().setReceiver( + synthDevice.getReceiver() ); + // Success! + return; + } + catch( MidiUnavailableException mue ) + { + // Problem linking the two, let the user know + errorMessage( "Unable to link sequencer transmitter " + + "with receiver for MIDI device '" + + overrideMIDISynthesizer + "'" ); + } + } + } + + // No alternate MIDI synthesizer was specified, or unable to use it. + + // If the squencer were also a synthesizer, that would make things easy: + if( sequencer instanceof Synthesizer ) + { + synthesizer = (Synthesizer) sequencer; + } + else + { + // Try getting the default synthesizer first: + try + { + synthesizer = MidiSystem.getSynthesizer(); + synthesizer.open(); + } + catch( MidiUnavailableException mue ) + { + message( "Unable to open the default synthesizer" ); + synthesizer = null; + } + + // See if we were sucessful: + if( synthesizer == null ) + { + // Try for the common MIDI synthesizers: + synthDevice = openMidiDevice( "Java Sound Synthesizer" ); + if( synthDevice == null ) + synthDevice = openMidiDevice( "Microsoft GS Wavetable" ); + if( synthDevice == null ) + synthDevice = openMidiDevice( "Gervill" ); + if( synthDevice == null ) + { + // Still nothing, MIDI is not going to work + errorMessage( "Failed to find an available MIDI " + + "synthesizer" ); + return; + } + } + + // Are we using the default synthesizer or something else? + if( synthesizer == null ) + { + // Link the sequencer and synthesizer: + try + { + sequencer.getTransmitter().setReceiver( + synthDevice.getReceiver() ); + } + catch( MidiUnavailableException mue ) + { + errorMessage( "Unable to link sequencer transmitter " + + "with MIDI device receiver" ); + } + } + else + { + // Bug-fix for multiple-receivers playing simultaneously + if( synthesizer.getDefaultSoundbank() == null ) + { + // Link the sequencer to the default receiver: + try + { + sequencer.getTransmitter().setReceiver( + MidiSystem.getReceiver() ); + } + catch( MidiUnavailableException mue ) + { + errorMessage( "Unable to link sequencer transmitter " + + "with default receiver" ); + } + } + else + { + // Link the sequencer to the default synthesizer: + try + { + sequencer.getTransmitter().setReceiver( + synthesizer.getReceiver() ); + } + catch( MidiUnavailableException mue ) + { + errorMessage( "Unable to link sequencer transmitter " + + "with synthesizer receiver" ); + } + } + // End bug-fix + } + } + } + +/** + * Attempts to open the Sequencer with a name containing the specified string. + * @param containsString Part or all of a Sequencer's name. + * @return Handle to the Sequencer, or null if not found or error. + */ + private Sequencer openSequencer( String containsString ) + { + Sequencer s = null; + s = (Sequencer) openMidiDevice( containsString ); + if( s == null ) + return null; + try + { + s.getTransmitter(); + } + catch( MidiUnavailableException mue ) + { + message( " Unable to get a transmitter from this sequencer" ); + s = null; + return null; + } + + return s; + } + +/** + * Attempts to open the MIDI device with a name containing the specified + * string. + * @param containsString Part or all of a MIDI device's name. + * @return Handle to the MIDI device, or null if not found or error. + */ + private MidiDevice openMidiDevice( String containsString ) + { + message( "Searching for MIDI device with name containing '" + + containsString + "'" ); + MidiDevice device = null; + MidiDevice.Info[] midiDevices = MidiSystem.getMidiDeviceInfo(); + for( int i = 0; i < midiDevices.length; i++ ) + { + device = null; + try + { + device = MidiSystem.getMidiDevice( midiDevices[i] ); + } + catch( MidiUnavailableException e ) + { + message( " Problem in method 'getMidiDevice': " + + "MIDIUnavailableException was thrown" ); + device = null; + } + if( device != null && midiDevices[i].getName().contains( + containsString ) ) + { + message( " Found MIDI device named '" + + midiDevices[i].getName() + "'" ); + if( device instanceof Synthesizer ) + message( " *this is a Synthesizer instance" ); + if( device instanceof Sequencer ) + message( " *this is a Sequencer instance" ); + try + { + device.open(); + } + catch( MidiUnavailableException mue ) + { + message( " Unable to open this MIDI device" ); + device = null; + } + return device; + } + } + message( " MIDI device not found" ); + return null; + } + +/** + * Prints a message. + * @param message Message to print. + */ + protected void message( String message ) + { + logger.message( message, 0 ); + } + +/** + * Prints an important message. + * @param message Message to print. + */ + protected void importantMessage( String message ) + { + logger.importantMessage( message, 0 ); + } + +/** + * Prints the specified message if error is true. + * @param error True or False. + * @param message Message to print if error is true. + * @return True if error is true. + */ + protected boolean errorCheck( boolean error, String message ) + { + return logger.errorCheck( error, "MidiChannel", message, 0 ); + } + +/** + * Prints an error message. + * @param message Message to print. + */ + protected void errorMessage( String message ) + { + logger.errorMessage( "MidiChannel", message, 0 ); + } + +/** + * Prints an exception's error message followed by the stack trace. + * @param e Exception containing the information to print. + */ + protected void printStackTrace( Exception e ) + { + logger.printStackTrace( e, 1 ); + } + +/** + * The FadeThread class handles sequence changing, timing, and volume change + * messages in the background. + */ + private class FadeThread extends SimpleThread + { + @Override +/** + * Runs in the background, timing fade in and fade out, changing the sequence, + * and issuing the appropriate volume change messages. + */ + public void run() + { + while( !dying() ) + { + // if not currently fading in or out, put the thread to sleep + if( fadeOutGain == -1.0f && fadeInGain == 1.0f ) + snooze( 3600000 ); + checkFadeOut(); + // only update every 50 miliseconds (no need to peg the cpu) + snooze( 50 ); + } + // Important! + cleanup(); + } + } + +} + diff --git a/src/lwjgl/java/paulscode/sound/SimpleThread.java b/src/lwjgl/java/paulscode/sound/SimpleThread.java new file mode 100644 index 0000000..8bd65fa --- /dev/null +++ b/src/lwjgl/java/paulscode/sound/SimpleThread.java @@ -0,0 +1,200 @@ +package paulscode.sound; + + +/** + * The SimpleThread class is the template used to create all thread classes + * used by in the SoundSystem library. It provides methods for common actions + * like sleeping, killing, and checking liveness. NOTE: super.cleanup() must + * be called at the bottom of overriden cleanup() methods, and cleanup() + * must be called at the bottom of the run() method for all extended classes. + *

+ * SoundSystem License:

+ * You are free to use this library for any purpose, commercial or otherwise. + * You may modify this library or source code, and distribute it any way you + * like, provided the following conditions are met: + *
+ * 1) You may not falsely claim to be the author of this library or any + * unmodified portion of it. + *
+ * 2) You may not copyright this library or a modified version of it and then + * sue me for copyright infringement. + *
+ * 3) If you modify the source code, you must clearly document the changes + * made before redistributing the modified source code, so other users know + * it is not the original code. + *
+ * 4) You are not required to give me credit for this library in any derived + * work, but if you do, you must also mention my website: + * http://www.paulscode.com + *
+ * 5) I the author will not be responsible for any damages (physical, + * financial, or otherwise) caused by the use if this library or any part + * of it. + *
+ * 6) I the author do not guarantee, warrant, or make any representations, + * either expressed or implied, regarding the use of this library or any + * part of it. + *

+ * Author: Paul Lamb + *
+ * http://www.paulscode.com + *
+ */ +public class SimpleThread extends Thread +{ +/** + * Used to return a current value from one of the synchronized + * boolean-interface methods. + */ + private static final boolean GET = false; + +/** + * Used to set the value in one of the synchronized boolean-interface methods. + */ + private static final boolean SET = true; + +/** + * Used when a parameter for one of the synchronized boolean-interface methods + * is not aplicable. + */ + private static final boolean XXX = false; + +/** + * True when thread is running. + */ + private boolean alive = true; + +/** + * True when thread should end. + */ + private boolean kill = false; + +/** + * Removes all references to instantiated objects, and changes the thread's + * state to "not alive". Method alive() returns false when this method has + * completed. NOTE: super.cleanup() must be called at the bottom of overriden + * cleanup() methods, and cleanup() must be called at the bottom of the run() + * method for all extended classes. + */ + protected void cleanup() + { + kill( SET, true ); // tread needs to shut down + alive( SET, false ); // thread has ended + } + +/** + * Executes the thread's main loop. NOTES: Extended classes should check + * method dying() often to know when the user wants the thread to shut down. + * Method cleanup() must be called at the bottom of the run() method for all + * extended classes. + */ + @Override + public void run() + { + /* How the run() method should be set up: */ + + + // Do your stuff here. Remember to check dying() often to know when + // the user wants the thread to shut down. + + // MUST call cleanup() at the bottom of Overridden run() method!!!!! + cleanup(); // clears memory and sets status to dead. + } + +/** + * Calls the rerun() method on a seperate thread, which calls run() when the + * previous thread finishes. + */ + public void restart() + { + new Thread() + { + @Override + public void run() + { + rerun(); + } + }.start(); + } + +/** + * Kills the previous thread, waits for it to die, then calls run(). + */ + private void rerun() + { + kill( SET, true ); + while( alive( GET, XXX ) ) + { + snooze( 100 ); + } + alive( SET, true ); + kill( SET, false ); + run(); + } + +/** + * Returns false when the cleanup() method has finished. This method should be + * used to know when the thread has been safely shut down. + * @return True while the thread is alive. + */ + public boolean alive() + { + return alive( GET, XXX ); + } + +/** + * Causes method dying() to return true, letting the thread know it needs to + * shut down. + */ + public void kill() + { + kill( SET, true ); + } + +/** + * Returns true when the thread is supposed to shut down. + * @return True if the thread should die. + */ + protected boolean dying() + { + return kill( GET, XXX ); + } + +/** + * Sets or returns the value of boolean 'alive'. + * @param action GET or SET. + * @param value New value if action == SET, or XXX if action == GET. + * @return True while the thread is alive. + */ + private synchronized boolean alive( boolean action, boolean value ) + { + if( action == SET ) + alive = value; + return alive; + } + +/** + * Sets or returns the value of boolean 'kill'. + * @param action GET or SET. + * @param value New value if action == SET, or XXX if action == GET. + * @return True if the thread should die. + */ + private synchronized boolean kill( boolean action, boolean value ) + { + if( action == SET ) + kill = value; + return kill; + } + +/** + * Sleeps for the specified number of milliseconds. + */ + protected void snooze( long milliseconds ) + { + try + { + Thread.sleep( milliseconds ); + } + catch( InterruptedException e ){} + } +} diff --git a/src/lwjgl/java/paulscode/sound/SoundBuffer.java b/src/lwjgl/java/paulscode/sound/SoundBuffer.java new file mode 100644 index 0000000..b258502 --- /dev/null +++ b/src/lwjgl/java/paulscode/sound/SoundBuffer.java @@ -0,0 +1,91 @@ +package paulscode.sound; + +import javax.sound.sampled.AudioFormat; + +/** + * The SoundBuffer class is used to wrap audio data along with the format in + * which the data is stored. + *

+ * SoundSystem License:

+ * You are free to use this library for any purpose, commercial or otherwise. + * You may modify this library or source code, and distribute it any way you + * like, provided the following conditions are met: + *
+ * 1) You may not falsely claim to be the author of this library or any + * unmodified portion of it. + *
+ * 2) You may not copyright this library or a modified version of it and then + * sue me for copyright infringement. + *
+ * 3) If you modify the source code, you must clearly document the changes + * made before redistributing the modified source code, so other users know + * it is not the original code. + *
+ * 4) You are not required to give me credit for this library in any derived + * work, but if you do, you must also mention my website: + * http://www.paulscode.com + *
+ * 5) I the author will not be responsible for any damages (physical, + * financial, or otherwise) caused by the use if this library or any part + * of it. + *
+ * 6) I the author do not guarantee, warrant, or make any representations, + * either expressed or implied, regarding the use of this library or any + * part of it. + *

+ * Author: Paul Lamb + *
+ * http://www.paulscode.com + *
+ */ +public class SoundBuffer +{ +/** + * The actual audio data. + */ + public byte[] audioData; +/** + * The audio format in which the data is stored. + */ + public AudioFormat audioFormat; + +/** + * Constructor: Wraps the specified data with the specified audio format. + * + * @param audioData The actual audio data. + * @param audioFormat The audio format in which the data is stored. + */ + public SoundBuffer( byte[] audioData, AudioFormat audioFormat ) + { + this.audioData = audioData; + this.audioFormat = audioFormat; + } + +/** + * Removes handles to all instantiated objects. + */ + public void cleanup() + { + audioData = null; + audioFormat = null; + } + +/** + * Trims down the size of the audio data if it is larger than the specified + * maximum length. + * + * @param maxLength Maximum size this buffer may be. + */ + public void trimData( int maxLength ) + { + if( audioData == null || maxLength == 0 ) + audioData = null; + else if( audioData.length > maxLength ) + { + byte[] trimmedArray = new byte[maxLength]; + System.arraycopy( audioData, 0, trimmedArray, 0, + maxLength ); + audioData = trimmedArray; + } + } +} diff --git a/src/lwjgl/java/paulscode/sound/SoundSystem.java b/src/lwjgl/java/paulscode/sound/SoundSystem.java new file mode 100644 index 0000000..0f25617 --- /dev/null +++ b/src/lwjgl/java/paulscode/sound/SoundSystem.java @@ -0,0 +1,2895 @@ +package paulscode.sound; + +import java.net.URL; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Random; +import java.util.Set; +import javax.sound.sampled.AudioFormat; + +/** + * The SoundSystem class is the core class for the SoundSystem library. It is + * capable of interfacing with external sound library and codec library + * pluggins. This core class is stripped down to give it a smaller memory + * footprint and to make it more customizable. This library was created to + * provide a simple, common interface to a variety of 3rd-party sound and codec + * libraries, and to simplify switching between them on the fly. If no + * external pluggins are loaded, this core class by itself is only capable of + * playing MIDI files. Specific implementations (such as SoundSystemJPCT) will + * extend this core class. They will automatically link with popular + * external pluggins and provide extra methods for ease of use. + * There should be only one instance of this class in any program! The + * SoundSystem can be constructed by defining which sound library to use, or by + * allowing SoundSystem to perform its own library compatibility checking. See + * {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for information + * about changing default settings and linking with external pluggins. + *

+ * SoundSystem License:

+ * You are free to use this library for any purpose, commercial or otherwise. + * You may modify this library or source code, and distribute it any way you + * like, provided the following conditions are met: + *
+ * 1) You may not falsely claim to be the author of this library or any + * unmodified portion of it. + *
+ * 2) You may not copyright this library or a modified version of it and then + * sue me for copyright infringement. + *
+ * 3) If you modify the source code, you must clearly document the changes + * made before redistributing the modified source code, so other users know + * it is not the original code. + *
+ * 4) You are not required to give me credit for this library in any derived + * work, but if you do, you must also mention my website: + * http://www.paulscode.com + *
+ * 5) I the author will not be responsible for any damages (physical, + * financial, or otherwise) caused by the use if this library or any part + * of it. + *
+ * 6) I the author do not guarantee, warrant, or make any representations, + * either expressed or implied, regarding the use of this library or any + * part of it. + *

+ * Author: Paul Lamb + *
+ * http://www.paulscode.com + *
+ */ +public class SoundSystem +{ +/** + * Used to return a current value from one of the synchronized + * boolean-interface methods. + */ + private static final boolean GET = false; +/** + * Used to set the value in one of the synchronized boolean-interface methods. + */ + private static final boolean SET = true; +/** + * Used when a parameter for one of the synchronized boolean-interface methods + * is not aplicable. + */ + private static final boolean XXX = false; + +/** + * Processes status messages, warnings, and error messages. + */ + protected SoundSystemLogger logger; + +/** + * Handle to the active sound library. + */ + protected Library soundLibrary; + +/** + * List of queued commands to perform. + */ + protected List commandQueue; + +/** + * Used internally by SoundSystem to keep track of play/pause/stop/rewind + * commands. This prevents source management (culling and activating) from + * being adversely affected by the quickPlay, quickStream, and backgroundMusic + * methods. + */ + private List sourcePlayList; + +/** + * Processes queued commands in the background. + */ + protected CommandThread commandThread; + +/** + * Generates random numbers. + */ + public Random randomNumberGenerator; + +/** + * Name of this class. + */ + protected String className = "SoundSystem"; + +/** + * Indicates the currently loaded sound-library, or null if none. + */ + private static Class currentLibrary = null; + +/** + * Becomes true when the sound library has been initialized. + */ + private static boolean initialized = false; + +/** + * Indicates the last exception that was thrown. + */ + private static SoundSystemException lastException = null; + +/** + * Constructor: Create the sound system using the default library. If the + * default library is not compatible, another library type will be loaded + * instead, in the order of library preference. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for + * information about sound library types. + */ + public SoundSystem() + { + // create the message logger: + logger = SoundSystemConfig.getLogger(); + // if the user didn't create one, then do it now: + if( logger == null ) + { + logger = new SoundSystemLogger(); + SoundSystemConfig.setLogger( logger ); + } + + linkDefaultLibrariesAndCodecs(); + + LinkedList libraries = SoundSystemConfig.getLibraries(); + + if( libraries != null ) + { + ListIterator i = libraries.listIterator(); + Class c; + while( i.hasNext() ) + { + c = i.next(); + try + { + init( c ); + return; + } + catch( SoundSystemException sse ) + { + logger.printExceptionMessage( sse, 1 ); + } + } + } + try + { + init( Library.class ); + return; + } + catch( SoundSystemException sse ) + { + logger.printExceptionMessage( sse, 1 ); + } + } + +/** + * Constructor: Create the sound system using the specified library. + * @param libraryClass Library to use. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for + * information about chosing a sound library. + */ + public SoundSystem( Class libraryClass ) throws SoundSystemException + { + // create the message logger: + logger = SoundSystemConfig.getLogger(); + // if the user didn't create one, then do it now: + if( logger == null ) + { + logger = new SoundSystemLogger(); + SoundSystemConfig.setLogger( logger ); + } + linkDefaultLibrariesAndCodecs(); + + init( libraryClass ); + } + +/** + * Links with any default libraries or codecs should be made in this method. + * This method is empty in the core SoundSystem class, and should be overriden + * by classes which extend SoundSystem. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for + * information about linking with sound libraries and codecs. + */ + protected void linkDefaultLibrariesAndCodecs() + { + } + +/** + * Loads the message logger, initializes the specified sound library, and + * starts the command thread. Also instantiates the random number generator + * and the command queue. + * @param libraryClass Library to initialize. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for + * information about chosing a sound library. + */ + protected void init( Class libraryClass ) throws SoundSystemException + { + message( "", 0 ); + message( "Starting up " + className + " version "+ SoundSystem.class.getPackage().getImplementationVersion()+"...", 0 ); + + // create the random number generator: + randomNumberGenerator = new Random(); + // create the command queue: + commandQueue = new LinkedList(); + // create the working source playlist: + sourcePlayList = new LinkedList(); + + // Instantiate and start the Command Processer thread: + commandThread = new CommandThread( this ); // Gets a SoundSystem handle + commandThread.start(); + + snooze( 200 ); + + newLibrary( libraryClass ); + message( "", 0 ); + } + +/** + * Ends the command thread, shuts down the sound system, and removes references + * to all instantiated objects. + */ + public void cleanup() + { + boolean killException = false; + message( "", 0 ); + message( className + " shutting down...", 0 ); + + // End the command thread: + try + { + commandThread.kill(); // end the command processor loop. + commandThread.interrupt(); // wake the thread up so it can end. + } + catch( Exception e ) + { + killException = true; + } + + if( !killException ) + { + // wait up to 5 seconds for command thread to end: + for( int i = 0; i < 50; i++ ) + { + if( !commandThread.alive() ) + break; + snooze( 100 ); + } + } + + // Let user know if there was a problem ending the command thread + if( killException || commandThread.alive() ) + { + errorMessage( "Command thread did not die!", 0 ); + message( "Ignoring errors... continuing clean-up.", 0 ); + } + + initialized( SET, false ); + currentLibrary( SET, null ); + try + { + // Stop all sources and shut down the sound library: + if( soundLibrary != null ) + soundLibrary.cleanup(); + } + catch( Exception e ) + { + errorMessage( "Problem during Library.cleanup()!", 0 ); + message( "Ignoring errors... continuing clean-up.", 0 ); + } + + try + { + // remove any queued commands: + if( commandQueue != null ) + commandQueue.clear(); + } + catch( Exception e ) + { + errorMessage( "Unable to clear the command queue!", 0 ); + message( "Ignoring errors... continuing clean-up.", 0 ); + } + + try + { + // empty the source management list: + if( sourcePlayList != null ) + sourcePlayList.clear(); + } + catch( Exception e ) + { + errorMessage( "Unable to clear the source management list!", 0 ); + message( "Ignoring errors... continuing clean-up.", 0 ); + } + + // Remove references to all instantiated objects: + randomNumberGenerator = null; + soundLibrary = null; + commandQueue = null; + sourcePlayList = null; + commandThread = null; + + importantMessage( "Author: Paul Lamb, www.paulscode.com", 1 ); + message( "", 0 ); + } + +/** + * Wakes up the Command Thread to process commands. This method should be + * used if there is a need to call methods 'ManageSources' and 'CommandQueue' + * externally. In most cases, this method will not be needed, since + * SoundSystem automatically wakes the Command Thread every time commands are + * placed into either the ManageSources queue or CommandQueue to be processed. + */ + public void interruptCommandThread() + { + if( commandThread == null ) + { + errorMessage( "Command Thread null in method " + + "'interruptCommandThread'", 0 ); + return; + } + // Wake the command thread to process commands: + commandThread.interrupt(); + } + +/** + * Pre-loads a sound into memory. The file may either be located within the + * JAR or at an online location. If the file is online, filename must begin + * with "http://", since that is how SoundSystem recognizes URL's. If the file + * is located within the compiled JAR, the package in which sound files are + * located may be set by calling SoundSystemConfig.setSoundFilesPackage(). + * @param filename Filename of the sound file to load. + */ + public void loadSound( String filename ) + { + // Queue a command to load the sound file: + CommandQueue( new CommandObject( CommandObject.LOAD_SOUND, + new FilenameURL( filename ) ) ); + // Wake the command thread to process commands: + commandThread.interrupt(); + } + +/** + * Pre-loads a sound specified by the given URL into memory. The second + * parameter 'identifier' should look like a filename, and it must have the + * correct extension so SoundSystem knows what codec to use for the file + * referenced by the URL instance. + * @param url URL handle to the sound file to load. + * @param identifier Filename/identifier of the file referenced by the URL. + */ + public void loadSound( URL url, String identifier ) + { + // Queue a command to load the sound file from a URL: + CommandQueue( new CommandObject( CommandObject.LOAD_SOUND, + new FilenameURL( url, identifier ) ) ); + // Wake the command thread to process commands: + commandThread.interrupt(); + } + +/** + * Saves raw PCM audio data in the specified audio format, under the specified + * identifier. This identifier can be later used in place of 'filename' + * parameters to reference the sample data. + * @param data The sample data + * @param format Format the sample data is stored in + * @param identifier What to call the sample. + */ + public void loadSound( byte[] data, AudioFormat format, String identifier ) + { + // Queue a command to load the sound file from a URL: + CommandQueue( new CommandObject( CommandObject.LOAD_DATA, + identifier, + new SoundBuffer( data, format ) ) ); + // Wake the command thread to process commands: + commandThread.interrupt(); + } + + +/** + * Removes a pre-loaded sound from memory. This is a good method to use for + * freeing up memory after a large sound file is no longer needed. NOTE: the + * source will remain in memory after calling this method as long as the + * sound is attached to an existing source. When calling this method, calls + * should also be made to method removeSource( String ) for all sources which + * this sound is bound to. + * @param filename Filename/identifier of the sound file to unload. + */ + public void unloadSound( String filename ) + { + // Queue a command to unload the sound file: + CommandQueue( new CommandObject( CommandObject.UNLOAD_SOUND, filename ) ); + // Wake the command thread to process commands: + commandThread.interrupt(); + } + +/** + * If the specified source is a streaming source or MIDI source, this method + * queues up the next sound to play when the previous playback ends. The file + * may either be located within the JAR or at an online location. If the file + * is online, filename must begin with "http://", since that is how SoundSystem + * recognizes URL paths. If the file is located within the compiled JAR, the + * package in which sound files are located may be set by calling + * SoundSystemConfig.setSoundFilesPackage(). This method has no effect on + * non-streaming sources. + * @param sourcename Source identifier. + * @param filename Name of the sound file to play next. + */ + public void queueSound( String sourcename, String filename ) + { + // Queue a command to queue the sound: + CommandQueue( new CommandObject( CommandObject.QUEUE_SOUND, sourcename, + new FilenameURL( filename ) ) ); + // Wake the command thread to process commands: + commandThread.interrupt(); + } + +/** + * If the specified source is a streaming source or MIDI source, this method + * queues up the next sound to play when the previous playback ends. The third + * parameter 'identifier' should look like a filename, and it must have the + * correct extension so SoundSystem knows what codec to use for the file + * referenced by the URL instance. This method has no effect on non-streaming + * sources. + * @param sourcename Source identifier. + * @param url URL handle to the sound file to load. + * @param identifier Filename/identifier of the file referenced by the URL. + */ + public void queueSound( String sourcename, URL url, String identifier ) + { + // Queue a command to queue the sound: + CommandQueue( new CommandObject( CommandObject.QUEUE_SOUND, sourcename, + new FilenameURL( url, identifier ) ) ); + // Wake the command thread to process commands: + commandThread.interrupt(); + } + +/** + * Removes the first occurrence of the specified filename/identifier from the + * specified source's list of sounds to play when previous playback ends. This + * method has no effect on non-streaming sources. + * @param sourcename Source identifier. + * @param filename Filename/identifier of the sound file to play next. + */ + public void dequeueSound( String sourcename, String filename ) + { + // Queue a command to dequeue the sound: + CommandQueue( new CommandObject( CommandObject.DEQUEUE_SOUND, + sourcename, filename ) ); + // Wake the command thread to process commands: + commandThread.interrupt(); + } + +/** + * Fades out the volume of whatever the specified source is currently playing, + * then begins playing the specified file at the source's previously + * assigned volume level. The file may either be located within the JAR or at + * an online location. If the file is online, filename must begin with + * "http://", since that is how SoundSystem recognizes URL paths. If the file + * is located within the compiled JAR, the package in which sound files are + * located may be set by calling SoundSystemConfig.setSoundFilesPackage(). If + * the filename parameter is null or empty, the specified source will simply + * fade out and stop. The miliseconds parameter must be non-negative or zero. + * This method will remove anything that is currently in the specified source's + * list of queued sounds that would have played next when the current sound + * finished playing. This method may only be used for streaming and MIDI + * sources. + * @param sourcename Name of the source to fade out. + * @param filename Name of a sound file to play next, or null for none. + * @param milis Number of miliseconds the fadeout should take. + */ + public void fadeOut( String sourcename, String filename, long milis ) + { + FilenameURL fu = null; + if( filename != null ) + fu = new FilenameURL( filename ); + // Queue a command to fade out: + CommandQueue( new CommandObject( CommandObject.FADE_OUT, sourcename, fu, + milis ) ); + // Wake the command thread to process commands: + commandThread.interrupt(); + } + +/** + * Fades out the volume of whatever the specified source is currently playing, + * then begins playing the specified file at the source's previously + * assigned volume level. If the url parameter is null or empty, the + * specified source will simply fade out and stop. The third + * parameter 'identifier' should look like a filename, and it must have the + * correct extension so SoundSystem knows what codec to use for the file + * referenced by the URL instance. The miliseconds parameter must be + * non-negative or zero. This method will remove anything that is currently in + * the specified source's list of queued sounds that would have played next + * when the current sound finished playing. This method may only be used for + * streaming and MIDI sources. + * @param sourcename Name of the source to fade out. + * @param url URL handle to the sound file to play next, or null for none. + * @param identifier Filename/identifier of the file referenced by the URL. + * @param milis Number of miliseconds the fadeout should take. + */ + public void fadeOut( String sourcename, URL url, String identifier, + long milis ) + { + FilenameURL fu = null; + if( url != null && identifier != null ) + fu = new FilenameURL( url, identifier ); + // Queue a command to fade out: + CommandQueue( new CommandObject( CommandObject.FADE_OUT, sourcename, fu, + milis ) ); + // Wake the command thread to process commands: + commandThread.interrupt(); + } + +/** + * Fades out the volume of whatever the specified source is currently playing, + * then fades the volume back in playing the specified filename. Final volume + * after fade-in completes will be equal to the source's previously assigned + * volume level. The filename parameter may not be null or empty. The file + * may either be located within the JAR or at an online location. If the file + * is online, filename must begin with "http://", since that is how + * SoundSystem recognizes URL paths. If the file is located within the + * compiled JAR, the package in which sound files are located may be set by + * calling SoundSystemConfig.setSoundFilesPackage(). The miliseconds + * parameters must be non-negative or zero. This method will remove anything + * that is currently in the specified source's list of queued sounds that would + * have played next when the current sound finished playing. This method may + * only be used for streaming and MIDI sources. + * @param sourcename Name of the source to fade out/in. + * @param filename Name of a sound file to play next, or null for none. + * @param milisOut Number of miliseconds the fadeout should take. + * @param milisIn Number of miliseconds the fadein should take. + */ + public void fadeOutIn( String sourcename, String filename, long milisOut, + long milisIn ) + { + // Queue a command to load the sound file: + CommandQueue( new CommandObject( CommandObject.FADE_OUT_IN, + sourcename, + new FilenameURL( filename ), milisOut, + milisIn ) ); + // Wake the command thread to process commands: + commandThread.interrupt(); + } + +/** + * Fades out the volume of whatever the specified source is currently playing, + * then fades the volume back in playing the specified file. Final volume + * after fade-in completes will be equal to the source's previously assigned + * volume level. The url parameter may not be null or empty. The third + * parameter 'identifier' should look like a filename, and it must have the + * correct extension so SoundSystem knows what codec to use for the file + * referenced by the URL instance. The miliseconds parameters must be + * non-negative or zero. This method will remove anything that is currently + * in the specified source's list of queued sounds that would have played next + * when the current sound finished playing. This method may only be used for + * streaming and MIDI sources. + * @param sourcename Name of the source to fade out/in. + * @param url URL handle to the sound file to play next. + * @param identifier Filename/identifier of the file referenced by the URL. + * @param milisOut Number of miliseconds the fadeout should take. + * @param milisIn Number of miliseconds the fadein should take. + */ + public void fadeOutIn( String sourcename, URL url, String identifier, + long milisOut, long milisIn ) + { + // Queue a command to load the sound file: + CommandQueue( new CommandObject( CommandObject.FADE_OUT_IN, + sourcename, + new FilenameURL( url, identifier ), + milisOut, milisIn ) ); + // Wake the command thread to process commands: + commandThread.interrupt(); + } + +/** + * Makes sure the current volume levels of streaming sources and MIDI are + * correct. This method is designed to help reduce the "jerky" fading behavior + * that happens when using some library and codec pluggins (such as + * LibraryJavaSound and CodecJOrbis). This method has no effect on normal + * "non-streaming" sources. It would normally be called somewhere in the main + * "game loop". IMPORTANT: To optimize frame-rates, do not call this method + * for every frame. It is better to just call this method at some acceptable + * "granularity" (play around with different granularities to find what sounds + * acceptable for a particular situation). + */ + public void checkFadeVolumes() + { + // Queue a command to load check fading source volumes: + CommandQueue( new CommandObject( CommandObject.CHECK_FADE_VOLUMES ) ); + // Wake the command thread to process commands: + commandThread.interrupt(); + } + +/** + * Creates a new permanant, streaming, priority source with zero attenuation. + * The file may either be located within the JAR or at an online location. If + * the file is online, filename must begin with "http://", since that is how + * SoundSystem recognizes URL paths. If the file is located within the + * compiled JAR, the package in which sound files are located may be set by + * calling SoundSystemConfig.setSoundFilesPackage(). + * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename. + * @param filename Filename of the sound file to stream at this source. + * @param toLoop Should this source loop, or play only once. + */ + public void backgroundMusic( String sourcename, String filename, + boolean toLoop ) + { + // Queue a command to quick stream a new source: + CommandQueue( new CommandObject( CommandObject.QUICK_PLAY, true, + true, toLoop, sourcename, + new FilenameURL( filename ), 0, 0, 0, + SoundSystemConfig.ATTENUATION_NONE, 0, false ) ); + CommandQueue( new CommandObject( CommandObject.PLAY, sourcename) ); + + commandThread.interrupt(); + } + +/** + * Creates a new permanant, streaming, priority source with zero attenuation. + * The third parameter 'identifier' should look like a filename, and it must + * have the correct extension so SoundSystem knows what codec to use for the + * file referenced by the URL instance. + * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename. + * @param url URL handle to the sound file to stream at this source. + * @param identifier Filename/identifier of the file referenced by the URL. + * @param toLoop Should this source loop, or play only once. + */ + public void backgroundMusic( String sourcename, URL url, String identifier, + boolean toLoop ) + { + // Queue a command to quick stream a new source: + CommandQueue( new CommandObject( CommandObject.QUICK_PLAY, true, + true, toLoop, sourcename, + new FilenameURL( url, identifier ), + 0, 0, 0, + SoundSystemConfig.ATTENUATION_NONE, + 0, false ) ); + CommandQueue( new CommandObject( CommandObject.PLAY, sourcename) ); + + commandThread.interrupt(); + } + +/** + * Creates a new non-streaming source. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more + * information about Attenuation, fade distance, and rolloff factor. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename. + * @param filename Filename/identifier of the sound file to play at this source. + * @param toLoop Should this source loop, or play only once. + * @param x X position for this source. + * @param y Y position for this source. + * @param z Z position for this source. + * @param attmodel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel". + */ + public void newSource( boolean priority, String sourcename, String filename, + boolean toLoop, float x, float y, float z, + int attmodel, float distOrRoll ) + { + CommandQueue( new CommandObject( CommandObject.NEW_SOURCE, priority, + false, toLoop, sourcename, + new FilenameURL( filename ), x, y, z, + attmodel, distOrRoll ) ); + commandThread.interrupt(); + } + +/** + * Creates a new non-streaming source. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more + * information about Attenuation, fade distance, and rolloff factor. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename. + * @param url URL handle to the sound file to stream at this source. + * @param identifier Filename/identifier of the file referenced by the URL. + * @param toLoop Should this source loop, or play only once. + * @param x X position for this source. + * @param y Y position for this source. + * @param z Z position for this source. + * @param attmodel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel". + */ + public void newSource( boolean priority, String sourcename, URL url, + String identifier, boolean toLoop, float x, float y, + float z, int attmodel, float distOrRoll ) + { + CommandQueue( new CommandObject( CommandObject.NEW_SOURCE, priority, + false, toLoop, sourcename, + new FilenameURL( url, identifier ), + x, y, z, + attmodel, distOrRoll ) ); + commandThread.interrupt(); + } + +/** + * Creates a new streaming source. The file may either be located within the + * JAR or at an online location. If the file is online, filename must begin + * with "http://", since that is how SoundSystem recognizes URL paths. If the + * file is located within the compiled JAR, the package in which sound files + * are located may be set by calling SoundSystemConfig.setSoundFilesPackage(). + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename. + * @param filename The filename of the sound file to play at this source. + * @param toLoop Should this source loop, or play only once. + * @param x X position for this source. + * @param y Y position for this source. + * @param z Z position for this source. + * @param attmodel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel". + */ + public void newStreamingSource( boolean priority, String sourcename, + String filename, boolean toLoop, float x, + float y, float z, int attmodel, + float distOrRoll ) + { + CommandQueue( new CommandObject( CommandObject.NEW_SOURCE, priority, + true, toLoop, sourcename, + new FilenameURL( filename ), x, y, z, + attmodel, distOrRoll ) ); + commandThread.interrupt(); + } + +/** + * Creates a new streaming source. The fourth parameter 'identifier' should + * look like a filename, and it must have the correct extension so SoundSystem + * knows what codec to use for the file referenced by the URL instance. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename. + * @param url URL handle to the sound file to stream at this source. + * @param identifier Filename/identifier of the file referenced by the URL. + * @param toLoop Should this source loop, or play only once. + * @param x X position for this source. + * @param y Y position for this source. + * @param z Z position for this source. + * @param attmodel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel". + */ + public void newStreamingSource( boolean priority, String sourcename, + URL url, String identifier, boolean toLoop, + float x, float y, float z, int attmodel, + float distOrRoll ) + { + CommandQueue( new CommandObject( CommandObject.NEW_SOURCE, priority, + true, toLoop, sourcename, + new FilenameURL( url, identifier ), + x, y, z, attmodel, distOrRoll ) ); + commandThread.interrupt(); + } + +/** + * Opens a direct line for streaming audio data. This method creates a new + * streaming source to play the data at. The resulting streaming source can be + * manipulated the same as any other streaming source. Raw data can be sent to + * the new streaming source using the feedRawAudioData() method. + * @param audioFormat Format that the data will be in. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename. + * @param x X position for this source. + * @param y Y position for this source. + * @param z Z position for this source. + * @param attModel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel". + */ + public void rawDataStream( AudioFormat audioFormat, boolean priority, + String sourcename, float x, float y, float z, + int attModel, float distOrRoll ) + { + CommandQueue( new CommandObject( CommandObject.RAW_DATA_STREAM, + audioFormat, priority, sourcename, x, + y, z, attModel, distOrRoll ) ); + commandThread.interrupt(); + } + +/** + * Creates a temporary source and plays it. After the source finishes playing, + * it is removed. Returns a randomly generated name for the new source. NOTE: + * to make a source created by this method permanant, call the setActive() + * method using the return value for sourcename. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param filename Filename/identifier of the sound file to play at this source. + * @param toLoop Should this source loop, or play only once. + * @param x X position for this source. + * @param y Y position for this source. + * @param z Z position for this source. + * @param attmodel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel". + * @return The new sorce's name. + */ + public String quickPlay( boolean priority, String filename, boolean toLoop, + float x, float y, float z, int attmodel, + float distOrRoll ) + { + //generate a random name for this source: + String sourcename = "Source_" + + randomNumberGenerator.nextInt() + + "_" + randomNumberGenerator.nextInt(); + + // Queue a command to quick play this new source: + CommandQueue( new CommandObject( CommandObject.QUICK_PLAY, priority, + false, toLoop, sourcename, + new FilenameURL( filename ), x, y, z, + attmodel, distOrRoll, true ) ); + CommandQueue( new CommandObject( CommandObject.PLAY, sourcename) ); + // Wake the command thread to process commands: + commandThread.interrupt(); + + // return the new source name. + return sourcename; + } + +/** + * Creates a temporary source and plays it. After the source finishes playing, + * it is removed. Returns a randomly generated name for the new source. NOTE: + * to make a source created by this method permanant, call the setActive() + * method using the return value for sourcename. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param url URL handle to the sound file to stream at this source. + * @param identifier Filename/identifier of the file referenced by the URL. + * @param toLoop Should this source loop, or play only once. + * @param x X position for this source. + * @param y Y position for this source. + * @param z Z position for this source. + * @param attmodel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel". + * @return The new sorce's name. + */ + public String quickPlay( boolean priority, URL url, String identifier, + boolean toLoop, float x, float y, float z, + int attmodel, float distOrRoll ) + { + //generate a random name for this source: + String sourcename = "Source_" + + randomNumberGenerator.nextInt() + + "_" + randomNumberGenerator.nextInt(); + + // Queue a command to quick play this new source: + CommandQueue( new CommandObject( CommandObject.QUICK_PLAY, priority, + false, toLoop, sourcename, + new FilenameURL( url, identifier ), + x, y, z, attmodel, distOrRoll, + true ) ); + CommandQueue( new CommandObject( CommandObject.PLAY, sourcename) ); + // Wake the command thread to process commands: + commandThread.interrupt(); + + // return the new source name. + return sourcename; + } + +/** + * Creates a temporary source and streams it. After the source finishes + * playing, it is removed. The file may either be located within the + * JAR or at an online location. If the file is online, filename must begin + * with "http://", since that is how SoundSystem recognizes URL paths. If the + * file is located within the compiled JAR, the package in which sound files + * are located may be set by calling SoundSystemConfig.setSoundFilesPackage(). + * Returns a randomly generated name for the new source. NOTE: to make a + * source created by this method permanant, call the setActive() method using + * the return value for sourcename. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param filename Filename of the sound file to stream at this source. + * @param toLoop Should this source loop, or play only once. + * @param x X position for this source. + * @param y Y position for this source. + * @param z Z position for this source. + * @param attmodel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel". + * @return The new sorce's name. + */ + public String quickStream( boolean priority, String filename, + boolean toLoop, float x, float y, float z, + int attmodel, float distOrRoll ) + { + //generate a random name for this source: + String sourcename = "Source_" + + randomNumberGenerator.nextInt() + + "_" + randomNumberGenerator.nextInt(); + + // Queue a command to quick stream this new source: + CommandQueue( new CommandObject( CommandObject.QUICK_PLAY, priority, + true, toLoop, sourcename, + new FilenameURL( filename ), x, y, z, + attmodel, distOrRoll, true ) ); + CommandQueue( new CommandObject( CommandObject.PLAY, sourcename) ); + // Wake the command thread to process commands: + commandThread.interrupt(); + + // return the new source name. + return sourcename; + } +/** + * Creates a temporary source and streams it. After the source finishes + * playing, it is removed. The third parameter 'identifier' should + * look like a filename, and it must have the correct extension so SoundSystem + * knows what codec to use for the file referenced by the URL instance. + * Returns a randomly generated name for the new source. NOTE: to make a + * source created by this method permanant, call the setActive() method using + * the return value for sourcename. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param url URL handle to the sound file to stream at this source. + * @param identifier Filename/identifier of the file referenced by the URL. + * @param toLoop Should this source loop, or play only once. + * @param x X position for this source. + * @param y Y position for this source. + * @param z Z position for this source. + * @param attmodel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel". + * @return The new sorce's name. + */ + public String quickStream( boolean priority, URL url, String identifier, + boolean toLoop, float x, float y, float z, + int attmodel, float distOrRoll ) + { + //generate a random name for this source: + String sourcename = "Source_" + + randomNumberGenerator.nextInt() + + "_" + randomNumberGenerator.nextInt(); + + // Queue a command to quick stream this new source: + CommandQueue( new CommandObject( CommandObject.QUICK_PLAY, priority, + true, toLoop, sourcename, + new FilenameURL( url, identifier ), + x, y, z, attmodel, distOrRoll, + true ) ); + CommandQueue( new CommandObject( CommandObject.PLAY, sourcename) ); + // Wake the command thread to process commands: + commandThread.interrupt(); + + // return the new source name. + return sourcename; + } + +/** + * Move a source to the specified location. + * @param sourcename Identifier for the source. + * @param x destination X coordinate. + * @param y destination Y coordinate. + * @param z destination Z coordinate. + */ + public void setPosition( String sourcename, float x, float y, float z ) + { + CommandQueue( new CommandObject( CommandObject.SET_POSITION, + sourcename, x, y, z ) ); + commandThread.interrupt(); + } +/** + * Manually sets the specified source's volume. + * @param sourcename Source to move. + * @param value New volume, float value ( 0.0f - 1.0f ). + */ + public void setVolume( String sourcename, float value ) + { + CommandQueue( new CommandObject( CommandObject.SET_VOLUME, + sourcename, value ) ); + commandThread.interrupt(); + } + +/** + * Returns the current volume of the specified source, or zero if the specified + * source was not found. + * @param sourcename Source to read volume from. + * @return Float value representing the source volume (0.0f - 1.0f). + */ + public float getVolume( String sourcename ) + { + synchronized( SoundSystemConfig.THREAD_SYNC ) + { + if( soundLibrary != null ) + return soundLibrary.getVolume( sourcename ); + else + return 0.0f; + } + } + +/** + * Manually sets the specified source's pitch. + * @param sourcename The source's name. + * @param value A float value ( 0.5f - 2.0f ). + */ + public void setPitch( String sourcename, float value ) + { + CommandQueue( new CommandObject( CommandObject.SET_PITCH, + sourcename, value ) ); + commandThread.interrupt(); + } + +/** + * Returns the pitch of the specified source. + * @param sourcename The source's name. + * @return Float value representing the source pitch (0.5f - 2.0f). + */ + public float getPitch( String sourcename ) + { + if( soundLibrary != null ) + return soundLibrary.getPitch( sourcename ); + else + return 1.0f; + } + +/** + * Set a source's priority factor. A priority source will not be overriden when + * too many sources are playing at once. + * @param sourcename Identifier for the source. + * @param pri Setting this to true makes this source a priority source. + */ + public void setPriority( String sourcename, boolean pri ) + { + CommandQueue( new CommandObject( CommandObject.SET_PRIORITY, + sourcename, pri ) ); + commandThread.interrupt(); + } +/** + * Changes a source to looping or non-looping. + * @param sourcename Identifier for the source. + * @param lp This source should loop. + */ + public void setLooping( String sourcename, boolean lp ) + { + CommandQueue( new CommandObject( CommandObject.SET_LOOPING, + sourcename, lp ) ); + commandThread.interrupt(); + } +/** + * Changes a source's attenuation model. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more + * information about Attenuation. + * @param sourcename Identifier for the source. + * @param model Attenuation model to use. + */ + public void setAttenuation( String sourcename, int model ) + { + CommandQueue( new CommandObject( CommandObject.SET_ATTENUATION, + sourcename, model ) ); + commandThread.interrupt(); + } +/** + * Changes a source's fade distance or rolloff factor. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more + * information about fade distance and rolloff. + * @param sourcename Identifier for the source. + * @param dr Either the fading distance or rolloff factor, depending on the attenuation model used. + */ + public void setDistOrRoll( String sourcename, float dr) + { + CommandQueue( new CommandObject( CommandObject.SET_DIST_OR_ROLL, + sourcename, dr ) ); + commandThread.interrupt(); + } + +/** + * Changes the Doppler factor, for determining Doppler effect scale. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more + * information about Doppler effect. + * @param dopplerFactor New value for Doppler factor. + */ + public void changeDopplerFactor( float dopplerFactor) + { + CommandQueue( new CommandObject( CommandObject.CHANGE_DOPPLER_FACTOR, + dopplerFactor ) ); + commandThread.interrupt(); + } + +/** + * Changes the Doppler velocity, for use in Doppler effect. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more + * information about Doppler effect. + * @param dopplerVelocity New value for Doppler velocity. + */ + public void changeDopplerVelocity( float dopplerVelocity ) + { + CommandQueue( new CommandObject( CommandObject.CHANGE_DOPPLER_VELOCITY, + dopplerVelocity ) ); + commandThread.interrupt(); + } + +/** + * Sets the specified source's velocity, for use in Doppler effect. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more + * information about Doppler effect. + * @param sourcename The source's name. + * @param x Velocity along world x-axis. + * @param y Velocity along world y-axis. + * @param z Velocity along world z-axis. + */ + public void setVelocity( String sourcename, float x, float y, float z ) + { + CommandQueue( new CommandObject( CommandObject.SET_VELOCITY, + sourcename, x, y, z ) ); + commandThread.interrupt(); + } + +/** + * Sets the listener's velocity, for use in Doppler effect. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more + * information about Doppler effect. + * @param x Velocity along world x-axis. + * @param y Velocity along world y-axis. + * @param z Velocity along world z-axis. + */ + public void setListenerVelocity( float x, float y, float z ) + { + CommandQueue( new CommandObject( CommandObject.SET_LISTENER_VELOCITY, + x, y, z ) ); + commandThread.interrupt(); + } + +/** + * Returns the number of miliseconds since the specified source began playing. + * @return miliseconds, or -1 if not playing or unable to calculate + */ + public float millisecondsPlayed( String sourcename ) + { + synchronized( SoundSystemConfig.THREAD_SYNC ) + { + return soundLibrary.millisecondsPlayed( sourcename ); + } + } + +/** + * Feeds raw data through the specified source. The source must be a + * streaming source and it can not be already associated with a file or URL to + * stream from. Only use this for streaming sources created with the + * rawDataStream() method. NOTE: Be carefull how much data you send to a + * source to stream. The data will be processed at playback speed, so if you + * queue up 1 hour worth of data, it will take 1 hour to play (not to mention + * hogging a ton of memory). To clear out all queued data from the source, use + * the flush() method. Also note: if there is a break in the data stream, + * you will hear clicks and studders, so ensure that the data flow is steady. + * @param sourcename Name of the streaming source to play from. + * @param buffer Byte buffer containing raw audio data to stream. + */ + public void feedRawAudioData( String sourcename, byte[] buffer ) + { + CommandQueue( new CommandObject( CommandObject.FEED_RAW_AUDIO_DATA, + sourcename, buffer ) ); + commandThread.interrupt(); + } +/** + * Plays the specified source. + * @param sourcename Identifier for the source. + */ + public void play( String sourcename ) + { + CommandQueue( new CommandObject( CommandObject.PLAY, sourcename) ); + commandThread.interrupt(); + } +/** + * Pauses the specified source. + * @param sourcename Identifier for the source. + */ + public void pause( String sourcename ) + { + CommandQueue( new CommandObject( CommandObject.PAUSE, sourcename) ); + commandThread.interrupt(); + } +/** + * Stops the specified source. + * @param sourcename Identifier for the source. + */ + public void stop( String sourcename ) + { + CommandQueue( new CommandObject( CommandObject.STOP, sourcename) ); + commandThread.interrupt(); + } +/** + * Rewinds the specified source. + * @param sourcename Identifier for the source. + */ + public void rewind( String sourcename ) + { + CommandQueue( new CommandObject( CommandObject.REWIND, sourcename) ); + commandThread.interrupt(); + } +/** + * Flushes all previously queued audio data from a streaming source. + * @param sourcename Identifier for the source. + */ + public void flush( String sourcename ) + { + CommandQueue( new CommandObject( CommandObject.FLUSH, sourcename) ); + commandThread.interrupt(); + } + +/** + * Culls the specified source. A culled source can not be played until it has + * been activated again. + * @param sourcename Identifier for the source. + */ + public void cull( String sourcename ) + { + CommandQueue( new CommandObject( CommandObject.CULL, sourcename) ); + commandThread.interrupt(); + } + +/** + * Activates the specified source after it was culled, so it can be played + * again. + * @param sourcename Identifier for the source. + */ + public void activate( String sourcename ) + { + CommandQueue( new CommandObject( CommandObject.ACTIVATE, sourcename) ); + commandThread.interrupt(); + } + +/** + * Sets a flag for a source indicating whether it should be used or if it + * should be removed after it finishes playing. One possible use for this + * method is to make temporary sources that were created with quickPlay() + * permanant. Another use could be to have a source automatically removed + * after it finishes playing. NOTE: Setting a source to temporary does not + * stop it, and setting a source to permanant does not play it. It is also + * important to note that a looping temporary source will not be removed as + * long as it keeps playing. + * @param sourcename Identifier for the source. + * @param temporary True = temporary, False = permanant. + */ + public void setTemporary( String sourcename, boolean temporary ) + { + CommandQueue( new CommandObject( CommandObject.SET_TEMPORARY, + sourcename, temporary ) ); + commandThread.interrupt(); + } + +/** + * Removes the specified source and clears up any memory it used. + * @param sourcename Identifier for the source. + */ + public void removeSource( String sourcename ) + { + CommandQueue( new CommandObject( CommandObject.REMOVE_SOURCE, + sourcename ) ); + commandThread.interrupt(); + } +/** + * Moves the listener relative to the current location. + * @param x X offset. + * @param y Y offset. + * @param z Z offset. + */ + public void moveListener( float x, float y, float z ) + { + CommandQueue( new CommandObject( CommandObject.MOVE_LISTENER, + x, y, z ) ); + commandThread.interrupt(); + } +/** + * Moves the listener to the specified location. + * @param x Destination X coordinate. + * @param y Destination Y coordinate. + * @param z Destination Z coordinate. + */ + public void setListenerPosition( float x, float y, float z ) + { + CommandQueue( new CommandObject( CommandObject.SET_LISTENER_POSITION, + x, y, z ) ); + commandThread.interrupt(); + } +/** + * Turns the listener counterclockwise by "angle" radians around the y-axis, + * relative to the current angle. + * @param angle radian offset. + */ + public void turnListener( float angle ) + { + CommandQueue( new CommandObject( CommandObject.TURN_LISTENER, + angle ) ); + commandThread.interrupt(); + } +/** + * Sets the listener's angle in radians around the y-axis. + * @param angle radians. + */ + public void setListenerAngle( float angle ) + { + CommandQueue( new CommandObject( CommandObject.SET_LISTENER_ANGLE, + angle ) ); + commandThread.interrupt(); + } +/** + * Sets the listener's orientation. + * @param lookX X coordinate of the (normalized) look-at vector. + * @param lookY Y coordinate of the (normalized) look-at vector. + * @param lookZ Z coordinate of the (normalized) look-at vector. + * @param upX X coordinate of the (normalized) up-direction vector. + * @param upY Y coordinate of the (normalized) up-direction vector. + * @param upZ Z coordinate of the (normalized) up-direction vector. + */ + public void setListenerOrientation( float lookX, float lookY, float lookZ, + float upX, float upY, float upZ ) + { + CommandQueue( new CommandObject( CommandObject.SET_LISTENER_ORIENTATION, + lookX, lookY, lookZ, upX, upY, upZ ) ); + commandThread.interrupt(); + } + +/** + * Sets the overall volume, affecting all sources. + * @param value New volume, float value ( 0.0f - 1.0f ). + */ + public void setMasterVolume( float value ) + { + CommandQueue( new CommandObject( CommandObject.SET_MASTER_VOLUME, + value ) ); + commandThread.interrupt(); + } + +/** + * Returns the overall volume, affecting all sources. + * @return Float value representing the master volume (0.0f - 1.0f). + */ + public float getMasterVolume() + { + return SoundSystemConfig.getMasterGain(); + } + +/** + * Method for obtaining information about the listener's position and + * orientation. + * @return a {@link paulscode.sound.ListenerData ListenerData} object. + */ + public ListenerData getListenerData() + { + synchronized( SoundSystemConfig.THREAD_SYNC ) + { + return soundLibrary.getListenerData(); + } + } +/** + * Switches to the specified library, and preserves all sources. + * @param libraryClass Library to use. + * @return True if switch was successful. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for + * information about chosing a sound library. + */ + public boolean switchLibrary( Class libraryClass ) + throws SoundSystemException + { + synchronized( SoundSystemConfig.THREAD_SYNC ) + { + initialized( SET, false ); + + HashMap sourceMap = null; + ListenerData listenerData = null; + + boolean wasMidiChannel = false; + MidiChannel midiChannel = null; + FilenameURL midiFilenameURL = null; + String midiSourcename = ""; + boolean midiToLoop = true; + + if( soundLibrary != null ) + { + currentLibrary( SET, null ); + sourceMap = copySources( soundLibrary.getSources() ); + listenerData = soundLibrary.getListenerData(); + midiChannel = soundLibrary.getMidiChannel(); + if( midiChannel != null ) + { + wasMidiChannel = true; + midiToLoop = midiChannel.getLooping(); + midiSourcename = midiChannel.getSourcename(); + midiFilenameURL = midiChannel.getFilenameURL(); + } + + soundLibrary.cleanup(); + soundLibrary = null; + } + message( "", 0 ); + message( "Switching to " + + SoundSystemConfig.getLibraryTitle( libraryClass ), 0 ); + message( "(" + SoundSystemConfig.getLibraryDescription( libraryClass ) + + ")", 1 ); + + try + { + soundLibrary = (Library) libraryClass.newInstance(); + } + catch( InstantiationException ie ) + { + errorMessage( "The specified library did not load properly", 1 ); + } + catch( IllegalAccessException iae ) + { + errorMessage( "The specified library did not load properly", 1 ); + } + catch( ExceptionInInitializerError eiie ) + { + errorMessage( "The specified library did not load properly", 1 ); + } + catch( SecurityException se ) + { + errorMessage( "The specified library did not load properly", 1 ); + } + + if( errorCheck( soundLibrary == null, "Library null after " + + "initialization in method 'switchLibrary'", 1 ) ) + { + SoundSystemException sse = new SoundSystemException( + className + " did not load properly. " + + "Library was null after initialization.", + SoundSystemException.LIBRARY_NULL ); + lastException( SET, sse ); + initialized( SET, true ); + throw sse; + } + + try + { + soundLibrary.init(); + } + catch( SoundSystemException sse ) + { + lastException( SET, sse ); + initialized( SET, true ); + throw sse; + } + + soundLibrary.setListenerData( listenerData ); + if( wasMidiChannel ) + { + if( midiChannel != null ) + midiChannel.cleanup(); + midiChannel = new MidiChannel( midiToLoop, midiSourcename, + midiFilenameURL ); + soundLibrary.setMidiChannel( midiChannel ); + } + soundLibrary.copySources( sourceMap ); + + message( "", 0 ); + + lastException( SET, null ); + initialized( SET, true ); + + return true; + } + } + +/** + * Switches to the specified library, loosing all sources. + * @param libraryClass Library to use. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for + * information about chosing a sound library. + */ + public boolean newLibrary( Class libraryClass ) + throws SoundSystemException + { + initialized( SET, false ); + + CommandQueue( new CommandObject( CommandObject.NEW_LIBRARY, + libraryClass ) ); + commandThread.interrupt(); + + for( int x = 0; (!initialized( GET, XXX )) && (x < 100); x++ ) + { + snooze( 400 ); + commandThread.interrupt(); + } + + if( !initialized( GET, XXX ) ) + { + SoundSystemException sse = new SoundSystemException( + className + + " did not load after 30 seconds.", + SoundSystemException.LIBRARY_NULL ); + lastException( SET, sse ); + throw sse; + } + else + { + SoundSystemException sse = lastException( GET, null ); + if( sse != null ) + throw sse; + } + return true; + } + +/** + * Switches to the specified library, loosing all sources. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the newLibrary() method instead. + * @param libraryClass Library to use. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for + * information about chosing a sound library. + */ + private void CommandNewLibrary( Class libraryClass ) + { + initialized( SET, false ); + + String headerMessage = "Initializing "; + if( soundLibrary != null ) + { + currentLibrary( SET, null ); + // we are switching libraries + headerMessage = "Switching to "; + soundLibrary.cleanup(); + soundLibrary = null; + } + message( headerMessage + + SoundSystemConfig.getLibraryTitle( libraryClass ), 0 ); + message( "(" + SoundSystemConfig.getLibraryDescription( libraryClass ) + + ")", 1 ); + + try + { + soundLibrary = (Library) libraryClass.newInstance(); + } + catch( InstantiationException ie ) + { + errorMessage( "The specified library did not load properly", 1 ); + } + catch( IllegalAccessException iae ) + { + errorMessage( "The specified library did not load properly", 1 ); + } + catch( ExceptionInInitializerError eiie ) + { + errorMessage( "The specified library did not load properly", 1 ); + } + catch( SecurityException se ) + { + errorMessage( "The specified library did not load properly", 1 ); + } + + if( errorCheck( soundLibrary == null, "Library null after " + + "initialization in method 'newLibrary'", 1 ) ) + { + lastException( SET, new SoundSystemException( + className + " did not load properly. " + + "Library was null after initialization.", + SoundSystemException.LIBRARY_NULL ) ); + importantMessage( "Switching to silent mode", 1 ); + + try + { + soundLibrary = new Library(); + } + catch( SoundSystemException sse ) + { + lastException( SET, new SoundSystemException( + "Silent mode did not load properly. " + + "Library was null after initialization.", + SoundSystemException.LIBRARY_NULL ) ); + initialized( SET, true ); + return; + } + } + + try + { + soundLibrary.init(); + } + catch( SoundSystemException sse ) + { + lastException( SET, sse ); + initialized( SET, true ); + return; + } + + lastException( SET, null ); + initialized( SET, true ); + + return; + } +/** + * Calls the library's initialize() method. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly. + */ + private void CommandInitialize() + { + try + { + if( errorCheck( soundLibrary == null, "Library null after " + + "initialization in method 'CommandInitialize'", + 1 ) ) + { + SoundSystemException sse = new SoundSystemException( + className + " did not load properly. " + + "Library was null after initialization.", + SoundSystemException.LIBRARY_NULL ); + lastException( SET, sse ); + throw sse; + } + soundLibrary.init(); + } + catch( SoundSystemException sse ) + { + lastException( SET, sse ); + initialized( SET, true ); + } + } +/** + * Loads sample data from a sound file or URL into memory. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the loadSound() method instead. + * @param filenameURL Filename/URL of the sound file to load. + */ + private void CommandLoadSound( FilenameURL filenameURL ) + { + if( soundLibrary != null ) + soundLibrary.loadSound( filenameURL ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandLoadSound'", 0 ); + } +/** + * Saves the specified sample data, under the specified identifier. This + * identifier can be later used in place of 'filename' parameters to reference + * the sample data. This method is used internally by SoundSystem for thread + * synchronization, and it can not be called directly - please use the + * loadSound() method instead. + * @param buffer the sample data and audio format to save. + * @param identifier What to call the sample. + */ + private void CommandLoadSound( SoundBuffer buffer, String identifier ) + { + if( soundLibrary != null ) + soundLibrary.loadSound( buffer, identifier ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandLoadSound'", 0 ); + } +/** + * Removes previously loaded sampled data from memory. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the unloadSound() method instead. + * @param filename Filename or string identifyer of sound to unload. + */ + private void CommandUnloadSound( String filename ) + { + if( soundLibrary != null ) + soundLibrary.unloadSound( filename ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandLoadSound'", 0 ); + } +/** + * If the specified source is a streaming source or MIDI source, this method + * queues up the next sound to play when the previous playback ends. This + * method has no effect on non-streaming sources. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the queueSound() method instead. + * @param sourcename Source identifier. + * @param filenameURL Filename/URL of the sound file to play next. + */ + private void CommandQueueSound( String sourcename, + FilenameURL filenameURL ) + { + if( soundLibrary != null ) + soundLibrary.queueSound( sourcename, filenameURL ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandQueueSound'", 0 ); + } +/** + * Removes the first occurrence of the specified filename/identifier from the + * specified source's list of sounds to play when previous playback ends. This + * method has no effect on non-streaming sources. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the dequeueSound() method instead. + * @param sourcename Source identifier. + * @param filename Filename/identifier of the sound file to remove from the queue. + */ + private void CommandDequeueSound( String sourcename, String filename ) + { + if( soundLibrary != null ) + soundLibrary.dequeueSound( sourcename, filename ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandDequeueSound'", 0 ); + } +/** + * Fades out the volume of whatever the specified source is currently playing, + * then begins playing the specified file at the source's previously + * assigned volume level. If the filenameURL parameter is null or empty, the + * specified source will simply fade out and stop. The miliseconds parameter + * must be non-negative or zero. This method will remove anything that is + * currently in the specified source's list of queued sounds that would have + * played next when the current sound finished playing. This method may only + * be used for streaming and MIDI sources. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the fadeOut() method instead. + * @param sourcename Name of the source to fade out. + * @param filenameURL Filename/URL of a sound file to play next, or null for none. + * @param milis Number of miliseconds the fadeout should take. + */ + private void CommandFadeOut( String sourcename, FilenameURL filenameURL, + long milis ) + { + if( soundLibrary != null ) + soundLibrary.fadeOut( sourcename, filenameURL, milis ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandFadeOut'", 0 ); + } +/** + * Fades out the volume of whatever the specified source is currently playing, + * then fades the volume back in playing the specified file. Final volume + * after fade-in completes will be equal to the source's previously assigned + * volume level. The filenameURL parameter may not be null or empty. The + * miliseconds parameters must be non-negative or zero. This method will + * remove anything that is currently in the specified source's list of queued + * sounds that would have played next when the current sound finished playing. + * This method may only be used for streaming and MIDI sources. This method is + * used internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the fadeOutIn() method instead. + * @param sourcename Name of the source to fade out/in. + * @param filenameURL Filename/URL of a sound file to play next, or null for none. + * @param milisOut Number of miliseconds the fadeout should take. + * @param milisIn Number of miliseconds the fadein should take. + */ + private void CommandFadeOutIn( String sourcename, FilenameURL filenameURL, + long milisOut, long milisIn ) + { + if( soundLibrary != null ) + soundLibrary.fadeOutIn( sourcename, filenameURL, milisOut, + milisIn ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandFadeOutIn'", 0 ); + } +/** + * Makes sure the current volume levels of streaming sources and MIDI are + * correct. This method is designed to help reduce the "jerky" fading behavior + * that happens when using some library and codec pluggins (such as + * LibraryJavaSound and CodecJOrbis). This method has no effect on normal + * "non-streaming" sources. It would normally be called somewhere in the main + * "game loop". IMPORTANT: To optimize frame-rates, do not call this method + * for every frame. It is better to just call this method at some acceptable + * "granularity" (play around with different granularities to find what sounds + * acceptable for a particular situation). This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the checkFadeVolumes() method instead. + */ + private void CommandCheckFadeVolumes() + { + if( soundLibrary != null ) + soundLibrary.checkFadeVolumes(); + else + errorMessage( "Variable 'soundLibrary' null in method " + + "'CommandCheckFadeVolumes'", 0 ); + } +/** + * Loads a sound file into memory. This method is used internally by + * SoundSystem for thread synchronization, and it can not be called directly - + * please use the newSource() method instead. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param toStream Whether or not to stream the source. + * @param toLoop Whether or not to loop the source. + * @param sourcename A unique identifier for the source. + * @param filenameURL Filename/URL of the sound file to play at this source. + * @param x X position for this source. + * @param y Y position for this source. + * @param z Z position for this source. + * @param attModel Attenuation model to use. + * @param distORroll Either the fading distance or rolloff factor, depending on the value of "attmodel". + */ + private void CommandNewSource( boolean priority, boolean toStream, + boolean toLoop, String sourcename, + FilenameURL filenameURL, float x, + float y, float z, int attModel, + float distORroll ) + { + if( soundLibrary != null ) + { + if( filenameURL.getFilename().matches( + SoundSystemConfig.EXTENSION_MIDI ) + && !SoundSystemConfig.midiCodec() ) + { + soundLibrary.loadMidi( toLoop, sourcename, filenameURL ); + } + else + { + soundLibrary.newSource( priority, toStream, toLoop, sourcename, + filenameURL, x, y, z, attModel, + distORroll ); + } + } + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandNewSource'", 0 ); + } +/** + * Opens a direct line for streaming audio data. This method is used + * internally by SoundSystem, and it can not be called directly - please use + * the rawDataStream() method instead. + * @param audioFormat Format that the data will be in. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename. + * @param x X position for this source. + * @param y Y position for this source. + * @param z Z position for this source. + * @param attModel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel". + */ + private void CommandRawDataStream( AudioFormat audioFormat, + boolean priority, String sourcename, + float x, float y, float z, + int attModel, float distOrRoll ) + { + if( soundLibrary != null ) + soundLibrary.rawDataStream( audioFormat, priority, sourcename, + x, y, z, attModel, distOrRoll ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandRawDataStream'", 0 ); + } +/** + * Creates a temporary source and either plays or streams it. After the source + * finishes playing, it is removed. This method is used internally by + * SoundSystem for thread synchronization, and it can not be called directly - + * please use the quickPlay() method instead. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param toStream Whether or not to stream the source. + * @param toLoop Whether or not to loop the source. + * @param sourcename A unique identifier for the source. + * @param filenameURL Filename/URL of the sound file to play at this source. + * @param x X position for this source. + * @param y Y position for this source. + * @param z Z position for this source. + * @param attModel Attenuation model to use. + * @param distORroll Either the fading distance or rolloff factor, depending on the value of "attmodel". + * @param temporary Whether or not the source should be removed after it finishes playing. + */ + private void CommandQuickPlay( boolean priority, boolean toStream, + boolean toLoop, String sourcename, + FilenameURL filenameURL, float x, float y, + float z, int attModel, float distORroll, + boolean temporary ) + { + if( soundLibrary != null ) + { + if( filenameURL.getFilename().matches( SoundSystemConfig.EXTENSION_MIDI ) && + !SoundSystemConfig.midiCodec() ) + { + soundLibrary.loadMidi( toLoop, sourcename, filenameURL ); + } + else + { + soundLibrary.quickPlay( priority, toStream, toLoop, sourcename, + filenameURL, x, y, z, attModel, + distORroll, temporary ); + } + } + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandQuickPlay'", 0 ); + } +/** + * Moves a source to the specified coordinates. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the setPosition() method instead. + * @param sourcename Source to move. + * @param x Destination X coordinate. + * @param y Destination Y coordinate. + * @param z Destination Z coordinate. + */ + private void CommandSetPosition( String sourcename, float x, float y, + float z) + { + if( soundLibrary != null ) + soundLibrary.setPosition( sourcename, x, y, z ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandMoveSource'", 0 ); + } +/** + * Manually sets the specified source's volume. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the setVolume() method instead. + * @param sourcename Source to change the volume of. + * @param value New volume, float value ( 0.0f - 1.0f ). + */ + private void CommandSetVolume( String sourcename, float value ) + { + if( soundLibrary != null ) + soundLibrary.setVolume( sourcename, value ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandSetVolume'", 0 ); + } +/** + * Manually sets the specified source's pitch. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the setPitch() method instead. + * @param sourcename Source to change the pitch of. + * @param value New pitch, float value ( 0.5f - 2.0f ). + */ + private void CommandSetPitch( String sourcename, float value ) + { + if( soundLibrary != null ) + soundLibrary.setPitch( sourcename, value ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandSetPitch'", 0 ); + } +/** + * Set a source's priority factor. A priority source will not be overriden when + * too many sources are playing at once. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the setPriority() method instead. + * @param sourcename Identifier for the source. + * @param pri Setting this to true makes this source a priority source. + */ + private void CommandSetPriority( String sourcename, boolean pri ) + { + if( soundLibrary != null ) + soundLibrary.setPriority( sourcename, pri ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandSetPriority'", 0 ); + } +/** + * Changes a source to looping or non-looping. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the setLooping() method instead. + * @param sourcename Identifier for the source. + * @param lp This source should loop. + */ + private void CommandSetLooping( String sourcename, boolean lp ) + { + if( soundLibrary != null ) + soundLibrary.setLooping( sourcename, lp ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandSetLooping'", 0 ); + } +/** + * Changes a source's attenuation model. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the setAttenuation() method instead. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more + * information about Attenuation. + * @param sourcename Identifier for the source. + * @param model Attenuation model to use. + */ + private void CommandSetAttenuation( String sourcename, int model ) + { + if( soundLibrary != null ) + soundLibrary.setAttenuation( sourcename, model ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandSetAttenuation'", + 0 ); + } +/** + * Changes a source's fade distance or rolloff factor. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more + * information about fade distance and rolloff. + * @param sourcename Identifier for the source. + * @param dr Either the fading distance or rolloff factor, depending on the attenuation model used. + */ + private void CommandSetDistOrRoll( String sourcename, float dr ) + { + if( soundLibrary != null ) + soundLibrary.setDistOrRoll( sourcename, dr ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandSetDistOrRoll'", + 0 ); + } +/** + * Changes the Doppler factor. This method is used internally by SoundSystem + * for thread synchronization, and it can not be called directly - please use + * the setDopplerFactor() method instead. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more + * information about Doppler effect. + * @param dopplerFactor New Doppler factor, for determining Doppler effect scale. + */ + private void CommandChangeDopplerFactor( float dopplerFactor ) + { + if( soundLibrary != null ) + { + SoundSystemConfig.setDopplerFactor( dopplerFactor ); + soundLibrary.dopplerChanged(); + } + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandSetDopplerFactor'", + 0 ); + } +/** + * Changes the Doppler velocity. This method is used internally by SoundSystem + * for thread synchronization, and it can not be called directly - please use + * the setDopplerVelocity() method instead. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more + * information about Doppler effect. + * @param dopplerVelocity New Doppler velocity, for use in Doppler effect. + */ + private void CommandChangeDopplerVelocity( float dopplerVelocity ) + { + if( soundLibrary != null ) + { + SoundSystemConfig.setDopplerVelocity( dopplerVelocity ); + soundLibrary.dopplerChanged(); + } + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandSetDopplerFactor'", + 0 ); + } +/** + * Changes a source's velocity, for use in Doppler effect. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the setVelocity() method instead. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more + * information about Doppler effect. + * @param sourcename Identifier for the source. + * @param x Source's velocity along the world x-axis. + * @param y Source's velocity along the world y-axis. + * @param z Source's velocity along the world z-axis. + */ + private void CommandSetVelocity( String sourcename, float x, float y, float z ) + { + if( soundLibrary != null ) + soundLibrary.setVelocity( sourcename, x, y, z ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandVelocity'", + 0 ); + } +/** + * Changes the listener's velocity, for use in Doppler effect. This method is + * used internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the setListenerVelocity() method instead. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more + * information about Doppler effect. + * @param x Velocity along the world x-axis. + * @param y Velocity along the world y-axis. + * @param z Velocity along the world z-axis. + */ + private void CommandSetListenerVelocity( float x, float y, float z ) + { + if( soundLibrary != null ) + soundLibrary.setListenerVelocity( x, y, z ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandSetListenerVelocity'", + 0 ); + } +/** + * Plays the specified source. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the play() method instead. + * @param sourcename Identifier for the source. + */ + private void CommandPlay( String sourcename ) + { + if( soundLibrary != null ) + soundLibrary.play( sourcename ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandPlay'", 0 ); + } +/** + * Feeds raw data through the specified source. The source must be a + * streaming source and it can not be already associated with a file or URL to + * stream from. This method is used internally by SoundSystem for thread + * synchronization, and it can not be called directly - please use the + * feedRawAudioData() method instead. + * @param sourcename Name of the streaming source to play from. + * @param buffer Byte buffer containing raw audio data to stream. + */ + private void CommandFeedRawAudioData( String sourcename, byte[] buffer ) + { + if( soundLibrary != null ) + soundLibrary.feedRawAudioData( sourcename, buffer ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandFeedRawAudioData'", 0 ); + } +/** + * Pauses the specified source. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the pause() method instead. + * @param sourcename Identifier for the source. + */ + private void CommandPause( String sourcename ) + { + if( soundLibrary != null ) + soundLibrary.pause( sourcename ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandPause'", 0 ); + } +/** + * Stops the specified source. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the stop() method instead. + * @param sourcename Identifier for the source. + */ + private void CommandStop( String sourcename ) + { + if( soundLibrary != null ) + soundLibrary.stop( sourcename ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandStop'", 0 ); + } +/** + * Rewinds the specified source. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the rewind() method instead. + * @param sourcename Identifier for the source. + */ + private void CommandRewind( String sourcename ) + { + if( soundLibrary != null ) + soundLibrary.rewind( sourcename ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandRewind'", 0 ); + } +/** + * Flushes all previously queued audio data from a streaming source. This + * method is used internally by SoundSystem for thread synchronization, and it + * can not be called directly - please use the flush() method instead. + * @param sourcename Identifier for the source. + */ + private void CommandFlush( String sourcename ) + { + if( soundLibrary != null ) + soundLibrary.flush( sourcename ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandFlush'", 0 ); + } +/** + * Sets a flag for a source indicating whether it should be used or if it + * should be removed after it finishes playing. One possible use for this + * method is to make temporary sources that were created with quickPlay() + * permanant. Another use could be to have a source automatically removed + * after it finishes playing. NOTE: Setting a source to inactive does not stop + * it, and setting a source to active does not play it. It is also important + * to note that a looping inactive source will not be removed as long as + * it keeps playing. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the setTemporary() method instead. + * @param sourcename Identifier for the source. + * @param temporary True or False. + */ + private void CommandSetTemporary( String sourcename, boolean temporary ) + { + if( soundLibrary != null ) + soundLibrary.setTemporary( sourcename, temporary ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandSetActive'", 0 ); + } +/** + * Removes the specified source and clears up any memory it used. This method + * is used internally by SoundSystem for thread synchronization, and it can not + * be called directly - please use the removeSource() method instead. + * @param sourcename Identifier for the source. + */ + private void CommandRemoveSource( String sourcename ) + { + if( soundLibrary != null ) + soundLibrary.removeSource( sourcename ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandRemoveSource'", 0 ); + } +/** + * Moves the listener relative to the current location. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the moveListener() method instead. + * @param x X offset. + * @param y Y offset. + * @param z Z offset. + */ + private void CommandMoveListener( float x, float y, float z ) + { + if( soundLibrary != null ) + soundLibrary.moveListener( x, y, z ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandMoveListener'", 0 ); + } + /** + * Moves the listener to the specified location. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the setListenerPosition() method instead. + * @param x Destination X coordinate. + * @param y Destination Y coordinate. + * @param z Destination Z coordinate. + */ + private void CommandSetListenerPosition( float x, float y, float z ) + { + if( soundLibrary != null ) + soundLibrary.setListenerPosition( x, y, z ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandSetListenerPosition'", + 0 ); + } +/** + * Turns the listener counterclockwise by "angle" radians around the y-axis, + * relative to the current angle. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the turnListener() method instead. + * @param angle radian offset. + */ + private void CommandTurnListener( float angle ) + { + if( soundLibrary != null ) + soundLibrary.turnListener( angle ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandTurnListener'", + 0 ); + } +/** + * Sets the listener's angle in radians around the y-axis. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the setListenerAngle() method instead. + * @param angle radians. + */ + private void CommandSetListenerAngle( float angle ) + { + if( soundLibrary != null ) + soundLibrary.setListenerAngle( angle ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandSetListenerAngle'", + 0 ); + } +/** + * Sets the listener's orientation. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the setListenerOrientation() method instead. + * @param lookX X coordinate of the (normalized) look-at vector. + * @param lookY Y coordinate of the (normalized) look-at vector. + * @param lookZ Z coordinate of the (normalized) look-at vector. + * @param upX X coordinate of the (normalized) look-at vector. + * @param upY Y coordinate of the (normalized) look-at vector. + * @param upZ Z coordinate of the (normalized) look-at vector. + */ + private void CommandSetListenerOrientation( float lookX, float lookY, + float lookZ, float upX, + float upY, float upZ ) + { + if( soundLibrary != null ) + soundLibrary.setListenerOrientation( lookX, lookY, lookZ, upX, upY, + upZ ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandSetListenerOrientation'", + 0 ); + } +/** + * Culls the specified source. A culled source can not be played until it has + * been activated again. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the cull() method instead. + * @param sourcename Identifier for the source. + */ + private void CommandCull( String sourcename ) + { + if( soundLibrary != null ) + soundLibrary.cull( sourcename ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandCull'", 0 ); + } +/** + * Activates a previously culled source, so it can be played again. This + * method is used internally by SoundSystem for thread synchronization, and it + * can not be called directly - please use the activate() method instead. + * @param sourcename Identifier for the source. + */ + private void CommandActivate( String sourcename ) + { + if( soundLibrary != null ) + soundLibrary.activate( sourcename ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandActivate'", + 0 ); + } +/** + * Sets the overall volume, affecting all sources. This method is used + * internally by SoundSystem for thread synchronization, and it can not be + * called directly - please use the setMasterVolume() method instead. + * @param value New volume, float value ( 0.0f - 1.0f ). + */ + private void CommandSetMasterVolume( float value ) + { + if( soundLibrary != null ) + soundLibrary.setMasterVolume( value ); + else + errorMessage( + "Variable 'soundLibrary' null in method 'CommandSetMasterVolume'", + 0 ); + } + +/** + * This method can be overridden by extended classes to be used for source + * management (culling and activating sources based on established rules). One + * possible use for this method is sorting sources by distance, culling the + * furthest, and activating the closest. + * This method is automatically called on the CommandThread before processing + * queued commands, so you do not need to call it anywhere else. Note: use + * methods cull() and activate() here, NOT CommandCull() and CommandActivate() + * (thread safety issue). + * IMPORTANT: Always use synchronized( SoundSystemConfig.THREAD_SYNC ) when + * manually manipulating sources from outside the Command Thread! + */ + protected void ManageSources() + { + // OVERRIDDEN METHODS MUST USE THIS: + + /******* + synchronized( SoundSystemConfig.THREAD_SYNC ) + { + // TODO: Sort the sources, cull and activate, etc. + } + ********/ + } + +/** + * Queues a command. + * If newCommand is null, all commands are dequeued and executed. + * This is automatically used by the sound system, so it is not + * likely that a user would ever need to use this method. + * See {@link paulscode.sound.CommandObject CommandObject} for more information + * about commands. + * @param newCommand Command to queue, or null to execute commands. + * @return True if more commands exist, false if queue is empty. + */ + public boolean CommandQueue( CommandObject newCommand ) + { + synchronized( SoundSystemConfig.THREAD_SYNC ) + { + if( newCommand == null ) + { + // New command is null - that means execute all queued commands. + boolean activations = false; + CommandObject commandObject; + + // Loop through the command queue: + while( commandQueue != null && commandQueue.size() > 0 ) + { + // Grab the oldest command in the queue: + commandObject = commandQueue.remove( 0 ); + // See what it is, and execute the proper Command method: + if( commandObject != null ) + { + switch( commandObject.Command ) + { + case CommandObject.INITIALIZE: + CommandInitialize(); + break; + case CommandObject.LOAD_SOUND: + CommandLoadSound( + (FilenameURL) commandObject.objectArgs[0] ); + break; + case CommandObject.LOAD_DATA: + CommandLoadSound( + (SoundBuffer) commandObject.objectArgs[0], + commandObject.stringArgs[0] ); + break; + case CommandObject.UNLOAD_SOUND: + CommandUnloadSound( commandObject.stringArgs[0] ); + break; + case CommandObject.QUEUE_SOUND: + CommandQueueSound( commandObject.stringArgs[0], + (FilenameURL) commandObject.objectArgs[0] ); + break; + case CommandObject.DEQUEUE_SOUND: + CommandDequeueSound( commandObject.stringArgs[0], + commandObject.stringArgs[1] ); + break; + case CommandObject.FADE_OUT: + CommandFadeOut( commandObject.stringArgs[0], + (FilenameURL) commandObject.objectArgs[0], + commandObject.longArgs[0] ); + break; + case CommandObject.FADE_OUT_IN: + CommandFadeOutIn( commandObject.stringArgs[0], + (FilenameURL) commandObject.objectArgs[0], + commandObject.longArgs[0], + commandObject.longArgs[1] ); + break; + case CommandObject.CHECK_FADE_VOLUMES: + CommandCheckFadeVolumes(); + break; + case CommandObject.NEW_SOURCE: + CommandNewSource( commandObject.boolArgs[0], + commandObject.boolArgs[1], + commandObject.boolArgs[2], + commandObject.stringArgs[0], + (FilenameURL) commandObject.objectArgs[0], + commandObject.floatArgs[0], + commandObject.floatArgs[1], + commandObject.floatArgs[2], + commandObject.intArgs[0], + commandObject.floatArgs[3] ); + break; + case CommandObject.RAW_DATA_STREAM: + CommandRawDataStream( + (AudioFormat) commandObject.objectArgs[0], + commandObject.boolArgs[0], + commandObject.stringArgs[0], + commandObject.floatArgs[0], + commandObject.floatArgs[1], + commandObject.floatArgs[2], + commandObject.intArgs[0], + commandObject.floatArgs[3] ); + break; + case CommandObject.QUICK_PLAY: + CommandQuickPlay( commandObject.boolArgs[0], + commandObject.boolArgs[1], + commandObject.boolArgs[2], + commandObject.stringArgs[0], + (FilenameURL) commandObject.objectArgs[0], + commandObject.floatArgs[0], + commandObject.floatArgs[1], + commandObject.floatArgs[2], + commandObject.intArgs[0], + commandObject.floatArgs[3], + commandObject.boolArgs[3] ); + break; + case CommandObject.SET_POSITION: + CommandSetPosition( commandObject.stringArgs[0], + commandObject.floatArgs[0], + commandObject.floatArgs[1], + commandObject.floatArgs[2] ); + break; + case CommandObject.SET_VOLUME: + CommandSetVolume( commandObject.stringArgs[0], + commandObject.floatArgs[0] ); + break; + case CommandObject.SET_PITCH: + CommandSetPitch( commandObject.stringArgs[0], + commandObject.floatArgs[0] ); + break; + case CommandObject.SET_PRIORITY: + CommandSetPriority( commandObject.stringArgs[0], + commandObject.boolArgs[0] ); + break; + case CommandObject.SET_LOOPING: + CommandSetLooping( commandObject.stringArgs[0], + commandObject.boolArgs[0] ); + break; + case CommandObject.SET_ATTENUATION: + CommandSetAttenuation( commandObject.stringArgs[0], + commandObject.intArgs[0] ); + break; + case CommandObject.SET_DIST_OR_ROLL: + CommandSetDistOrRoll( commandObject.stringArgs[0], + commandObject.floatArgs[0] ); + break; + case CommandObject.CHANGE_DOPPLER_FACTOR: + CommandChangeDopplerFactor( + commandObject.floatArgs[0] ); + break; + case CommandObject.CHANGE_DOPPLER_VELOCITY: + CommandChangeDopplerVelocity( + commandObject.floatArgs[0] ); + break; + case CommandObject.SET_VELOCITY: + CommandSetVelocity( commandObject.stringArgs[0], + commandObject.floatArgs[0], + commandObject.floatArgs[1], + commandObject.floatArgs[2] + ); + break; + case CommandObject.SET_LISTENER_VELOCITY: + CommandSetListenerVelocity( + commandObject.floatArgs[0], + commandObject.floatArgs[1], + commandObject.floatArgs[2] + ); + break; + // Methods related to playing sources must be processed + // after cull/activate commands in order for source + // management to work properly, so save them for + // later: + //------------------------------------------------------ + case CommandObject.PLAY: + sourcePlayList.add( commandObject ); + break; + case CommandObject.FEED_RAW_AUDIO_DATA: + sourcePlayList.add( commandObject ); + break; + //------------------------------------------------------ + case CommandObject.PAUSE: + CommandPause( commandObject.stringArgs[0] ); + break; + case CommandObject.STOP: + CommandStop( commandObject.stringArgs[0] ); + break; + case CommandObject.REWIND: + CommandRewind( commandObject.stringArgs[0] ); + break; + case CommandObject.FLUSH: + CommandFlush( commandObject.stringArgs[0] ); + break; + case CommandObject.CULL: + CommandCull( commandObject.stringArgs[0] ); + break; + case CommandObject.ACTIVATE: + activations = true; + CommandActivate( commandObject.stringArgs[0] ); + break; + case CommandObject.SET_TEMPORARY: + CommandSetTemporary( commandObject.stringArgs[0], + commandObject.boolArgs[0] ); + break; + case CommandObject.REMOVE_SOURCE: + CommandRemoveSource( commandObject.stringArgs[0] ); + break; + case CommandObject.MOVE_LISTENER: + CommandMoveListener( commandObject.floatArgs[0], + commandObject.floatArgs[1], + commandObject.floatArgs[2]); + break; + case CommandObject.SET_LISTENER_POSITION: + CommandSetListenerPosition( + commandObject.floatArgs[0], + commandObject.floatArgs[1], + commandObject.floatArgs[2]); + break; + case CommandObject.TURN_LISTENER: + CommandTurnListener( commandObject.floatArgs[0] ); + break; + case CommandObject.SET_LISTENER_ANGLE: + CommandSetListenerAngle( + commandObject.floatArgs[0]); + break; + case CommandObject.SET_LISTENER_ORIENTATION: + CommandSetListenerOrientation( + commandObject.floatArgs[0], + commandObject.floatArgs[1], + commandObject.floatArgs[2], + commandObject.floatArgs[3], + commandObject.floatArgs[4], + commandObject.floatArgs[5]); + break; + case CommandObject.SET_MASTER_VOLUME: + CommandSetMasterVolume( + commandObject.floatArgs[0] ); + break; + case CommandObject.NEW_LIBRARY: + CommandNewLibrary( commandObject.classArgs[0] ); + break; + // If we don't recognize the command, just skip it: + default: + break; + } + } + } + + // If any sources were reactivated, check if they need to be + // replayed: + if( activations ) + soundLibrary.replaySources(); + + // Now that we have the correct sources culled and activated, we + // can start playing sources. Loop through the playlist and + // execute the commands: + while( sourcePlayList != null && sourcePlayList.size() > 0 ) + { + // Grab the oldest command in the queue: + commandObject = sourcePlayList.remove( 0 ); + if( commandObject != null ) + { + // See what it is, and execute the proper Command method: + switch( commandObject.Command ) + { + case CommandObject.PLAY: + CommandPlay( commandObject.stringArgs[0] ); + break; + case CommandObject.FEED_RAW_AUDIO_DATA: + CommandFeedRawAudioData( + commandObject.stringArgs[0], + commandObject.buffer ); + break; + } + } + } + + return( commandQueue != null && commandQueue.size() > 0 ); + } + else + { + // make sure the commandQueue exists: + if( commandQueue == null ) + return false; + // queue a new command + commandQueue.add( newCommand ); + // Of course there is something in the list now, since we just + // added it: + return true; + } + } + } + +/** + * Searches for and removes any temporary sources that have finished + * playing. This method is used internally by SoundSystem, and it is + * unlikely that the user will ever need to use it. + */ + public void removeTemporarySources() + { + synchronized( SoundSystemConfig.THREAD_SYNC ) + { + if( soundLibrary != null ) + soundLibrary.removeTemporarySources(); + } + } + +/** + * Returns true if the specified source is playing. + * @param sourcename Unique identifier of the source to check. + * @return True or false. + */ + public boolean playing( String sourcename ) + { + synchronized( SoundSystemConfig.THREAD_SYNC ) + { + if( soundLibrary == null ) + return false; + + Source src = soundLibrary.getSources().get( sourcename ); + + if( src == null ) + return false; + + return src.playing(); + } + } + +/** + * Returns true if anything is currently playing. + * @return True or false. + */ + public boolean playing() + { + synchronized( SoundSystemConfig.THREAD_SYNC ) + { + if( soundLibrary == null ) + return false; + + HashMap sourceMap = soundLibrary.getSources(); + if( sourceMap == null ) + return false; + + Set keys = sourceMap.keySet(); + Iterator iter = keys.iterator(); + String sourcename; + Source source; + + while( iter.hasNext() ) + { + sourcename = iter.next(); + source = sourceMap.get( sourcename ); + if( source != null ) + if( source.playing() ) + return true; + } + + return false; + } + } + +/** + * Copies and returns the peripheral information from a map of sources. This + * method is used internally by SoundSystem, and it is unlikely that the user + * will ever need to use it. + * @param sourceMap Sources to copy. + * @return New map of sources. + */ + private HashMap copySources( HashMap sourceMap ) + { + Set keys = sourceMap.keySet(); + Iterator iter = keys.iterator(); + String sourcename; + Source source; + + // New map of generic source data: + HashMap returnMap = new HashMap(); + + + // loop through and store information from all the sources: + while( iter.hasNext() ) + { + sourcename = iter.next(); + source = sourceMap.get( sourcename ); + if( source != null ) + returnMap.put( sourcename, new Source( source, null ) ); + } + return returnMap; + } + +/** + * Checks if the specified library type is compatible. + * @param libraryClass Libary type to check. + * @return True or false. + */ + public static boolean libraryCompatible( Class libraryClass ) + { + // create the message logger: + SoundSystemLogger logger = SoundSystemConfig.getLogger(); + // if the user didn't create one, then do it now: + if( logger == null ) + { + logger = new SoundSystemLogger(); + SoundSystemConfig.setLogger( logger ); + } + logger.message( "", 0 ); + logger.message( "Checking if " + + SoundSystemConfig.getLibraryTitle( libraryClass ) + + " is compatible...", 0 ); + + boolean comp = SoundSystemConfig.libraryCompatible( libraryClass ); + + if( comp ) + logger.message( "...yes", 1 ); + else + logger.message( "...no", 1 ); + + return comp; + } + +/** + * Returns the currently loaded library, or -1 if none. + * @return Global library identifier + */ + public static Class currentLibrary() + { + return( currentLibrary( GET, null ) ); + } + +/** + * Returns false if a sound library is busy initializing. + * @return True or false. + */ + public static boolean initialized() + { + return( initialized( GET, XXX ) ); + } + +/** + * Returns the last SoundSystemException thrown, or null if none. + * @return The last exception. + */ + public static SoundSystemException getLastException() + { + return( lastException( GET, null ) ); + } + +/** + * Stores a SoundSystemException which can be retreived later with the + * 'getLastException' method. + * @param e Exception to store. + */ + public static void setException( SoundSystemException e ) + { + lastException( SET, e ); + } + +/** + * Sets or returns the value of boolean 'initialized'. + * @param action Action to perform (GET or SET). + * @param value New value if action is SET, otherwise XXX. + * @return value of boolean 'initialized'. + */ + private static boolean initialized( boolean action, boolean value ) + { + synchronized( SoundSystemConfig.THREAD_SYNC ) + { + if( action == SET ) + initialized = value; + return initialized; + } + } + +/** + * Sets or returns the value of boolean 'initialized'. + * @param action Action to perform (GET or SET). + * @param value New value if action is SET, otherwise XXX. + * @return value of boolean 'initialized'. + */ + private static Class currentLibrary( boolean action, + Class value ) + { + synchronized( SoundSystemConfig.THREAD_SYNC ) + { + if( action == SET ) + currentLibrary = value; + return currentLibrary; + } + } + +/** + * Sets or returns the error code for the last error that occurred. If no + * errors have occurred, returns SoundSystem.ERROR_NONE + * @param action Action to perform (GET or SET). + * @param e New exception if action is SET, otherwise XXX. + * @return Last SoundSystemException thrown. + */ + private static SoundSystemException lastException( boolean action, + SoundSystemException e ) + { + synchronized( SoundSystemConfig.THREAD_SYNC ) + { + if( action == SET ) + lastException = e; + return lastException; + } + } + +/** + * Sleeps for the specified number of milliseconds. + */ + protected static void snooze( long milliseconds ) + { + try + { + Thread.sleep( milliseconds ); + } + catch( InterruptedException e ){} + } + +/** + * Prints a message. + * @param message Message to print. + * @param indent Number of tabs to indent the message. + */ + protected void message( String message, int indent ) + { + logger.message( message, indent ); + } + +/** + * Prints an important message. + * @param message Message to print. + * @param indent Number of tabs to indent the message. + */ + protected void importantMessage( String message, int indent ) + { + logger.importantMessage( message, indent ); + } + +/** + * Prints the specified message if error is true. + * @param error True or False. + * @param message Message to print if error is true. + * @param indent Number of tabs to indent the message. + * @return True if error is true. + */ + protected boolean errorCheck( boolean error, String message, int indent ) + { + return logger.errorCheck( error, className, message, indent ); + } + +/** + * Prints an error message. + * @param message Message to print. + * @param indent Number of tabs to indent the message. + */ + protected void errorMessage( String message, int indent ) + { + logger.errorMessage( className, message, indent ); + } +} diff --git a/src/lwjgl/java/paulscode/sound/SoundSystemConfig.java b/src/lwjgl/java/paulscode/sound/SoundSystemConfig.java new file mode 100644 index 0000000..d5efbc0 --- /dev/null +++ b/src/lwjgl/java/paulscode/sound/SoundSystemConfig.java @@ -0,0 +1,1074 @@ +package paulscode.sound; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Locale; +import java.util.ListIterator; +import java.util.LinkedList; + +/** + * The SoundSystemConfig class is used to access global sound system settings, + * and to link with external pluggins. All members of this class are static. + * SoundSystemConfig is sort of a "catch all" configuration class, so if you + * are not sure where to find something in the SoundSystem library, this is + * probably a good place to start. + *

+ * SoundSystem License:

+ * You are free to use this library for any purpose, commercial or otherwise. + * You may modify this library or source code, and distribute it any way you + * like, provided the following conditions are met: + *
+ * 1) You may not falsely claim to be the author of this library or any + * unmodified portion of it. + *
+ * 2) You may not copyright this library or a modified version of it and then + * sue me for copyright infringement. + *
+ * 3) If you modify the source code, you must clearly document the changes + * made before redistributing the modified source code, so other users know + * it is not the original code. + *
+ * 4) You are not required to give me credit for this library in any derived + * work, but if you do, you must also mention my website: + * http://www.paulscode.com + *
+ * 5) I the author will not be responsible for any damages (physical, + * financial, or otherwise) caused by the use if this library or any part + * of it. + *
+ * 6) I the author do not guarantee, warrant, or make any representations, + * either expressed or implied, regarding the use of this library or any + * part of it. + *

+ * Author: Paul Lamb + *
+ * http://www.paulscode.com + *
+ */ +public class SoundSystemConfig +{ +// GLOBAL THREAD SYNCHRONIZATION +/** + * Lock object used to synchronize the three threads used by SoundSystem. + * Synchronize on this anytime you manually manipulate a Source's properties. + */ + public static final Object THREAD_SYNC = new Object(); +// END GLOBAL THREAD SYNCHRONIZATION + +// GLOBAL IDENTIFIERS + +/** + * A normal (non-streaming) source. Also used to define a Channel type as + * normal. + */ + public static final int TYPE_NORMAL = 0; +/** + * A streaming source. Also used to define a Channel type as streaming. + */ + public static final int TYPE_STREAMING = 1; + +/** + * Global identifier for no attenuation. Attenuation is how a source's volume + * fades with distance. When there is no attenuation, a source's volume + * remains constaint regardles of distance. + */ + public static final int ATTENUATION_NONE = 0; // no attenuation +/** + * Global identifier for rolloff attenuation. Rolloff attenuation is a + * realistic attenuation model, which uses a rolloff factor to determine how + * quickly a source fades with distance. A smaller rolloff factor will fade at + * a further distance, and a rolloff factor of 0 will never fade. NOTE: In + * OpenAL, rolloff attenuation only works for monotone sounds. + */ + public static final int ATTENUATION_ROLLOFF = 1; // logrithmic attenuation +/** + * Global identifier for linear attenuation. Linear attenuation is less + * realistic than rolloff attenuation, but it allows the user to specify a + * maximum "fade distance" where a source's volume becomes zero. + */ + public static final int ATTENUATION_LINEAR = 2; // linear attenuation + +/** + * A Regular expression for determining if a file's extension is MIDI. + */ + public static String EXTENSION_MIDI = ".*[mM][iI][dD][iI]?$"; + +/** + * A Regular expression for determining if a path is an online URL. + */ + public static String PREFIX_URL = "^[hH][tT][tT][pP]://.*"; + +// END GLOBAL IDENTIFIERS + + +// PRIVATE STATIC VARIABLES + +/** + * Handle to the message logger. The default logger can be changed by + * overridding the {@link paulscode.sound.SoundSystemLogger SoundSystemLogger} + * class and calling the setLogger() method (must be done BEFORE instantiating + * the SoundSystem class!) + */ + private static SoundSystemLogger logger = null; + +/** + * List of library types in their order of priority. + */ + private static LinkedList libraries; + +/** + * List of codecs and the file formats they are associated with. + */ + private static LinkedList codecs = null; + +/** + * List of stream listeners. + */ + private static LinkedList streamListeners = null; +/** + * For synchronizing access to the streamListeners list. + */ + private static final Object streamListenersLock = new Object(); + +/** + * Maximum number of normal (non-streaming) channels that can be created. + * NOTE: JavaSound may require the total number of channels (non-streaming + + * streaming) to be 32. + */ + private static int numberNormalChannels = 28; +/** + * Maximum number of streaming channels that can be created. + * NOTE: JavaSound may require the total number of channels (non-streaming + + * streaming) to be 32. + */ + private static int numberStreamingChannels = 4; +/** + * Overall volume, affecting all sources. Float value (0.0f - 1.0f). + */ + private static float masterGain = 1.0f; +/** + * Attenuation model to use if not specified. Attenuation is how a source's + * volume fades with distance. + */ + private static int defaultAttenuationModel = ATTENUATION_ROLLOFF; +/** + * Default value to use for the rolloff factor if not specified. + */ + private static float defaultRolloffFactor = 0.03f; +/** + * Value to use for the doppler factor, for determining Doppler scale. + */ + private static float dopplerFactor = 0.0f; +/** + * Value to use for the doppler velocity. + */ + private static float dopplerVelocity = 1.0f; +/** + * Default value to use for fade distance if not specified. + */ + private static float defaultFadeDistance = 1000.0f; +/** + * Package where the sound files are located (must be followed by '/'). + */ + private static String soundFilesPackage = "Sounds/"; + +/** + * Number of bytes to load at a time when streaming. + */ + private static int streamingBufferSize = 131072; +/** + * Number of buffers used for each streaming sorce. Slow codecs may require + * this number to be greater than 2 to prevent audio skipping during playback. + */ + private static int numberStreamingBuffers = 3; +/** + * Enables a transition-speed optimization by assuming all sounds in each + * streaming source's queue will have exactly the same format once decoded + * (including channels, sample rate, and sample size). This is an advanced + * setting which should only be changed by experienced developers. + */ + private static boolean streamQueueFormatsMatch = false; +/** + * The maximum number of bytes to read in for (non-streaming) files. + * Increase this value if non-streaming sounds are getting cut off. + * Decrease this value if large sound files are causing lag during load time. + */ + private static int maxFileSize = 268435456; +/** + * Size of each chunk to read at a time for loading (non-streaming) files. + * Increase if loading sound files is causing significant lag. + */ + private static int fileChunkSize = 1048576; + +/** + * Indicates whether or not there is a codec for reading from MIDI files. If + * there is no codec for MIDI, then SoundSystem uses javax.sound.midi. + */ + private static boolean midiCodec = false; + +/** + * MIDI device to try using as the Synthesizer. May be the full name or part + * of the name. If this String is empty, the default Synthesizer will be used, + * or one of the common alternate synthesizers if the default Synthesizer is + * unavailable. + */ + private static String overrideMIDISynthesizer = ""; + +// END PRIVATE STATIC VARIABLES + +// THESE TWO METHODS PROVIDE INFORMATION ABOUT THE INDIVIDUAL SOUND LIBRARIES + +/** + * Adds an entry to the list of library types. This method has no effect if + * the specified library type is already in the list of libraries. + * NOTE: The parameterless constructor of the SoundSystem class will try to + * load libraries in the order that they were entered into the list. + * @param libraryClass Derivitive of class 'Library'. +*/ + public static void addLibrary( Class libraryClass ) + throws SoundSystemException + { + if( libraryClass == null ) + throw new SoundSystemException( + "Parameter null in method 'addLibrary'", + SoundSystemException.NULL_PARAMETER ); + if( !Library.class.isAssignableFrom( libraryClass ) ) + throw new SoundSystemException( "The specified class does not " + + "extend class 'Library' in method 'addLibrary'" ); + + if( libraries == null ) + libraries = new LinkedList(); + + if( !libraries.contains( libraryClass ) ) + libraries.add( libraryClass ); + } + +/** + * Removes the specified library from the list of library types. + * @param libraryClass Derivitive of class 'Library'. +*/ + public static void removeLibrary( Class libraryClass ) + throws SoundSystemException + { + if( libraries == null || libraryClass == null ) + return; + + libraries.remove( libraryClass ); + } + +/** + * Returns the list of library types. + * @return LinkedList of classes derived from 'Library', or null if none were specified. +*/ + public static LinkedList getLibraries() + { + return libraries; + } + +/** + * Checks if the specified library class is compatible on the user's machine. + * @param libraryClass Library type to check. + * @return True or false. +*/ + public static boolean libraryCompatible( Class libraryClass ) + { + if( libraryClass == null ) + { + errorMessage( "Parameter 'libraryClass' null in method" + + "'librayCompatible'" ); + return false; + } + if( !Library.class.isAssignableFrom( libraryClass ) ) + { + errorMessage( "The specified class does not extend class " + + "'Library' in method 'libraryCompatible'" ); + return false; + } + + Object o = runMethod( libraryClass, "libraryCompatible", + new Class[0], new Object[0] ); + + if( o == null ) + { + errorMessage( "Method 'Library.libraryCompatible' returned " + + "'null' in method 'libraryCompatible'" ); + return false; + } + + return( ( (Boolean) o ).booleanValue() ); + } + +/** + * Return the short title of the specified library, or null if error. + * @param libraryClass Derivitive of class 'Library'. + * @return String containing the library title. +*/ + public static String getLibraryTitle( Class libraryClass ) + { + if( libraryClass == null ) + { + errorMessage( "Parameter 'libraryClass' null in method" + + "'getLibrayTitle'" ); + return null; + } + if( !Library.class.isAssignableFrom( libraryClass ) ) + { + errorMessage( "The specified class does not extend class " + + "'Library' in method 'getLibraryTitle'" ); + return null; + } + + Object o = runMethod( libraryClass, "getTitle", new Class[0], + new Object[0] ); + if( o == null ) + { + errorMessage( "Method 'Library.getTitle' returned " + + "'null' in method 'getLibraryTitle'" ); + return null; + } + + return( (String) o ); + } + +/** + * Return the longer description of the specified library, or null if error. + * @param libraryClass Derivitive of class 'Library'. + * @return String containing the library title. +*/ + public static String getLibraryDescription( Class libraryClass ) + { + if( libraryClass == null ) + { + errorMessage( "Parameter 'libraryClass' null in method" + + "'getLibrayDescription'" ); + return null; + } + if( !Library.class.isAssignableFrom( libraryClass ) ) + { + errorMessage( "The specified class does not extend class " + + "'Library' in method 'getLibraryDescription'" ); + return null; + } + + Object o = runMethod( libraryClass, "getDescription", + new Class[0], new Object[0] ); + if( o == null ) + { + errorMessage( "Method 'Library.getDescription' returned " + + "'null' in method 'getLibraryDescription'" ); + return null; + } + + return( (String) o ); + } + +/** + * Return whether or not requires reversal of audio data byte-order. + * @param libraryClass Derivitive of class 'Library'. + * @return True if byte-order reversal is required. +*/ + public static boolean reverseByteOrder( Class libraryClass ) + { + if( libraryClass == null ) + { + errorMessage( "Parameter 'libraryClass' null in method" + + "'reverseByteOrder'" ); + return false; + } + if( !Library.class.isAssignableFrom( libraryClass ) ) + { + errorMessage( "The specified class does not extend class " + + "'Library' in method 'reverseByteOrder'" ); + return false; + } + + Object o = runMethod( libraryClass, "reversByteOrder", + new Class[0], new Object[0] ); + if( o == null ) + { + errorMessage( "Method 'Library.reverseByteOrder' returned " + + "'null' in method 'getLibraryDescription'" ); + return false; + } + + return( ((Boolean) o).booleanValue() ); + } + +// END LIBRARY INFORMATION + +// Use the following methods to interface the private variables above: + +// STATIC NONSYNCHRONIZED INTERFACE METHODS +/** + * Changes the message logger to use for handling status messages, warnings, + * and error messages. This method should only be called BEFORE instantiating + * the SoundSystem class! If this method is called after the SoundSystem has + * been created, there will be handles floating around to two different + * loggers, and the results will be undesirable. This method can be used to + * change how messages are handled. First, the + * {@link paulscode.sound.SoundSystemLogger SoundSystemLogger} class should be + * extended and methods overriden to change how messages are handled. Then, + * the overridden class should be instantiated, and a call made to + * SoundSystemConfig.setLogger() before creating the SoundSystem object. + * If an alternate logger is not set by the user before the SoundSystem is + * instantiated, then an instance of the base SoundSystemLogger class will be + * used by default. + * @param l Handle to a message logger. + */ + public static void setLogger( SoundSystemLogger l ) + { + logger = l; + } +/** + * Returns a handle to the message logger. + * @return The current message logger. + */ + public static SoundSystemLogger getLogger() + { + return logger; + } + +// STATIC SYNCHRONIZED INTERFACE METHODS + +/** + * Sets the maximum number of normal (non-streaming) channels that can be + * created. Streaming channels are created first, so the higher the maximum + * number of streaming channels is set, the fewer non-streaming channels will + * be available. If unable to create the number of channels specified, + * SoundSystem will create as many as possible. + * NOTE: Some sound library pluggins may require the total number of channels + * (non-streaming + streaming) to be 32. + * @param number How many normal audio channels. + */ + public static synchronized void setNumberNormalChannels( int number ) + { + numberNormalChannels = number; + } + +/** + * Returns the maximum number of normal (non-streaming) channels that can be + * created. + * @return Maximum non-streaming channels. + */ + public static synchronized int getNumberNormalChannels() + { + return numberNormalChannels; + } + +/** + * Sets the maximum number of streaming channels that can be created. + * Streaming channels are created first, so the higher the maximum number of + * streaming channels is set, the fewer non-streaming channels will + * be available. If unable to create the number of channels specified, + * SoundSystem will create as many as possible. + * NOTE: Some sound library pluggins may require the total number of channels + * (non-streaming + streaming) to be 32. + * @param number How many streaming audio channels. + */ + public static synchronized void setNumberStreamingChannels( int number ) + { + numberStreamingChannels = number; + } + +/** + * Returns the maximum number of streaming channels that can be created. + * @return Maximum streaming channels. + */ + public static synchronized int getNumberStreamingChannels() + { + return numberStreamingChannels; + } + +/** + * Sets the varriable used for overall volume, affecting all sources. + * @param value Float value (0.0f - 1.0f). + */ + public static synchronized void setMasterGain( float value ) + { + masterGain = value; + } + +/** + * Returns the value for the overall volume. + * @return A float value (0.0f - 1.0f). + */ + public static synchronized float getMasterGain() + { + return masterGain; + } + +/** + * Sets the default attenuation model to use when one is not specified. + * Attenuation is how a source's volume fades with distance. + * @param model A global attenuation model identifier. + */ + public static synchronized void setDefaultAttenuation( int model ) + { + defaultAttenuationModel = model; + } +/** + * Returns the default attenuation model used when one is not specified. + * @return A global attenuation model identifier + */ + public static synchronized int getDefaultAttenuation() + { + return defaultAttenuationModel; + } +/** + * Sets the default rolloff factor to use when one is not specified. + * @param rolloff Rolloff factor. + */ + public static synchronized void setDefaultRolloff( float rolloff ) + { + defaultRolloffFactor = rolloff; + } +/** + * Returns the doppler factor, for determining Doppler Effect scale. + * @return Doppler factor + */ + public static synchronized float getDopplerFactor() + { + return dopplerFactor; + } +/** + * Sets the doppler factor, for determining Doppler Effect scale. Use this + * method BEFORE instantiating the SoundSystem. To change the Doppler factor + * after the SoundSystem is instantiated, use the + * SoundSystem.changeDopplerFactor method instead. + * @param factor Doppler factor. + */ + public static synchronized void setDopplerFactor( float factor ) + { + dopplerFactor = factor; + } +/** + * Returns the Doppler Velocity, for use in Doppler Effect. + * @return Doppler velocity. + */ + public static synchronized float getDopplerVelocity() + { + return dopplerVelocity; + } +/** + * Sets the Doppler velocity, for use in Doppler Effect. Use this method + * BEFORE instantiating the SoundSystem. To change the Doppler velocity after + * the SoundSystem is instantiated, use the SoundSystem.changeDopplerVelocity + * method instead. + * @param velocity Doppler velocity. + */ + public static synchronized void setDopplerVelocity( float velocity ) + { + dopplerVelocity = velocity; + } +/** + * Returns the default rolloff factor used when one is not specified. + * @return Default rolloff factor + */ + public static synchronized float getDefaultRolloff() + { + return defaultRolloffFactor; + } +/** + * Sets the default fade distance to use when one is not specified. + * @param distance Fade Distance. + */ + public static synchronized void setDefaultFadeDistance( float distance ) + { + defaultFadeDistance = distance; + } +/** + * Returns the default fade distance used when one is not specified. + * @return Default fade distance + */ + public static synchronized float getDefaultFadeDistance() + { + return defaultFadeDistance; + } +/** + * Sets the package where sound files are located. + * @param location Path to the sound files location (must be followed by '/'). + */ + public static synchronized void setSoundFilesPackage( String location ) + { + soundFilesPackage = location; + } +/** + * Returns the package where sound files are located. + * @return Path to the sound files location + */ + public static synchronized String getSoundFilesPackage() + { + return soundFilesPackage; + } +/** + * Sets the number of bytes to load at a time when streaming. + * @param size Size in bytes. + */ + public static synchronized void setStreamingBufferSize( int size ) + { + streamingBufferSize = size; + } +/** + * Returns the number of bytes to load at a time when streaming. + * @return Size in bytes. + */ + public static synchronized int getStreamingBufferSize() + { + return streamingBufferSize; + } +/** + * Sets the number of buffers used for each streaming sorce. + * Slow codecs may require this number to be greater than 2 to prevent audio + * skipping during playback. + * @param num How many buffers. + */ + public static synchronized void setNumberStreamingBuffers( int num ) + { + numberStreamingBuffers = num; + } +/** + * Returns the number of buffers used for each streaming sorce. + * @return How many buffers. + */ + public static synchronized int getNumberStreamingBuffers() + { + return numberStreamingBuffers; + } + +/** + * Enables a transition-speed optimization by assuming all sounds in each + * streaming source's queue will have exactly the same format once decoded + * (including channels, sample rate, and sample size). This is an advanced + * setting which should only be changed by experienced developers. + * @param val False by default. + */ + public static synchronized void setStreamQueueFormatsMatch( boolean val ) + { + streamQueueFormatsMatch = val; + } + +/** + * Returns whether or not all sounds in each streaming source's queue will be + * handled as if they have exactly the same format once decoded (including + * channels, sample rate, and sample size). This is an advanced setting which + * should only be changed by experienced developers. + * @return Normally false. + */ + public static synchronized boolean getStreamQueueFormatsMatch() + { + return streamQueueFormatsMatch; + } + +/** + * Sets the maximum number of bytes to read in for (non-streaming) files. + * Increase this value if non-streaming sounds are getting cut off. + * Decrease this value if large sound files are causing lag during load time. + * @param size Size in bytes. + */ + public static synchronized void setMaxFileSize( int size ) + { + maxFileSize = size; + } +/** + * Returns the maximum number of bytes to read in for (non-streaming) files. + * @return Size in bytes. + */ + public static synchronized int getMaxFileSize() + { + return maxFileSize; + } +/** + * Sets the size of each chunk to read at a time for loading (non-streaming) + * files. Increase if loading sound files is causing significant lag. + * @param size Size in bytes. + */ + public static synchronized void setFileChunkSize( int size ) + { + fileChunkSize = size; + } +/** + * Returns the size of each chunk to read at a time for loading (non-streaming) + * files. + * @return Size in bytes. + */ + public static synchronized int getFileChunkSize() + { + return fileChunkSize; + } +/** + * Returns the name of the MIDI synthesizer to use instead of the default, or + * empty string if none was specified. + * @return All or part of a MIDI device name, or empty string for not specified. + */ + public static synchronized String getOverrideMIDISynthesizer() + { + return overrideMIDISynthesizer; + } +/** + * Sets the name of the MIDI synthesizer to use instead of the default. If + * 'name' is an empty string, the default Synthesizer will be used, or one of + * the common alternate synthesizers if the default Synthesizer is unavailable. + * @param name All or part of the MIDI device name. + */ + public static synchronized void setOverrideMIDISynthesizer( String name ) + { + overrideMIDISynthesizer = name; + } +/** + * Uses the specified file extension to associate a particular file format + * with the codec used to read audio data from it. + * @param extension File extension to be associated with the specified codec. + * @param iCodecClass Codec type to use for files with the specified extension. + */ + public static synchronized void setCodec( String extension, + Class iCodecClass ) + throws SoundSystemException + { + if( extension == null ) + throw new SoundSystemException( "Parameter 'extension' null in " + + "method 'setCodec'.", + SoundSystemException.NULL_PARAMETER ); + if( iCodecClass == null ) + throw new SoundSystemException( "Parameter 'iCodecClass' null in " + + "method 'setCodec'.", + SoundSystemException.NULL_PARAMETER ); + if( !ICodec.class.isAssignableFrom( iCodecClass ) ) + throw new SoundSystemException( "The specified class does " + + "not implement interface 'ICodec' in method 'setCodec'", + SoundSystemException.CLASS_TYPE_MISMATCH ); + + if( codecs == null ) + codecs = new LinkedList(); + + ListIterator i = codecs.listIterator(); + Codec codec; + + while( i.hasNext() ) + { + codec = i.next(); + if( extension.matches( codec.extensionRegX ) ) + i.remove(); + } + codecs.add( new Codec( extension, iCodecClass ) ); + + // Let SoundSystem know if this is a MIDI codec, so it won't use + // javax.sound.midi anymore: + if( extension.matches( EXTENSION_MIDI ) ) + midiCodec = true; + } +/** + * Returns the codec that can be used to read audio data from the specified + * file. + * @param filename File to get a codec for. + * @return Codec to use for reading audio data. + */ + public static synchronized ICodec getCodec( String filename ) + { + if( codecs == null ) + return null; + + ListIterator i = codecs.listIterator(); + Codec codec; + + while( i.hasNext() ) + { + codec = i.next(); + if( filename.matches( codec.extensionRegX ) ) + return codec.getInstance(); + } + + return null; + } + +/** + * Indicates whether or not there is a codec for reading from MIDI files. If + * there is no codec for MIDI, then SoundSystem uses javax.sound.midi. + * @return True if there the user defined a MIDI codec. + */ + public static boolean midiCodec() + { + return midiCodec; + } + +/** + * Adds an entry to the list of stream listeners. If the instance is already + * in the list, the command is ignored. + * @param streamListener Implementation of interface 'IStreamListener'. +*/ + public static void addStreamListener( IStreamListener streamListener ) + { + synchronized( streamListenersLock ) + { + if( streamListeners == null ) + streamListeners = new LinkedList(); + + if( !streamListeners.contains( streamListener ) ) + streamListeners.add( streamListener ); + } + } + +/** + * Removes an entry from the list of stream listeners. + * @param streamListener Implementation of interface 'IStreamListener'. +*/ + public static void removeStreamListener( IStreamListener streamListener ) + { + + synchronized( streamListenersLock ) + { + if( streamListeners == null ) + streamListeners = new LinkedList(); + + if( streamListeners.contains( streamListener ) ) + streamListeners.remove( streamListener ); + } + } + +/** + * Notifies all stream listeners that an End Of Stream was reached. If there + * are no listeners, the command is ignored. + * @param sourcename String identifier of the source which reached the EOS. + * @param queueSize Number of items left the the stream's play queue, or zero if none. +*/ + public static void notifyEOS( String sourcename, int queueSize ) + { + synchronized( streamListenersLock ) + { + if( streamListeners == null ) + return; + } + final String srcName = sourcename; + final int qSize = queueSize; + + new Thread() + { + @Override + public void run() + { + synchronized( streamListenersLock ) + { + if( streamListeners == null ) + return; + ListIterator i = streamListeners.listIterator(); + IStreamListener streamListener; + while( i.hasNext() ) + { + streamListener = i.next(); + if( streamListener == null ) + i.remove(); + else + streamListener.endOfStream( srcName, qSize ); + } + } + } + }.start(); + } + +// END STATIC SYNCHRONIZED INTERFACE METHODS + + +// PRIVATE INTERNAL METHODS + +/** + * Display the specified error message using the current logger. + * @param message Error message to display. +*/ + private static void errorMessage( String message ) + { + if( logger != null ) + logger.errorMessage( "SoundSystemConfig", message, 0 ); + } + + // We don't know what Class parameter 'c' is, so we will ignore the + // warning message "unchecked call to getMethod". + @SuppressWarnings("unchecked") +/** + * Returns the results of calling the specified method from the specified + * class using the specified parameters. + * @param c Class to call the method on. + * @param method Name of the method. + * @param paramTypes Data types of the parameters being passed to the method. + * @param params Actual parameters to pass to the method. + * @return Specified method's return value, or null if error or void. +*/ + private static Object runMethod( Class c, String method, Class[] paramTypes, + Object[] params ) + { + Method m = null; + try + { + m = c.getMethod( method, paramTypes ); // <--- generates a warning + } + catch( NoSuchMethodException nsme ) + { + errorMessage( "NoSuchMethodException thrown when attempting " + + "to call method '" + method + "' in " + + "method 'runMethod'" ); + return null; + } + catch( SecurityException se ) + { + errorMessage( "Access denied when attempting to call method '" + + method + "' in method 'runMethod'" ); + return null; + } + catch( NullPointerException npe ) + { + errorMessage( "NullPointerException thrown when attempting " + + "to call method '" + method + "' in " + + "method 'runMethod'" ); + return null; + } + if( m == null ) + { + errorMessage( "Method '" + method + "' not found for the class " + + "specified in method 'runMethod'" ); + return null; + } + + Object o = null; + try + { + o = m.invoke( null, params ); + } + catch( IllegalAccessException iae ) + { + errorMessage( "IllegalAccessException thrown when attempting " + + "to invoke method '" + method + "' in " + + "method 'runMethod'" ); + return null; + } + catch( IllegalArgumentException iae ) + { + errorMessage( "IllegalArgumentException thrown when attempting " + + "to invoke method '" + method + "' in " + + "method 'runMethod'" ); + return null; + } + catch( InvocationTargetException ite ) + { + errorMessage( "InvocationTargetException thrown while attempting " + + "to invoke method 'Library.getTitle' in " + + "method 'getLibraryTitle'" ); + return null; + } + catch( NullPointerException npe ) + { + errorMessage( "NullPointerException thrown when attempting " + + "to invoke method '" + method + "' in " + + "method 'runMethod'" ); + return null; + } + catch( ExceptionInInitializerError eiie ) + { + errorMessage( "ExceptionInInitializerError thrown when " + + "attempting to invoke method '" + method + "' in " + + "method 'runMethod'" ); + return null; + } + + return( o ); + } + +// END PRIVATE INTERNAL METHODS + + +// PRIVATE INTERNAL CLASSES + +/** + * The Codec class is used to associate individual file formats with the + * codecs used to load audio data from them. + * + * Author: Paul Lamb + */ + private static class Codec + { +/** + * A regular expression used to match a file's extension. This is used to + * determine the file format. + */ + public String extensionRegX; +/** + * Codec used to load audio data from this file format. + */ + public Class iCodecClass; +/** + * Constructor: Converts the specified extension string into a regular + * expression, and associates that with the specified codec. + * @param extension File extension to be associated with the specified codec. + * @param iCodec Codec to use for files with the specified extension. + */ + public Codec( String extension, Class iCodecClass ) + { + extensionRegX = ""; + // Make sure an extension was specified: + if( extension != null && extension.length() > 0 ) + { + // We are only interested in the file extension. The filename + // can begin with whatever: + extensionRegX = ".*"; + String c; + for( int x = 0; x < extension.length(); x++ ) + { + // Each character could be either upper or lower case: + c = extension.substring( x, x + 1 ); + extensionRegX += "[" + c.toLowerCase( Locale.ENGLISH ) + + c.toUpperCase( Locale.ENGLISH ) + "]"; + } + // The extension will be at the end of the filename: + extensionRegX += "$"; + } + // remember the codec to use for this format: + this.iCodecClass = iCodecClass; + } + + public ICodec getInstance() + { + if( iCodecClass == null ) + return null; + + Object o = null; + try + { + o = iCodecClass.newInstance(); + } + catch( InstantiationException ie ) + { + instantiationErrorMessage(); + return null; + } + catch( IllegalAccessException iae ) + { + instantiationErrorMessage(); + return null; + } + catch( ExceptionInInitializerError eiie ) + { + instantiationErrorMessage(); + return null; + } + catch( SecurityException se ) + { + instantiationErrorMessage(); + return null; + } + + + if( o == null ) + { + instantiationErrorMessage(); + return null; + } + + return (ICodec) o; + } + + private void instantiationErrorMessage() + { + errorMessage( "Unrecognized ICodec implementation in method " + + "'getInstance'. Ensure that the implementing " + + "class has one public, parameterless constructor." ); + } + } +// END PRIVATE INTERNAL CLASSES +} diff --git a/src/lwjgl/java/paulscode/sound/SoundSystemException.java b/src/lwjgl/java/paulscode/sound/SoundSystemException.java new file mode 100644 index 0000000..d0a0101 --- /dev/null +++ b/src/lwjgl/java/paulscode/sound/SoundSystemException.java @@ -0,0 +1,94 @@ +package paulscode.sound; + +/** + * The SoundSystemException class is used to provide information about serious + * errors. + *

+ * SoundSystem License:

+ * You are free to use this library for any purpose, commercial or otherwise. + * You may modify this library or source code, and distribute it any way you + * like, provided the following conditions are met: + *
+ * 1) You may not falsely claim to be the author of this library or any + * unmodified portion of it. + *
+ * 2) You may not copyright this library or a modified version of it and then + * sue me for copyright infringement. + *
+ * 3) If you modify the source code, you must clearly document the changes + * made before redistributing the modified source code, so other users know + * it is not the original code. + *
+ * 4) You are not required to give me credit for this library in any derived + * work, but if you do, you must also mention my website: + * http://www.paulscode.com + *
+ * 5) I the author will not be responsible for any damages (physical, + * financial, or otherwise) caused by the use if this library or any part + * of it. + *
+ * 6) I the author do not guarantee, warrant, or make any representations, + * either expressed or implied, regarding the use of this library or any + * part of it. + *

+ * Author: Paul Lamb + *
+ * http://www.paulscode.com + *
+ */ +public class SoundSystemException extends Exception +{ +/** + * Global identifier for no problem. + */ + public static final int ERROR_NONE = 0; +/** + * Global identifier for a generic exception. + */ + public static final int UNKNOWN_ERROR = 1; +/** + * Global identifier for a null parameter. + */ + public static final int NULL_PARAMETER = 2; +/** + * Global identifier for a class type mismatch. + */ + public static final int CLASS_TYPE_MISMATCH = 3; +/** + * Global identifier for the sound library does not exist. + */ + public static final int LIBRARY_NULL = 4; +/** + * Global identifier for the sound library does not exist. + */ + public static final int LIBRARY_TYPE = 5; + +/** + * Holds a global identifier indicating the type of exception. + */ + private int myType = UNKNOWN_ERROR; + +/** + * Constructor: Generic exception. Specify the error message. + */ + public SoundSystemException( String message ) + { + super( message ); + } + +/** + * Constructor: Specify the error message and type of exception. + * @param message Description of the problem. + * @param type Global identifier for type of exception. + */ + public SoundSystemException( String message, int type ) + { + super( message ); + myType = type; + } + + public int getType() + { + return myType; + } +} diff --git a/src/lwjgl/java/paulscode/sound/SoundSystemLogger.java b/src/lwjgl/java/paulscode/sound/SoundSystemLogger.java new file mode 100644 index 0000000..7230a13 --- /dev/null +++ b/src/lwjgl/java/paulscode/sound/SoundSystemLogger.java @@ -0,0 +1,173 @@ +package paulscode.sound; + +/** + * The SoundSystemLogger class handles all status messages, warnings, and error + * messages for the SoundSystem library. This class can be extended and + * methods overriden to change how messages are handled. To do this, the + * overridden class should be instantiated, and a call should be made to method + * SoundSystemConfig.setLogger() BEFORE creating the SoundSystem object. If + * the setLogger() method is called after the SoundSystem has been created, + * there will be handles floating around to two different message loggers, and + * the results will be undesirable. + * See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more + * information about changing default settings. If an alternate logger is not + * set by the user, then an instance of this base class will be automatically + * created by default when the SoundSystem class is instantiated. + *

+ * SoundSystem License:

+ * You are free to use this library for any purpose, commercial or otherwise. + * You may modify this library or source code, and distribute it any way you + * like, provided the following conditions are met: + *
+ * 1) You may not falsely claim to be the author of this library or any + * unmodified portion of it. + *
+ * 2) You may not copyright this library or a modified version of it and then + * sue me for copyright infringement. + *
+ * 3) If you modify the source code, you must clearly document the changes + * made before redistributing the modified source code, so other users know + * it is not the original code. + *
+ * 4) You are not required to give me credit for this library in any derived + * work, but if you do, you must also mention my website: + * http://www.paulscode.com + *
+ * 5) I the author will not be responsible for any damages (physical, + * financial, or otherwise) caused by the use if this library or any part + * of it. + *
+ * 6) I the author do not guarantee, warrant, or make any representations, + * either expressed or implied, regarding the use of this library or any + * part of it. + *

+ * Author: Paul Lamb + *
+ * http://www.paulscode.com + *
+ */ +public class SoundSystemLogger +{ +/** + * Prints a message. + * @param message Message to print. + * @param indent Number of tabs to indent the message. + */ + public void message( String message, int indent ) + { + String messageText; + // Determine how many spaces to indent: + String spacer = ""; + for( int x = 0; x < indent; x++ ) + { + spacer += " "; + } + // indent the message: + messageText = spacer + message; + + // Print the message: + System.out.println( messageText ); + } + +/** + * Prints an important message. + * @param message Message to print. + * @param indent Number of tabs to indent the message. + */ + public void importantMessage( String message, int indent ) + { + String messageText; + // Determine how many spaces to indent: + String spacer = ""; + for( int x = 0; x < indent; x++ ) + { + spacer += " "; + } + // indent the message: + messageText = spacer + message; + + // Print the message: + System.out.println( messageText ); + } + +/** + * Prints the specified message if error is true. + * @param error True or False. + * @param classname Name of the class checking for an error. + * @param message Message to print if error is true. + * @param indent Number of tabs to indent the message. + * @return True if error is true. + */ + public boolean errorCheck( boolean error, String classname, String message, + int indent ) + { + if( error ) + errorMessage( classname, message, indent ); + return error; + } + +/** + * Prints the classname which generated the error, followed by the error + * message. + * @param classname Name of the class which generated the error. + * @param message The actual error message. + * @param indent Number of tabs to indent the message. +*/ + public void errorMessage( String classname, String message, int indent ) + { + String headerLine, messageText; + // Determine how many spaces to indent: + String spacer = ""; + for( int x = 0; x < indent; x++ ) + { + spacer += " "; + } + // indent the header: + headerLine = spacer + "Error in class '" + classname + "'"; + // indent the message one more than the header: + messageText = " " + spacer + message; + + // Print the error message: + System.out.println( headerLine ); + System.out.println( messageText ); + } + +/** + * Prints an exception's error message followed by the stack trace. + * @param e Exception containing the information to print. + * @param indent Number of tabs to indent the message and stack trace. + */ + public void printStackTrace( Exception e, int indent ) + { + printExceptionMessage( e, indent ); + importantMessage( "STACK TRACE:", indent ); + if( e == null ) + return; + + StackTraceElement[] stack = e.getStackTrace(); + if( stack == null ) + return; + + StackTraceElement line; + for( int x = 0; x < stack.length; x++ ) + { + line = stack[x]; + if( line != null ) + message( line.toString(), indent + 1 ); + } + } + +/** + * Prints an exception's error message. + * @param e Exception containing the message to print. + * @param indent Number of tabs to indent the message. + */ + public void printExceptionMessage( Exception e, int indent ) + { + importantMessage( "ERROR MESSAGE:", indent ); + if( e.getMessage() == null ) + message( "(none)", indent + 1 ); + else + message( e.getMessage(), indent + 1 ); + } +} diff --git a/src/lwjgl/java/paulscode/sound/Source.java b/src/lwjgl/java/paulscode/sound/Source.java new file mode 100644 index 0000000..5bc6cb0 --- /dev/null +++ b/src/lwjgl/java/paulscode/sound/Source.java @@ -0,0 +1,1346 @@ +package paulscode.sound; + +import java.net.URL; +import java.util.LinkedList; +import java.util.ListIterator; +import javax.sound.sampled.AudioFormat; + +import net.lax1dude.eaglercraft.EaglerAdapter; + +/** + * The Source class is used to store information about a source. + * Source objects are stored in a map in the Library class. The + * information they contain is used to create library-specific sources. + * This is the template class which is extended for each specific library. + * This class is also used by the "No Sound" library to represent a mute + * source. + *

+ * SoundSystem License:

+ * You are free to use this library for any purpose, commercial or otherwise. + * You may modify this library or source code, and distribute it any way you + * like, provided the following conditions are met: + *
+ * 1) You may not falsely claim to be the author of this library or any + * unmodified portion of it. + *
+ * 2) You may not copyright this library or a modified version of it and then + * sue me for copyright infringement. + *
+ * 3) If you modify the source code, you must clearly document the changes + * made before redistributing the modified source code, so other users know + * it is not the original code. + *
+ * 4) You are not required to give me credit for this library in any derived + * work, but if you do, you must also mention my website: + * http://www.paulscode.com + *
+ * 5) I the author will not be responsible for any damages (physical, + * financial, or otherwise) caused by the use if this library or any part + * of it. + *
+ * 6) I the author do not guarantee, warrant, or make any representations, + * either expressed or implied, regarding the use of this library or any + * part of it. + *

+ * Author: Paul Lamb + *
+ * http://www.paulscode.com + *
+ */ +public class Source +{ +/** + * The library class associated with this type of channel. + */ + protected Class libraryType = Library.class; + +/** + * Used to return a current value from one of the synchronized + * boolean-interface methods. + */ + private static final boolean GET = false; + +/** + * Used to set the value in one of the synchronized boolean-interface methods. + */ + private static final boolean SET = true; + +/** + * Used when a parameter for one of the synchronized boolean-interface methods + * is not aplicable. + */ + private static final boolean XXX = false; + +/** + * Processes status messages, warnings, and error messages. + */ + private SoundSystemLogger logger; + +/** + * True if this source is being directly fed with raw audio data. + */ + public boolean rawDataStream = false; + +/** + * Format the raw data will be in if this is a Raw Data Stream source. + */ + public AudioFormat rawDataFormat = null; + +/** + * Determines whether a source should be removed after it finishes playing. + */ + public boolean temporary = false; + +/** + * Determines whether or not this is a priority source. Priority sources will + * not be overwritten by other sources when there are no available channels. + */ + public boolean priority = false; + +/** + * Whether or not this source should be streamed. + */ + public boolean toStream = false; + +/** + * Whether this source should loop or only play once. + */ + public boolean toLoop = false; + +/** + * Whether this source needs to be played (for example if it was playing and + * looping when it got culled). + */ + public boolean toPlay = false; + +/** + * Unique name for this source. More than one source can not have the same + * sourcename. + */ + public String sourcename = ""; + +/** + * The audio file which this source should play. + */ + public FilenameURL filenameURL = null; + +/** + * This source's position in 3D space. + */ + public Vector3D position; + +/** + * Attenuation model to use for this source. + */ + public int attModel = 0; + +/** + * Either fade distance or rolloff factor, depending on the value of attModel. + */ + public float distOrRoll = 0.0f; + +/** + * Source's velocity in world-space, for use in Doppler effect. + */ + public Vector3D velocity; + +/** + * This source's volume (a float between 0.0 - 1.0). This value is used + * internally for attenuation, and should not be used to manually change a + * source's volume. + */ + public float gain = 1.0f; + +/** + * This value should be used to manually increase or decrease source volume. + */ + public float sourceVolume = 1.0f; + + /** + * Indicates to the streaming thread that this source is removed and needs cleanup. + * @see https://github.com/MinecraftForge/MinecraftForge/pull/4765 + */ + public boolean removed = false; + +/** + * This value represents the source's pitch (float value between 0.5f - 2.0f). + */ + protected float pitch = 1.0f; + +/** + * This source's distance from the listener. + */ + public float distanceFromListener = 0.0f; + +/** + * Channel to play this source on. + */ + public Channel channel = null; + +/** + * Holds the data used by normal sources. + */ + public SoundBuffer soundBuffer = null; + +/** + * False when this source gets culled. + */ + private boolean active = true; + +/** + * Whether or not this source has been stopped. + */ + private boolean stopped = true; + +/** + * Whether or not this source has been paused. + */ + private boolean paused = false; + +/** + * Codec used to read data for streaming sources. + */ + protected ICodec codec = null; + +/** + * Codec used to read in some initial data from the next sound in the queue. + */ + protected ICodec nextCodec = null; + +/** + * List of buffers to hold some initial data from the next sound in the queue. + */ + protected LinkedList nextBuffers = null; + + +/** + * The list of files to stream when the current stream finishes. + */ + protected LinkedList soundSequenceQueue = null; + +/** + * Ensures that only one thread accesses the soundSequenceQueue at a time. + */ + protected final Object soundSequenceLock = new Object(); + +/** + * Used by streaming sources to indicate whether or not the initial + * stream-buffers still need to be queued. + */ + public boolean preLoad = false; + +/** + * Specifies the gain factor used for the fade-out effect, or -1 when + * source is not currently fading out. + */ + protected float fadeOutGain = -1.0f; + +/** + * Specifies the gain factor used for the fade-in effect, or 1 when + * source is not currently fading in. + */ + protected float fadeInGain = 1.0f; + +/** + * Specifies the number of miliseconds it should take to fade out. + */ + protected long fadeOutMilis = 0; + +/** + * Specifies the number of miliseconds it should take to fade in. + */ + protected long fadeInMilis = 0; + +/** + * System time in miliseconds when the last fade in/out volume check occurred. + */ + protected long lastFadeCheck = 0; + +/** + * Constructor: Creates a new source using the specified parameters. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param toStream Setting this to true will create a streaming source. + * @param toLoop Should this source loop, or play only once. + * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename. + * @param filenameURL The filename/URL of the sound file to play at this source. + * @param soundBuffer Buffer containing audio data, or null if not loaded yet. + * @param x X position for this source. + * @param y Y position for this source. + * @param z Z position for this source. + * @param attModel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of 'att'. + * @param temporary Whether or not to remove this source after it finishes playing. + */ + public Source( boolean priority, boolean toStream, boolean toLoop, + String sourcename, FilenameURL filenameURL, + SoundBuffer soundBuffer, float x, float y, float z, + int attModel, float distOrRoll, boolean temporary ) + { + // grab a handle to the message logger: + logger = SoundSystemConfig.getLogger(); + + this.priority = priority; + this.toStream = toStream; + this.toLoop = toLoop; + this.sourcename = sourcename; + this.filenameURL = filenameURL; + this.soundBuffer = soundBuffer; + position = new Vector3D( x, y, z ); + this.attModel = attModel; + this.distOrRoll = distOrRoll; + this.velocity = new Vector3D( 0, 0, 0 ); + this.temporary = temporary; + + if( toStream && filenameURL != null ) + codec = SoundSystemConfig.getCodec( filenameURL.getFilename() ); + } + +/** + * Constructor: Creates a new source matching the specified one. + * @param old Source to copy information from. + * @param soundBuffer Buffer containing audio data, or null if not loaded yet. + */ + public Source( Source old, SoundBuffer soundBuffer ) + { + // grab a handle to the message logger: + logger = SoundSystemConfig.getLogger(); + + priority = old.priority; + toStream = old.toStream; + toLoop = old.toLoop; + sourcename = old.sourcename; + filenameURL = old.filenameURL; + position = old.position.clone(); + attModel = old.attModel; + distOrRoll = old.distOrRoll; + velocity = old.velocity.clone(); + temporary = old.temporary; + + sourceVolume = old.sourceVolume; + + rawDataStream = old.rawDataStream; + rawDataFormat = old.rawDataFormat; + + this.soundBuffer = soundBuffer; + + if( toStream && filenameURL != null ) + codec = SoundSystemConfig.getCodec( filenameURL.getFilename() ); + } + +/** + * Constructor: Creates a new streaming source that will be directly fed with + * raw audio data. + * @param audioFormat Format that the data will be in. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename. + * @param x X position for this source. + * @param y Y position for this source. + * @param z Z position for this source. + * @param attModel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of 'att'. + */ + public Source( AudioFormat audioFormat, boolean priority, String sourcename, + float x, float y, float z, int attModel, float distOrRoll ) + { + // grab a handle to the message logger: + logger = SoundSystemConfig.getLogger(); + + this.priority = priority; + this.toStream = true; + this.toLoop = false; + this.sourcename = sourcename; + this.filenameURL = null; + this.soundBuffer = null; + position = new Vector3D( x, y, z ); + this.attModel = attModel; + this.distOrRoll = distOrRoll; + this.velocity = new Vector3D( 0, 0, 0 ); + this.temporary = false; + + rawDataStream = true; + rawDataFormat = audioFormat; + } +/* Override methods */ + +/** + * Shuts the source down and removes references to all instantiated objects. + */ + public void cleanup() + { + if( codec != null ) + codec.cleanup(); + + synchronized( soundSequenceLock ) + { + if( soundSequenceQueue != null ) + soundSequenceQueue.clear(); + soundSequenceQueue = null; + } + + sourcename = null; + filenameURL = null; + position = null; + soundBuffer = null; + codec = null; + } + +/** + * If this is a streaming source, queues up the next sound to play when + * the previous stream ends. This method has no effect on non-streaming + * sources. + * @param filenameURL The filename/URL of the sound file to stream next. + */ + public void queueSound( FilenameURL filenameURL ) + { + if( !toStream ) + { + errorMessage( "Method 'queueSound' may only be used for " + + "streaming and MIDI sources." ); + return; + } + if( filenameURL == null ) + { + errorMessage( "File not specified in method 'queueSound'" ); + return; + } + + synchronized( soundSequenceLock ) + { + if( soundSequenceQueue == null ) + soundSequenceQueue = new LinkedList(); + soundSequenceQueue.add( filenameURL ); + } + } + +/** + * Removes the first occurrence of the specified filename from the list of + * sounds to play when the previous stream ends. This method has no effect + * on non-streaming sources. + * @param filename Filename/identifier of a sound file to remove from the queue. + */ + public void dequeueSound( String filename ) + { + if( !toStream ) + { + errorMessage( "Method 'dequeueSound' may only be used for " + + "streaming and MIDI sources." ); + return; + } + if( filename == null || filename.equals( "" ) ) + { + errorMessage( "Filename not specified in method 'dequeueSound'" ); + return; + } + + synchronized( soundSequenceLock ) + { + if( soundSequenceQueue != null ) + { + ListIterator i = soundSequenceQueue.listIterator(); + while( i.hasNext() ) + { + if( i.next().getFilename().equals( filename ) ) + { + i.remove(); + break; + } + } + } + } + } + +/** + * Fades out the volume of whatever this source is currently playing, then + * begins playing the specified filename at the source's previously assigned + * volume level. If the filename parameter is null or empty, the source will + * simply fade out and stop. The miliseconds parameter must be non-negative or + * zero. This method will remove anything that is currently in the list of + * queued sounds that would have played next when the current sound finished + * playing. This method has no effect on non-streaming sources. + * @param filenameURL Filename/URL of the sound file to play next, or null for none. + * @param milis Number of miliseconds the fadeout should take. + */ + public void fadeOut( FilenameURL filenameURL, long milis ) + { + if( !toStream ) + { + errorMessage( "Method 'fadeOut' may only be used for " + + "streaming and MIDI sources." ); + return; + } + if( milis < 0 ) + { + errorMessage( "Miliseconds may not be negative in method " + + "'fadeOut'." ); + return; + } + + fadeOutMilis = milis; + fadeInMilis = 0; + fadeOutGain = 1.0f; + lastFadeCheck = EaglerAdapter.steadyTimeMillis(); + + synchronized( soundSequenceLock ) + { + if( soundSequenceQueue != null ) + soundSequenceQueue.clear(); + + if( filenameURL != null ) + { + if( soundSequenceQueue == null ) + soundSequenceQueue = new LinkedList(); + soundSequenceQueue.add( filenameURL ); + } + } + } + +/** + * Fades out the volume of whatever this source is currently playing, then + * fades the volume back in playing the specified file. Final volume after + * fade-in completes will be equal to the source's previously assigned volume + * level. The filenameURL parameter may not be null or empty. The miliseconds + * parameters must be non-negative or zero. This method will remove anything + * that is currently in the list of queued sounds that would have played next + * when the current sound finished playing. This method has no effect on + * non-streaming sources. + * @param filenameURL Filename/URL of the sound file to play next, or null for none. + * @param milisOut Number of miliseconds the fadeout should take. + * @param milisIn Number of miliseconds the fadein should take. + */ + public void fadeOutIn( FilenameURL filenameURL, long milisOut, long milisIn ) + { + if( !toStream ) + { + errorMessage( "Method 'fadeOutIn' may only be used for " + + "streaming and MIDI sources." ); + return; + } + if( filenameURL == null ) + { + errorMessage( "Filename/URL not specified in method 'fadeOutIn'." ); + return; + } + if( milisOut < 0 || milisIn < 0 ) + { + errorMessage( "Miliseconds may not be negative in method " + + "'fadeOutIn'." ); + return; + } + + fadeOutMilis = milisOut; + fadeInMilis = milisIn; + + fadeOutGain = 1.0f; + lastFadeCheck = EaglerAdapter.steadyTimeMillis(); + + synchronized( soundSequenceLock ) + { + if( soundSequenceQueue == null ) + soundSequenceQueue = new LinkedList(); + soundSequenceQueue.clear(); + soundSequenceQueue.add( filenameURL ); + } + } + +/** + * Resets this source's volume if it is fading out or in. Returns true if this + * source is currently in the process of fading out. When fade-out completes, + * this method transitions the source to the next sound in the sound sequence + * queue if there is one. This method has no effect on non-streaming sources. + * @return True if this source is in the process of fading out. + */ + public boolean checkFadeOut() + { + if( !toStream ) + return false; + + if( fadeOutGain == -1.0f && fadeInGain == 1.0f ) + return false; + + long currentTime = EaglerAdapter.steadyTimeMillis(); + long milisPast = currentTime - lastFadeCheck; + lastFadeCheck = currentTime; + + if( fadeOutGain >= 0.0f ) + { + if( fadeOutMilis == 0 ) + { + fadeOutGain = -1.0f; + fadeInGain = 0.0f; + if( !incrementSoundSequence() ) + { + stop(); + } + positionChanged(); + preLoad = true; + return false; + } + else + { + float fadeOutReduction = ((float)milisPast) / ((float)fadeOutMilis); + fadeOutGain -= fadeOutReduction; + if( fadeOutGain <= 0.0f ) + { + fadeOutGain = -1.0f; + fadeInGain = 0.0f; + if( !incrementSoundSequence() ) + stop(); + positionChanged(); + preLoad = true; + return false; + } + } + positionChanged(); + return true; + } + + if( fadeInGain < 1.0f ) + { + fadeOutGain = -1.0f; + if( fadeInMilis == 0 ) + { + fadeOutGain = -1.0f; + fadeInGain = 1.0f; + } + else + { + float fadeInIncrease = ((float)milisPast) / ((float)fadeInMilis); + fadeInGain += fadeInIncrease; + if( fadeInGain >= 1.0f ) + { + fadeOutGain = -1.0f; + fadeInGain = 1.0f; + } + } + positionChanged(); + return true; + } + return false; + } + +/** + * Removes the next filename/URL from the sound sequence queue and assigns it to + * this source. This method has no effect on non-streaming sources. This + * method is used internally by SoundSystem, and it is unlikely that the user + * will ever need to use it. + * @return True if there was something in the queue. + */ + public boolean incrementSoundSequence() + { + if( !toStream ) + { + errorMessage( "Method 'incrementSoundSequence' may only be used " + + "for streaming and MIDI sources." ); + return false; + } + + synchronized( soundSequenceLock ) + { + if( soundSequenceQueue != null && soundSequenceQueue.size() > 0 ) + { + filenameURL = soundSequenceQueue.remove( 0 ); + if( codec != null ) + codec.cleanup(); + codec = SoundSystemConfig.getCodec( filenameURL.getFilename() ); + return true; + } + } + return false; + } + +/** + * Reads in initial buffers of data from the next sound in the sound sequence + * queue, to reduce lag when the transition occurrs. This method has no effect + * on non-streaming sources. This method is used internally by SoundSystem, and + * it is unlikely that the user will ever need to use it. + * @return False if there is nothing in the queue to read from. + */ + public boolean readBuffersFromNextSoundInSequence() + { + if( !toStream ) + { + errorMessage( "Method 'readBuffersFromNextSoundInSequence' may " + + "only be used for streaming sources." ); + return false; + } + + synchronized( soundSequenceLock ) + { + if( soundSequenceQueue != null && soundSequenceQueue.size() > 0 ) + { + if( nextCodec != null ) + nextCodec.cleanup(); + nextCodec = SoundSystemConfig.getCodec( + soundSequenceQueue.get( 0 ).getFilename() ); + nextCodec.initialize( soundSequenceQueue.get( 0 ).getURL() ); + + SoundBuffer buffer = null; + for( int i = 0; + i < SoundSystemConfig.getNumberStreamingBuffers() + && !nextCodec.endOfStream(); + i++ ) + { + buffer = nextCodec.read(); + if( buffer != null ) + { + if( nextBuffers == null ) + nextBuffers = new LinkedList(); + nextBuffers.add( buffer ); + } + } + return true; + } + } + return false; + } + + +/** + * Returns the size of the sound sequence queue (if this is a streaming source). + * @return Number of sounds left in the queue, or zero if none. + */ + public int getSoundSequenceQueueSize() + { + if( soundSequenceQueue == null ) + return 0; + return soundSequenceQueue.size(); + } + +/** + * Sets whether or not this source should be removed when it finishes playing. + * @param tmp True or false. + */ + public void setTemporary( boolean tmp ) + { + temporary = tmp; + } + +/** + * Called every time the listener's position or orientation changes. + */ + public void listenerMoved() + {} + +/** + * Moves the source to the specified position. + * @param x X coordinate to move to. + * @param y Y coordinate to move to. + * @param z Z coordinate to move to. + */ + public void setPosition( float x, float y, float z ) + { + position.x = x; + position.y = y; + position.z = z; + } + +/** + * Called every time the source changes position. + */ + public void positionChanged() + {} + +/** + * Sets whether or not this source is a priority source. A priority source + * will not be overritten by another source if there are no channels available + * to play on. + * @param pri True or false. + */ + public void setPriority( boolean pri ) + { + priority = pri; + } + +/** + * Sets whether this source should loop or only play once. + * @param lp True or false. + */ + public void setLooping( boolean lp ) + { + toLoop = lp; + } + +/** + * Sets this source's attenuation model. + * @param model Attenuation model to use. + */ + public void setAttenuation( int model ) + { + attModel = model; + } + +/** + * Sets this source's fade distance or rolloff factor, depending on the + * attenuation model. + * @param dr New value for fade distance or rolloff factor. + */ + public void setDistOrRoll( float dr) + { + distOrRoll = dr; + } + +/** + * Sets this source's velocity, for use in Doppler effect. + * @param x Velocity along world x-axis. + * @param y Velocity along world y-axis. + * @param z Velocity along world z-axis. + */ + public void setVelocity( float x, float y, float z ) + { + this.velocity.x = x; + this.velocity.y = y; + this.velocity.z = z; + } + +/** + * Returns the source's distance from the listener. + * @return How far away the source is. + */ + public float getDistanceFromListener() + { + return distanceFromListener; + } + +/** + * Manually sets the specified source's pitch. + * @param value A float value ( 0.5f - 2.0f ). + */ + public void setPitch( float value ) + { + float newPitch = value; + if( newPitch < 0.5f ) + newPitch = 0.5f; + else if( newPitch > 2.0f ) + newPitch = 2.0f; + pitch = newPitch; + } + +/** + * Returns the pitch of the specified source. + * @return Float value representing the source pitch (0.5f - 2.0f). + */ + public float getPitch() + { + return pitch; + } + +/** + * Indicates whether or not this source's associated library requires some + * codecs to reverse-order the audio data they generate. + * @return True if audio data should be reverse-ordered. + */ + public boolean reverseByteOrder() + { + return SoundSystemConfig.reverseByteOrder( libraryType ); + } + +/** + * Changes the sources peripheral information to match the supplied parameters. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param toStream Setting this to true will create a streaming source. + * @param toLoop Should this source loop, or play only once. + * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename. + * @param filenameURL Filename/URL of the sound file to play at this source. + * @param x X position for this source. + * @param y Y position for this source. + * @param z Z position for this source. + * @param attModel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of 'att'. + * @param temporary Whether or not to remove this source after it finishes playing. + */ + public void changeSource( boolean priority, boolean toStream, + boolean toLoop, String sourcename, + FilenameURL filenameURL, SoundBuffer soundBuffer, + float x, float y, float z, int attModel, + float distOrRoll, boolean temporary ) + { + this.priority = priority; + this.toStream = toStream; + this.toLoop = toLoop; + this.sourcename = sourcename; + this.filenameURL = filenameURL; + this.soundBuffer = soundBuffer; + position.x = x; + position.y = y; + position.z = z; + this.attModel = attModel; + this.distOrRoll = distOrRoll; + this.temporary = temporary; + } + +/** + * Feeds raw data to the specified channel. + * @param buffer Byte buffer containing raw audio data to stream. + * @param c Channel to stream on. + * @return Number of prior buffers that have been processed, or -1 if unable to queue the buffer (if the source was culled, for example). + */ + public int feedRawAudioData( Channel c, byte[] buffer ) + { + if( !active( GET, XXX) ) + { + toPlay = true; + return -1; + } + if( channel != c ) + { + channel = c; + channel.close(); + channel.setAudioFormat( rawDataFormat ); + positionChanged(); + } + + // change the state of this source to not stopped and not paused: + stopped( SET, false ); + paused( SET, false ); + + return channel.feedRawAudioData( buffer ); + } + +/** + * Plays the source on the specified channel. + * @param c Channel to play on. + */ + public void play( Channel c ) + { + if( !active( GET, XXX) ) + { + if( toLoop ) + toPlay = true; + return; + } + if( channel != c ) + { + channel = c; + channel.close(); + } + // change the state of this source to not stopped and not paused: + stopped( SET, false ); + paused( SET, false ); + } +/* END Override methods */ + +/** + * Streams the source on its current channel + * @return False when stream has finished playing. + */ + public boolean stream() + { + if( channel == null ) + return false; + + if( preLoad ) + { + if( rawDataStream ) + preLoad = false; + else + return preLoad(); + } + + if( rawDataStream ) + { + if( stopped() || paused() ) + return true; + if( channel.buffersProcessed() > 0 ) + channel.processBuffer(); + return true; + } + else + { + if( codec == null ) + return false; + if( stopped() ) + return false; + if( paused() ) + return true; + + int processed = channel.buffersProcessed(); + + SoundBuffer buffer = null; + for( int i = 0; i < processed; i++ ) + { + buffer = codec.read(); + if( buffer != null ) + { + if( buffer.audioData != null ) + channel.queueBuffer( buffer.audioData ); + buffer.cleanup(); + buffer = null; + return true; + } + else if( codec.endOfStream() ) + { + synchronized( soundSequenceLock ) + { + if( SoundSystemConfig.getStreamQueueFormatsMatch() ) + { + if( soundSequenceQueue != null && + soundSequenceQueue.size() > 0 ) + { + if( codec != null ) + codec.cleanup(); + filenameURL = soundSequenceQueue.remove( 0 ); + codec = SoundSystemConfig.getCodec( + filenameURL.getFilename() ); + codec.initialize( filenameURL.getURL() ); + buffer = codec.read(); + if( buffer != null ) + { + if( buffer.audioData != null ) + channel.queueBuffer( buffer.audioData ); + buffer.cleanup(); + buffer = null; + return true; + } + } + else if( toLoop ) + { + codec.initialize( filenameURL.getURL() ); + buffer = codec.read(); + if( buffer != null ) + { + if( buffer.audioData != null ) + channel.queueBuffer( buffer.audioData ); + buffer.cleanup(); + buffer = null; + return true; + } + } + } + } + } +/* + if( codec.endOfStream() ) + { + synchronized( soundSequenceLock ) + { + if( SoundSystemConfig.getStreamQueueFormatsMatch() ) + { + if( soundSequenceQueue != null && + soundSequenceQueue.size() > 0 ) + { + if( codec != null ) + codec.cleanup(); + filenameURL = soundSequenceQueue.remove( 0 ); + codec = SoundSystemConfig.getCodec( + filenameURL.getFilename() ); + codec.initialize( filenameURL.getURL() ); + return true; + } + else if( toLoop ) + { + codec.initialize( filenameURL.getURL() ); + buffer = codec.read(); + if( buffer != null ) + { + if( buffer.audioData != null ) + channel.queueBuffer( buffer.audioData ); + buffer.cleanup(); + buffer = null; + } + } + } + } + return false; + } +*/ + } + } + return false; + } + +/** + * Queues up the initial stream-buffers for the stream. + * @return False if the end of the stream was reached. + */ + public boolean preLoad() + { + if( channel == null ) + return false; + + if( codec == null ) + return false; + + SoundBuffer buffer = null; + + boolean noNextBuffers = false; + synchronized( soundSequenceLock ) + { + if( nextBuffers == null || nextBuffers.isEmpty() ) + noNextBuffers = true; + } + + if( nextCodec != null && !noNextBuffers ) + { + codec = nextCodec; + nextCodec = null; + synchronized( soundSequenceLock ) + { + while( !nextBuffers.isEmpty() ) + { + buffer = nextBuffers.remove( 0 ); + if( buffer != null ) + { + if( buffer.audioData != null ) + channel.queueBuffer( buffer.audioData ); + buffer.cleanup(); + buffer = null; + } + } + } + } + else + { + nextCodec = null; + URL url = filenameURL.getURL(); + + codec.initialize( url ); + for( int i = 0; i < SoundSystemConfig.getNumberStreamingBuffers(); + i++ ) + { + buffer = codec.read(); + if( buffer != null ) + { + if( buffer.audioData != null ) + channel.queueBuffer( buffer.audioData ); + buffer.cleanup(); + buffer = null; + } + } + } + + return true; + } + +/** + * Pauses the source. + */ + public void pause() + { + toPlay = false; + paused( SET, true ); + if( channel != null ) + channel.pause(); + else + errorMessage( "Channel null in method 'pause'" ); + } + +/** + * Stops the source. + */ + public void stop() + { + toPlay = false; + stopped( SET, true ); + paused( SET, false ); + if( channel != null ) + channel.stop(); + else + errorMessage( "Channel null in method 'stop'" ); + } + +/** + * Rewinds the source. If the source was paused, then it is stopped. + */ + public void rewind() + { + if( paused( GET, XXX ) ) + { + stop(); + } + if( channel != null ) + { + boolean rePlay = playing(); + channel.rewind(); + if( toStream && rePlay ) + { + stop(); + play( channel ); + } + } + else + errorMessage( "Channel null in method 'rewind'" ); + } + +/** + * Dequeues any previously queued data. + */ + public void flush() + { + if( channel != null ) + channel.flush(); + else + errorMessage( "Channel null in method 'flush'" ); + } + +/** + * Stops and flushes the source, and prevents it from being played again until + * the activate() is called. + */ + public void cull() + { + if( !active( GET, XXX ) ) + return; + if( playing() && toLoop ) + toPlay = true; + if( rawDataStream ) + toPlay = true; + active( SET, false ); + if( channel != null ) + channel.close(); + channel = null; + } + +/** + * Allows a previously culled source to be played again. + */ + public void activate() + { + active( SET, true ); + } + +/** + * Returns false if the source has been culled. + * @return True or False + */ + public boolean active() + { + return active( GET, XXX ); + } + +/** + * Returns true if the source is playing. + * @return True or False + */ + public boolean playing() + { + if( channel == null || channel.attachedSource != this ) + return false; + else if( paused() || stopped() ) + return false; + else + return channel.playing(); + } + +/** + * Returns true if the source has been stopped. + * @return True or False + */ + public boolean stopped() + { + return stopped( GET, XXX ); + } + +/** + * Returns true if the source has been paused. + * @return True or False + */ + public boolean paused() + { + return paused( GET, XXX ); + } + +/** + * Returns the number of miliseconds since the source began playing. + * @return miliseconds, or -1 if not playing or unable to calculate + */ + public float millisecondsPlayed() + { + if( channel == null ) + return( -1 ); + else + return channel.millisecondsPlayed(); + } + +/** + * Sets or returns whether or not the source has been culled. + * @return True or False + */ + private synchronized boolean active( boolean action, boolean value ) + { + if( action == SET ) + active = value; + return active; + } + +/** + * Sets or returns whether or not the source has been stopped. + * @return True or False + */ + private synchronized boolean stopped( boolean action, boolean value ) + { + if( action == SET ) + stopped = value; + return stopped; + } + +/** + * Sets or returns whether or not the source has been paused. + * @return True or False + */ + private synchronized boolean paused( boolean action, boolean value ) + { + if( action == SET ) + paused = value; + return paused; + } + +/** + * Returns the name of the class. + * @return SoundLibraryXXXX. + */ + public String getClassName() + { + String libTitle = SoundSystemConfig.getLibraryTitle( libraryType ); + + if( libTitle.equals( "No Sound" ) ) + return "Source"; + else + return "Source" + libTitle; + } +/** + * Prints a message. + * @param message Message to print. + */ + protected void message( String message ) + { + logger.message( message, 0 ); + } + +/** + * Prints an important message. + * @param message Message to print. + */ + protected void importantMessage( String message ) + { + logger.importantMessage( message, 0 ); + } + +/** + * Prints the specified message if error is true. + * @param error True or False. + * @param message Message to print if error is true. + * @return True if error is true. + */ + protected boolean errorCheck( boolean error, String message ) + { + return logger.errorCheck( error, getClassName(), message, 0 ); + } + +/** + * Prints an error message. + * @param message Message to print. + */ + protected void errorMessage( String message ) + { + logger.errorMessage( getClassName(), message, 0 ); + } + +/** + * Prints an exception's error message followed by the stack trace. + * @param e Exception containing the information to print. + */ + protected void printStackTrace( Exception e ) + { + logger.printStackTrace( e, 1 ); + } +} diff --git a/src/lwjgl/java/paulscode/sound/StreamThread.java b/src/lwjgl/java/paulscode/sound/StreamThread.java new file mode 100644 index 0000000..ab237be --- /dev/null +++ b/src/lwjgl/java/paulscode/sound/StreamThread.java @@ -0,0 +1,303 @@ +package paulscode.sound; + +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; + +/** + * The StreamThread class is used to process all streaming sources. This + * thread starts out asleep, and it sleeps when all streaming sources are + * finished playing, so it is necessary to call interrupt() after adding new + * streaming sources to the list. + *

+ * SoundSystem License:

+ * You are free to use this library for any purpose, commercial or otherwise. + * You may modify this library or source code, and distribute it any way you + * like, provided the following conditions are met: + *
+ * 1) You may not falsely claim to be the author of this library or any + * unmodified portion of it. + *
+ * 2) You may not copyright this library or a modified version of it and then + * sue me for copyright infringement. + *
+ * 3) If you modify the source code, you must clearly document the changes + * made before redistributing the modified source code, so other users know + * it is not the original code. + *
+ * 4) You are not required to give me credit for this library in any derived + * work, but if you do, you must also mention my website: + * http://www.paulscode.com + *
+ * 5) I the author will not be responsible for any damages (physical, + * financial, or otherwise) caused by the use if this library or any part + * of it. + *
+ * 6) I the author do not guarantee, warrant, or make any representations, + * either expressed or implied, regarding the use of this library or any + * part of it. + *

+ * Author: Paul Lamb + *
+ * http://www.paulscode.com + *
+ * + */ +public class StreamThread extends SimpleThread +{ +/** + * Processes status messages, warnings, and error messages. + */ + private SoundSystemLogger logger; + +/** + * List of sources that are currently streaming. + */ + private List streamingSources; + +/** + * Used to synchronize access to the streaming sources list. + */ + private final Object listLock = new Object(); + +/** + * Constructor: Grabs a handle to the message logger and instantiates the + * streaming sources list. + */ + public StreamThread() + { + // grab a handle to the message logger: + logger = SoundSystemConfig.getLogger(); + + streamingSources = new LinkedList(); + } + +/** + * Removes all references to instantiated objects, and changes the thread's + * state to "not alive". Method alive() returns false when the cleanup() + * method has completed. + */ + @Override + protected void cleanup() + { + kill(); + super.cleanup(); // Important!! + } + +/** + * The main loop for processing commands. The thread sleeps when it finishes + * processing commands, and it must be interrupted to process more. + */ + @Override + public void run() + { + ListIterator iter; + Source src; + + // Start out asleep: + snooze( 3600000 ); + + while( !dying() ) + { + while( !dying() && !streamingSources.isEmpty() ) + { + // Make sure noone else is accessing the list of sources: + synchronized( listLock ) + { + iter = streamingSources.listIterator(); + while( !dying() && iter.hasNext() ) + { + src = iter.next(); + // If this is a removed source, we cleanup here and then let normal cleanup run - https://github.com/MinecraftForge/MinecraftForge/pull/4765 + if (src!=null && src.removed) + { + src.cleanup(); + src = null; + } + if( src == null ) + { + iter.remove(); + } + else if( src.stopped() ) + { + if( !src.rawDataStream ) + iter.remove(); + } + else if( !src.active() ) + { + if( src.toLoop || src.rawDataStream ) + src.toPlay = true; + iter.remove(); + } + else if( !src.paused() ) + { + src.checkFadeOut(); + if( (!src.stream()) && (!src.rawDataStream) ) + { + if( src.channel == null + || !src.channel.processBuffer() ) + { + if( src.nextCodec == null ) + { + src.readBuffersFromNextSoundInSequence(); + } +/* + if( src.getSoundSequenceQueueSize() > 0 ) + { + src.incrementSoundSequence(); + } + + // check if this is a looping source + else*/ if( src.toLoop ) + { + // wait for stream to finish playing + if( !src.playing() ) + { + // Generate an EOS event: + SoundSystemConfig.notifyEOS( + src.sourcename, + src.getSoundSequenceQueueSize() + ); + // Check if the source is currently + // in the process of fading out. + if( src.checkFadeOut() ) + { + // Source is fading out. + // Keep looping until it + // finishes. + src.preLoad = true; + } + else + { + // Source is not fading out. + // If there is another sound in + // the sequence, switch to it + // before replaying. + src.incrementSoundSequence(); + src.preLoad = true; // replay + } + } + } + else + { + // wait for stream to finish playing + if( !src.playing() ) + { + // Generate an EOS event: + SoundSystemConfig.notifyEOS( + src.sourcename, + src.getSoundSequenceQueueSize() + ); + // Check if the source is currently + // in the process of fading out + if( !src.checkFadeOut() ) + { + // Source is not fading out. + // Play anything else that is + // in the sound sequence queue. + if( + src.incrementSoundSequence() ) + src.preLoad = true; + else + iter.remove(); // finished + } + } + } + } + } + } + } + } + if( !dying() && !streamingSources.isEmpty() ) + snooze( 20 ); // sleep a bit so we don't peg the cpu + } + if( !dying() && streamingSources.isEmpty() ) + snooze( 3600000 ); // sleep until there is more to do. + } + + cleanup(); // Important!! + } + +/** + * Adds a new streaming source to the list. If another source in the list is + * already playing on the same channel, it is stopped and removed from the + * list. + * @param source New source to stream. + */ + public void watch( Source source ) + { + // make sure the source exists: + if( source == null ) + return; + + // make sure we aren't already watching this source: + if( streamingSources.contains( source ) ) + return; + + ListIterator iter; + Source src; + + // Make sure noone else is accessing the list of sources: + synchronized( listLock ) + { + // Any currently watched source which is null or playing on the + // same channel as the new source should be stopped and removed + // from the list. + iter = streamingSources.listIterator(); + while( iter.hasNext() ) + { + src = iter.next(); + if( src == null ) + { + iter.remove(); + } + else if( source.channel == src.channel ) + { + src.stop(); + iter.remove(); + } + } + + // Add the new source to the list: + streamingSources.add( source ); + } + } + +/** + * Prints a message. + * @param message Message to print. + */ + private void message( String message ) + { + logger.message( message, 0 ); + } + +/** + * Prints an important message. + * @param message Message to print. + */ + private void importantMessage( String message ) + { + logger.importantMessage( message, 0 ); + } + +/** + * Prints the specified message if error is true. + * @param error True or False. + * @param message Message to print if error is true. + * @return True if error is true. + */ + private boolean errorCheck( boolean error, String message ) + { + return logger.errorCheck( error, "StreamThread", message, 0 ); + } + +/** + * Prints an error message. + * @param message Message to print. + */ + private void errorMessage( String message ) + { + logger.errorMessage( "StreamThread", message, 0 ); + } +} diff --git a/src/lwjgl/java/paulscode/sound/Vector3D.java b/src/lwjgl/java/paulscode/sound/Vector3D.java new file mode 100644 index 0000000..5c38676 --- /dev/null +++ b/src/lwjgl/java/paulscode/sound/Vector3D.java @@ -0,0 +1,210 @@ +package paulscode.sound; + +/** + * The Vector3D class contains methods to simplify common 3D vector functions, + * such as cross and dot product, normalize, etc. + *

+ * SoundSystem License:

+ * You are free to use this library for any purpose, commercial or otherwise. + * You may modify this library or source code, and distribute it any way you + * like, provided the following conditions are met: + *
+ * 1) You may not falsely claim to be the author of this library or any + * unmodified portion of it. + *
+ * 2) You may not copyright this library or a modified version of it and then + * sue me for copyright infringement. + *
+ * 3) If you modify the source code, you must clearly document the changes + * made before redistributing the modified source code, so other users know + * it is not the original code. + *
+ * 4) You are not required to give me credit for this library in any derived + * work, but if you do, you must also mention my website: + * http://www.paulscode.com + *
+ * 5) I the author will not be responsible for any damages (physical, + * financial, or otherwise) caused by the use if this library or any part + * of it. + *
+ * 6) I the author do not guarantee, warrant, or make any representations, + * either expressed or implied, regarding the use of this library or any + * part of it. + *

+ * Author: Paul Lamb + *
+ * http://www.paulscode.com + *
+ */ +public class Vector3D +{ + +/** + * The vector's X coordinate. + */ + public float x; + +/** + * The vector's Y coordinate. + */ + public float y; + +/** + * The vector's Z coordinate. + */ + public float z; + +/** + * Constructor: Places the vector at the origin. + */ + public Vector3D() + { + x = 0.0f; + y = 0.0f; + z = 0.0f; + } + +/** + * Constructor: Places the vector at the specified 3D coordinates. + * @param nx X coordinate for the new vector. + * @param ny Y coordinate for the new vector. + * @param nz Z coordinate for the new vector. + */ + public Vector3D( float nx, float ny, float nz ) + { + x = nx; + y = ny; + z = nz; + } + +/** + * Returns a new instance containing the same information as this one. + * @return A new Vector3D. + */ + @Override + public Vector3D clone() + { + return new Vector3D( x, y, z ); + } + +/** + * Returns a vector containing the cross-product: A cross B. + * @param A First vector in the cross product. + * @param B Second vector in the cross product. + * @return A new Vector3D. + */ + public Vector3D cross( Vector3D A, Vector3D B ) + { + return new Vector3D( + A.y * B.z - B.y * A.z, + A.z * B.x - B.z * A.x, + A.x * B.y - B.x * A.y ); + } + +/** + * Returns a vector containing the cross-product: (this) cross B. + * @param B Second vector in the cross product. + * @return A new Vector3D. + */ + public Vector3D cross( Vector3D B ) + { + return new Vector3D( + y * B.z - B.y * z, + z * B.x - B.z * x, + x * B.y - B.x * y ); + + } + +/** + * Returns the dot-product result of: A dot B. + * @param A First vector in the dot product. + * @param B Second vector in the dot product. + * @return Dot product. + */ + public float dot( Vector3D A, Vector3D B ) + { + return( (A.x * B.x) + (A.y * B.y) + (A.z * B.z) ); + } + +/** + * Returns the dot-product result of: (this) dot B. + * @param B Second vector in the dot product. + * @return Dot product. + */ + public float dot( Vector3D B ) + { + return( (x * B.x) + (y * B.y) + (z * B.z) ); + } + +/** + * Returns the vector represented by: A + B. + * @param A First vector. + * @param B Vector to add to A. + * @return A new Vector3D. + */ + public Vector3D add( Vector3D A, Vector3D B ) + { + return new Vector3D( A.x + B.x, A.y + B.y, A.z + B.z ); + } + +/** + * Returns the vector represented by: (this) + B. + * @param B Vector to add to this one. + * @return A new Vector3D. + */ + public Vector3D add( Vector3D B ) + { + return new Vector3D( x + B.x, y + B.y, z + B.z ); + } + +/** + * Returns the vector represented by: A - B. + * @param A First vector. + * @param B Vector to subtract from A. + * @return A new Vector3D. + */ + public Vector3D subtract( Vector3D A, Vector3D B ) + { + return new Vector3D( A.x - B.x, A.y - B.y, A.z - B.z ); + } + +/** + * Returns the vector represented by: (this) - B. + * @param B Vector to subtract from this one. + * @return A new Vector3D. + */ + public Vector3D subtract( Vector3D B ) + { + return new Vector3D( x - B.x, y - B.y, z - B.z ); + } + +/** + * Returns the length of this vector. + * @return Length. + */ + public float length() + { + return (float) Math.sqrt( x * x + y * y + z * z ); + } + +/** + * Changes the length of this vector to 1.0. + */ + public void normalize() + { + double t = Math.sqrt( x*x + y*y + z*z ); + x = (float) (x / t); + y = (float) (y / t); + z = (float) (z / t); + } + +/** + * Returns a string depicting this vector. + * @return "Vector3D (x, y, z)". + */ + @Override + public String toString() + { + return "Vector3D (" + x + ", " + y + ", " + z + ")"; + } +} diff --git a/src/lwjgl/java/paulscode/sound/libraries/ChannelLWJGLOpenAL.java b/src/lwjgl/java/paulscode/sound/libraries/ChannelLWJGLOpenAL.java new file mode 100644 index 0000000..637d146 --- /dev/null +++ b/src/lwjgl/java/paulscode/sound/libraries/ChannelLWJGLOpenAL.java @@ -0,0 +1,696 @@ +package paulscode.sound.libraries; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.util.LinkedList; +import javax.sound.sampled.AudioFormat; + +// From the lwjgl library, http://www.lwjgl.org +import org.lwjgl.BufferUtils; +import org.lwjgl.openal.AL10; +import org.lwjgl.openal.AL11; + +import paulscode.sound.Channel; +import paulscode.sound.SoundSystemConfig; + +/** + * The ChannelLWJGLOpenAL class is used to reserve a sound-card voice using the + * lwjgl binding of OpenAL. Channels can be either normal or streaming + * channels. + *

+ * This software is based on or using the LWJGL Lightweight Java Gaming + * Library available from + * http://www.lwjgl.org/. + *


+ * LWJGL License: + *
+ * Copyright (c) 2002-2008 Lightweight Java Game Library Project + * All rights reserved. + *
+ * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + *
+ * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + *
+ * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + *
+ * * Neither the name of 'Light Weight Java Game Library' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *


+ * SoundSystem LibraryLWJGLOpenAL License:

+ * + * You are free to use this library for any purpose, commercial or otherwise. + * You may modify this library or source code, and distribute it any way you + * like, provided the following conditions are met: + *
+ * 1) You must abide by the conditions of the aforementioned LWJGL License. + *
+ * 2) You may not falsely claim to be the author of this library or any + * unmodified portion of it. + *
+ * 3) You may not copyright this library or a modified version of it and then + * sue me for copyright infringement. + *
+ * 4) If you modify the source code, you must clearly document the changes + * made before redistributing the modified source code, so other users know + * it is not the original code. + *
+ * 5) You are not required to give me credit for this library in any derived + * work, but if you do, you must also mention my website: + * http://www.paulscode.com + *
+ * 6) I the author will not be responsible for any damages (physical, + * financial, or otherwise) caused by the use if this library or any part + * of it. + *
+ * 7) I the author do not guarantee, warrant, or make any representations, + * either expressed or implied, regarding the use of this library or any + * part of it. + *

+ * Author: Paul Lamb + *
+ * http://www.paulscode.com + *
+ */ +public class ChannelLWJGLOpenAL extends Channel +{ +/** + * OpenAL's IntBuffer identifier for this channel. + */ + public IntBuffer ALSource; + +/** + * OpenAL data format to use when playing back the assigned source. + */ + public int ALformat; // OpenAL data format + +/** + * Sample rate (speed) to use for play-back. + */ + public int sampleRate; // sample rate + +/** + * Miliseconds of buffers previously played (streaming sources). + */ + public float millisPreviouslyPlayed = 0; + +/** + * Constructor: takes channelType identifier and a handle to the OpenAL + * IntBuffer identifier to use for this channel. Possible values for channel + * type can be found in the + * {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} class. + * @param type Type of channel (normal or streaming). + * @param src Handle to the OpenAL source identifier. + */ + public ChannelLWJGLOpenAL( int type, IntBuffer src ) + { + super( type ); + libraryType = LibraryLWJGLOpenAL.class; + ALSource = src; + } + +/** + * Empties the streamBuffers list, stops and deletes the ALSource, shuts the + * channel down, and removes references to all instantiated objects. + */ + @Override + public void cleanup() + { + if( ALSource != null ) + { + try + { + // Stop playing the source: + AL10.alSourceStop( ALSource ); + AL10.alGetError(); + } + catch( Exception e ) + {} + try + { + // Delete the source: + AL10.alDeleteSources( ALSource ); + AL10.alGetError(); + } + catch( Exception e ) + {} + ALSource.clear(); + } + ALSource = null; + + super.cleanup(); + } + +/** + * Attaches an OpenAL sound-buffer identifier for the sound data to be played + * back for a normal source. + * @param buf Intbuffer identifier for the sound data to play. + * @return False if an error occurred. + */ + public boolean attachBuffer( IntBuffer buf ) + { + // A sound buffer can only be attached to a normal source: + if( errorCheck( channelType != SoundSystemConfig.TYPE_NORMAL, + "Sound buffers may only be attached to normal " + + "sources." ) ) + return false; + + // send the sound buffer to the channel: + AL10.alSourcei( ALSource.get( 0 ), AL10.AL_BUFFER, + buf.get(0) ); + + + // save the format for later, for determining milliseconds played + if( attachedSource != null && attachedSource.soundBuffer != null && + attachedSource.soundBuffer.audioFormat != null ) + setAudioFormat( attachedSource.soundBuffer.audioFormat ); + + // Check for errors and return: + return checkALError(); + } +/** + * Sets the channel up to receive the specified audio format. + * @param audioFormat Format to use when playing the stream data. + */ + @Override + public void setAudioFormat( AudioFormat audioFormat ) + { + int soundFormat = 0; + if( audioFormat.getChannels() == 1 ) + { + if( audioFormat.getSampleSizeInBits() == 8 ) + { + soundFormat = AL10.AL_FORMAT_MONO8; + } + else if( audioFormat.getSampleSizeInBits() == 16 ) + { + soundFormat = AL10.AL_FORMAT_MONO16; + } + else + { + errorMessage( "Illegal sample size in method " + + "'setAudioFormat'" ); + return; + } + } + else if( audioFormat.getChannels() == 2 ) + { + if( audioFormat.getSampleSizeInBits() == 8 ) + { + soundFormat = AL10.AL_FORMAT_STEREO8; + } + else if( audioFormat.getSampleSizeInBits() == 16 ) + { + soundFormat = AL10.AL_FORMAT_STEREO16; + } + else + { + errorMessage( "Illegal sample size in method " + + "'setAudioFormat'" ); + return; + } + } + else + { + errorMessage( "Audio data neither mono nor stereo in " + + "method 'setAudioFormat'" ); + return; + } + ALformat = soundFormat; + sampleRate = (int) audioFormat.getSampleRate(); + } +/** + * Sets the channel up to receive the specified OpenAL audio format and sample + * rate. + * @param format Format to use. + * @param rate Sample rate (speed) to use. + */ + public void setFormat( int format, int rate ) + { + ALformat = format; + sampleRate = rate; + } + +/** + * Queues up the initial byte[] buffers of data to be streamed. + * @param bufferList List of the first buffers to be played for a streaming source. + * @return False if problem occurred or if end of stream was reached. + */ + @Override + public boolean preLoadBuffers( LinkedList bufferList ) + { + // Stream buffers can only be queued for streaming sources: + if( errorCheck( channelType != SoundSystemConfig.TYPE_STREAMING, + "Buffers may only be queued for streaming sources." ) ) + return false; + + if( errorCheck( bufferList == null, + "Buffer List null in method 'preLoadBuffers'" ) ) + return false; + + IntBuffer streamBuffers; + + // Remember if the channel was playing: + boolean playing = playing(); + // stop the channel if it is playing: + if( playing ) + { + AL10.alSourceStop( ALSource.get( 0 ) ); + checkALError(); + } + // Clear out any previously queued buffers: + int processed = AL10.alGetSourcei( ALSource.get( 0 ), + AL10.AL_BUFFERS_PROCESSED ); + if( processed > 0 ) + { + streamBuffers = BufferUtils.createIntBuffer( processed ); + AL10.alGenBuffers( streamBuffers ); + if( errorCheck( checkALError(), + "Error clearing stream buffers in method 'preLoadBuffers'" ) ) + return false; + AL10.alSourceUnqueueBuffers( ALSource.get( 0 ), streamBuffers ); + if( errorCheck( checkALError(), + "Error unqueuing stream buffers in method 'preLoadBuffers'" ) ) + return false; + } + + // restart the channel if it was previously playing: + if( playing ) + { + AL10.alSourcePlay( ALSource.get( 0 ) ); + checkALError(); + } + + streamBuffers = BufferUtils.createIntBuffer( bufferList.size() ); + AL10.alGenBuffers( streamBuffers ); + if( errorCheck( checkALError(), + "Error generating stream buffers in method 'preLoadBuffers'" ) ) + return false; + + ByteBuffer byteBuffer = null; + for( int i = 0; i < bufferList.size(); i++ ) + { + //byteBuffer = ByteBuffer.wrap( bufferList.get(i), 0, + // bufferList.get(i).length ); + byteBuffer = (ByteBuffer) BufferUtils.createByteBuffer( + bufferList.get(i).length ).put( bufferList.get( i ) ).flip(); + + try + { + AL10.alBufferData( streamBuffers.get(i), ALformat, byteBuffer, + sampleRate ); + } + catch( Exception e ) + { + errorMessage( "Error creating buffers in method " + + "'preLoadBuffers'" ); + printStackTrace( e ); + return false; + } + if( errorCheck( checkALError(), + "Error creating buffers in method 'preLoadBuffers'" ) ) + return false; + + } + + try + { + AL10.alSourceQueueBuffers( ALSource.get( 0 ), streamBuffers ); + } + catch( Exception e ) + { + errorMessage( "Error queuing buffers in method 'preLoadBuffers'" ); + printStackTrace( e ); + return false; + } + if( errorCheck( checkALError(), + "Error queuing buffers in method 'preLoadBuffers'" ) ) + return false; + + AL10.alSourcePlay( ALSource.get( 0 ) ); + if( errorCheck( checkALError(), + "Error playing source in method 'preLoadBuffers'" ) ) + return false; + + // Success: + return true; + } + +/** + * Queues up a byte[] buffer of data to be streamed. + * @param buffer The next buffer to be played for a streaming source. + * @return False if an error occurred or if the channel is shutting down. + */ + @Override + public boolean queueBuffer( byte[] buffer ) + { + // Stream buffers can only be queued for streaming sources: + if( errorCheck( channelType != SoundSystemConfig.TYPE_STREAMING, + "Buffers may only be queued for streaming sources." ) ) + return false; + + //ByteBuffer byteBuffer = ByteBuffer.wrap( buffer, 0, buffer.length ); + ByteBuffer byteBuffer = (ByteBuffer) BufferUtils.createByteBuffer( + buffer.length ).put( buffer ).flip(); + + IntBuffer intBuffer = BufferUtils.createIntBuffer( 1 ); + + AL10.alSourceUnqueueBuffers( ALSource.get( 0 ), intBuffer ); + if( checkALError() ) + return false; + + if( AL10.alIsBuffer( intBuffer.get( 0 ) ) ) + millisPreviouslyPlayed += millisInBuffer( intBuffer.get( 0 ) ); + checkALError(); + + AL10.alBufferData( intBuffer.get(0), ALformat, byteBuffer, sampleRate ); + if( checkALError() ) + return false; + + AL10.alSourceQueueBuffers( ALSource.get( 0 ), intBuffer ); + if( checkALError() ) + return false; + + return true; + } + +/** + * Feeds raw data to the stream. + * @param buffer Buffer containing raw audio data to stream. + * @return Number of prior buffers that have been processed., or -1 if error. + */ + @Override + public int feedRawAudioData( byte[] buffer ) + { + // Stream buffers can only be queued for streaming sources: + if( errorCheck( channelType != SoundSystemConfig.TYPE_STREAMING, + "Raw audio data can only be fed to streaming sources." ) ) + return -1; + + //ByteBuffer byteBuffer = ByteBuffer.wrap( buffer, 0, buffer.length ); + ByteBuffer byteBuffer = (ByteBuffer) BufferUtils.createByteBuffer( + buffer.length ).put( buffer ).flip(); + + IntBuffer intBuffer; + + // Clear out any previously queued buffers: + int processed = AL10.alGetSourcei( ALSource.get( 0 ), + AL10.AL_BUFFERS_PROCESSED ); + if( processed > 0 ) + { + intBuffer = BufferUtils.createIntBuffer( processed ); + AL10.alGenBuffers( intBuffer ); + if( errorCheck( checkALError(), + "Error clearing stream buffers in method 'feedRawAudioData'" ) ) + return -1; + AL10.alSourceUnqueueBuffers( ALSource.get( 0 ), intBuffer ); + if( errorCheck( checkALError(), + "Error unqueuing stream buffers in method 'feedRawAudioData'" ) ) + return -1; + int i; + intBuffer.rewind(); + while( intBuffer.hasRemaining() ) + { + i = intBuffer.get(); + if( AL10.alIsBuffer( i ) ) + { + millisPreviouslyPlayed += millisInBuffer( i ); + } + checkALError(); + } + AL10.alDeleteBuffers( intBuffer ); + checkALError(); + } + intBuffer = BufferUtils.createIntBuffer( 1 ); + AL10.alGenBuffers( intBuffer ); + if( errorCheck( checkALError(), + "Error generating stream buffers in method 'preLoadBuffers'" ) ) + return -1; + + AL10.alBufferData( intBuffer.get(0), ALformat, byteBuffer, sampleRate ); + if( checkALError() ) + return -1; + + AL10.alSourceQueueBuffers( ALSource.get( 0 ), intBuffer ); + if( checkALError() ) + return -1; + + if( attachedSource != null && attachedSource.channel == this && + attachedSource.active() ) + { + // restart the channel if it was previously playing: + if( !playing() ) + { + AL10.alSourcePlay( ALSource.get( 0 ) ); + checkALError(); + } + } + + return processed; + } + +/** + * Returns the number of milliseconds of audio contained in specified buffer. + * @return milliseconds, or 0 if unable to calculate. + */ + public float millisInBuffer( int alBufferi ) + { + return( ( (float) AL10.alGetBufferi( alBufferi, AL10.AL_SIZE ) / + (float) AL10.alGetBufferi( alBufferi, AL10.AL_CHANNELS ) / + ( (float) AL10.alGetBufferi( alBufferi, AL10.AL_BITS ) / 8.0f ) / + (float) sampleRate ) * 1000 ); + } + +/** + * Calculates the number of milliseconds since the channel began playing. + * @return Milliseconds, or -1 if unable to calculate. + */ + @Override + public float millisecondsPlayed() + { + // get number of samples played in current buffer + float offset = (float)AL10.alGetSourcei( ALSource.get( 0 ), + AL11.AL_BYTE_OFFSET ); + + float bytesPerFrame = 1f; + switch( ALformat ) + { + case AL10.AL_FORMAT_MONO8 : + bytesPerFrame = 1f; + break; + case AL10.AL_FORMAT_MONO16 : + bytesPerFrame = 2f; + break; + case AL10.AL_FORMAT_STEREO8 : + bytesPerFrame = 2f; + break; + case AL10.AL_FORMAT_STEREO16 : + bytesPerFrame = 4f; + break; + default : + break; + } + + offset = ( ( (float) offset / bytesPerFrame ) / (float) sampleRate ) + * 1000; + + // add the milliseconds from stream-buffers that played previously + if( channelType == SoundSystemConfig.TYPE_STREAMING ) + offset += millisPreviouslyPlayed; + + // Return millis played: + return( offset ); + } + +/** + * Returns the number of queued byte[] buffers that have finished playing. + * @return Number of buffers processed. + */ + @Override + public int buffersProcessed() + { + // Only streaming sources process buffers: + if( channelType != SoundSystemConfig.TYPE_STREAMING ) + return 0; + + // determine how many have been processed: + int processed = AL10.alGetSourcei( ALSource.get( 0 ), + AL10.AL_BUFFERS_PROCESSED ); + + // Check for errors: + if( checkALError() ) + return 0; + + // Return how many were processed: + return processed; + } + +/** + * Dequeues all previously queued data. + */ + @Override + public void flush() + { + // Only a streaming source can be flushed, because only streaming + // sources have queued buffers: + if( channelType != SoundSystemConfig.TYPE_STREAMING ) + return; + + // determine how many buffers have been queued: + int queued = AL10.alGetSourcei( ALSource.get( 0 ), + AL10.AL_BUFFERS_QUEUED ); + // Check for errors: + if( checkALError() ) + return; + + IntBuffer intBuffer = BufferUtils.createIntBuffer( 1 ); + while( queued > 0 ) + { + try + { + AL10.alSourceUnqueueBuffers( ALSource.get( 0 ), intBuffer ); + } + catch( Exception e ) + { + return; + } + if( checkALError() ) + return; + queued--; + } + millisPreviouslyPlayed = 0; + } + +/** + * Stops the channel, dequeues any queued data, and closes the channel. + */ + @Override + public void close() + { + try + { + AL10.alSourceStop( ALSource.get( 0 ) ); + AL10.alGetError(); + } + catch( Exception e ) + {} + + if( channelType == SoundSystemConfig.TYPE_STREAMING ) + flush(); + } + +/** + * Plays the currently attached normal source, opens this channel up for + * streaming, or resumes playback if this channel was paused. + */ + @Override + public void play() + { + AL10.alSourcePlay( ALSource.get( 0 ) ); + checkALError(); + } + +/** + * Temporarily stops playback for this channel. + */ + @Override + public void pause() + { + AL10.alSourcePause( ALSource.get( 0 ) ); + checkALError(); + } + +/** + * Stops playback for this channel and rewinds the attached source to the + * beginning. + */ + @Override + public void stop() + { + AL10.alSourceStop( ALSource.get( 0 ) ); + if( !checkALError() ) + millisPreviouslyPlayed = 0; + } + +/** + * Rewinds the attached source to the beginning. Stops the source if it was + * paused. + */ + @Override + public void rewind() + { + // rewinding for streaming sources is handled elsewhere + if( channelType == SoundSystemConfig.TYPE_STREAMING ) + return; + + AL10.alSourceRewind( ALSource.get( 0 ) ); + if( !checkALError() ) + millisPreviouslyPlayed = 0; + } + + +/** + * Used to determine if a channel is actively playing a source. This method + * will return false if the channel is paused or stopped and when no data is + * queued to be streamed. + * @return True if this channel is playing a source. + */ + @Override + public boolean playing() + { + int state = AL10.alGetSourcei( ALSource.get( 0 ), + AL10.AL_SOURCE_STATE ); + if( checkALError() ) + return false; + + return( state == AL10.AL_PLAYING ); + } + +/** + * Checks for OpenAL errors, and prints a message if there is an error. + * @return True if there was an error, False if not. + */ + private boolean checkALError() + { + switch( AL10.alGetError() ) + { + case AL10.AL_NO_ERROR: + return false; + case AL10.AL_INVALID_NAME: + errorMessage( "Invalid name parameter." ); + return true; + case AL10.AL_INVALID_ENUM: + errorMessage( "Invalid parameter." ); + return true; + case AL10.AL_INVALID_VALUE: + errorMessage( "Invalid enumerated parameter value." ); + return true; + case AL10.AL_INVALID_OPERATION: + errorMessage( "Illegal call." ); + return true; + case AL10.AL_OUT_OF_MEMORY: + errorMessage( "Unable to allocate memory." ); + return true; + default: + errorMessage( "An unrecognized error occurred." ); + return true; + } + } +} diff --git a/src/lwjgl/java/paulscode/sound/libraries/LibraryLWJGLOpenAL.java b/src/lwjgl/java/paulscode/sound/libraries/LibraryLWJGLOpenAL.java new file mode 100644 index 0000000..1b1b939 --- /dev/null +++ b/src/lwjgl/java/paulscode/sound/libraries/LibraryLWJGLOpenAL.java @@ -0,0 +1,1126 @@ +package paulscode.sound.libraries; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.nio.FloatBuffer; +import java.net.URL; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Set; +import javax.sound.sampled.AudioFormat; + +// From the lwjgl library, http://www.lwjgl.org +import org.lwjgl.BufferUtils; +import org.lwjgl.LWJGLException; +import org.lwjgl.openal.AL; +import org.lwjgl.openal.AL10; + +import paulscode.sound.Channel; +import paulscode.sound.FilenameURL; +import paulscode.sound.ICodec; +import paulscode.sound.Library; +import paulscode.sound.ListenerData; +import paulscode.sound.SoundBuffer; +import paulscode.sound.SoundSystemConfig; +import paulscode.sound.SoundSystemException; +import paulscode.sound.Source; + +/** + * The LibraryLWJGLOpenAL class interfaces the lwjgl binding of OpenAL. + *

+ * This software is based on or using the LWJGL Lightweight Java Gaming + * Library available from + * http://www.lwjgl.org/. + *


+ * LWJGL License: + *
+ * Copyright (c) 2002-2008 Lightweight Java Game Library Project + * All rights reserved. + *
+ * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + *
+ * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + *
+ * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + *
+ * * Neither the name of 'Light Weight Java Game Library' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *


+ * SoundSystem LibraryLWJGLOpenAL License:

+ * + * You are free to use this library for any purpose, commercial or otherwise. + * You may modify this library or source code, and distribute it any way you + * like, provided the following conditions are met: + *
+ * 1) You must abide by the conditions of the aforementioned LWJGL License. + *
+ * 2) You may not falsely claim to be the author of this library or any + * unmodified portion of it. + *
+ * 3) You may not copyright this library or a modified version of it and then + * sue me for copyright infringement. + *
+ * 4) If you modify the source code, you must clearly document the changes + * made before redistributing the modified source code, so other users know + * it is not the original code. + *
+ * 5) You are not required to give me credit for this library in any derived + * work, but if you do, you must also mention my website: + * http://www.paulscode.com + *
+ * 6) I the author will not be responsible for any damages (physical, + * financial, or otherwise) caused by the use if this library or any part + * of it. + *
+ * 7) I the author do not guarantee, warrant, or make any representations, + * either expressed or implied, regarding the use of this library or any + * part of it. + *

+ * Author: Paul Lamb + *
+ * http://www.paulscode.com + *
+ */ +public class LibraryLWJGLOpenAL extends Library +{ +/** + * Used to return a current value from one of the synchronized + * boolean-interface methods. + */ + private static final boolean GET = false; +/** + * Used to set the value in one of the synchronized boolean-interface methods. + */ + private static final boolean SET = true; +/** + * Used when a parameter for one of the synchronized boolean-interface methods + * is not aplicable. + */ + private static final boolean XXX = false; + +/** + * Position of the listener in 3D space. + */ + private FloatBuffer listenerPositionAL = null; +/** + * Information about the listener's orientation. + */ + private FloatBuffer listenerOrientation = null; +/** + * Velocity of the listener. + */ + private FloatBuffer listenerVelocity = null; +/** + * Map containing OpenAL identifiers for sound buffers. + */ + private HashMap ALBufferMap = null; + +/** + * Whether or not the AL_PITCH control is supported. + */ + private static boolean alPitchSupported = true; + +/** + * Constructor: Instantiates the source map, buffer map and listener + * information. Also sets the library type to + * SoundSystemConfig.LIBRARY_OPENAL + */ + public LibraryLWJGLOpenAL() throws SoundSystemException + { + super(); + ALBufferMap = new HashMap(); + reverseByteOrder = true; + } + +/** + * Initializes OpenAL, creates the listener, and grabs up audio channels. + */ + @Override + public void init() throws SoundSystemException + { + boolean errors = false; // set to 'true' if error(s) occur: + + try + { + // Try and create the sound system: + AL.create(); + errors = checkALError(); + } + catch( LWJGLException e ) + { + // There was an exception + errorMessage( "Unable to initialize OpenAL. Probable cause: " + + "OpenAL not supported." ); + printStackTrace( e ); + throw new LibraryLWJGLOpenAL.Exception( e.getMessage(), + LibraryLWJGLOpenAL.Exception.CREATE ); + } + + // Let user know if the library loaded properly + if( errors ) + importantMessage( "OpenAL did not initialize properly!" ); + else + message( "OpenAL initialized." ); + + // Listener is at the origin, facing along the z axis, no velocity: + listenerPositionAL = BufferUtils.createFloatBuffer( 3 ).put( + new float[] { listener.position.x, + listener.position.y, + listener.position.z } ); + listenerOrientation = BufferUtils.createFloatBuffer( 6 ).put ( + new float[] { listener.lookAt.x, listener.lookAt.y, + listener.lookAt.z, listener.up.x, listener.up.y, + listener.up.z } ); + listenerVelocity = BufferUtils.createFloatBuffer( 3 ).put ( + new float[] { 0.0f, 0.0f, 0.0f } ); + + // Flip the buffers, so they can be used: + listenerPositionAL.flip(); + listenerOrientation.flip(); + listenerVelocity.flip(); + + // Pass the buffers to the sound system, and check for potential errors: + AL10.alListener( AL10.AL_POSITION, listenerPositionAL ); + errors = checkALError() || errors; + AL10.alListener( AL10.AL_ORIENTATION, listenerOrientation ); + errors = checkALError() || errors; + AL10.alListener( AL10.AL_VELOCITY, listenerVelocity ); + errors = checkALError() || errors; + + AL10.alDopplerFactor( SoundSystemConfig.getDopplerFactor() ); + errors = checkALError() || errors; + + AL10.alDopplerVelocity( SoundSystemConfig.getDopplerVelocity() ); + errors = checkALError() || errors; + + // Let user know what caused the above error messages: + if( errors ) + { + importantMessage( "OpenAL did not initialize properly!" ); + throw new LibraryLWJGLOpenAL.Exception( "Problem encountered " + + "while loading OpenAL or " + + "creating the listener. " + + "Probable cause: OpenAL not " + + "supported", + LibraryLWJGLOpenAL.Exception.CREATE ); + } + + super.init(); + + // Check if we can use the AL_PITCH control: + ChannelLWJGLOpenAL channel = (ChannelLWJGLOpenAL) + normalChannels.get( 1 ); + try + { + AL10.alSourcef( channel.ALSource.get( 0 ), + AL10.AL_PITCH, 1.0f ); + if( checkALError() ) + { + alPitchSupported( SET, false ); + throw new LibraryLWJGLOpenAL.Exception( "OpenAL: AL_PITCH not " + + "supported.", LibraryLWJGLOpenAL.Exception.NO_AL_PITCH ); + } + else + { + alPitchSupported( SET, true ); + } + } + catch( java.lang.Exception e ) + { + alPitchSupported( SET, false ); + throw new LibraryLWJGLOpenAL.Exception( "OpenAL: AL_PITCH not " + + "supported.", LibraryLWJGLOpenAL.Exception.NO_AL_PITCH ); + } + } + +/** + * Checks if the OpenAL library type is compatible. + * @return True or false. + */ + public static boolean libraryCompatible() + { + if( AL.isCreated() ) + return true; + + try + { + AL.create(); + } + catch( java.lang.Exception e ) + { + return false; + } + + try + { + AL.destroy(); + } + catch( java.lang.Exception e ) + {} + + return true; + } + +/** + * Creates a new channel of the specified type (normal or streaming). Possible + * values for channel type can be found in the + * {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} class. + * @param type Type of channel. + */ + @Override + protected Channel createChannel( int type ) + { + ChannelLWJGLOpenAL channel; + IntBuffer ALSource; + + ALSource = BufferUtils.createIntBuffer( 1 ); + try + { + AL10.alGenSources( ALSource ); + } + catch( java.lang.Exception e ) + { + AL10.alGetError(); + return null; // no more voices left + } + + if( AL10.alGetError() != AL10.AL_NO_ERROR ) + return null; + + channel = new ChannelLWJGLOpenAL( type, ALSource ); + return channel; + } + + /** + * Stops all sources, shuts down OpenAL, and removes references to all + * instantiated objects. + */ + @Override + public void cleanup() + { + super.cleanup(); + + Set keys = bufferMap.keySet(); + Iterator iter = keys.iterator(); + String filename; + IntBuffer buffer; + + // loop through and clear all sound buffers: + while( iter.hasNext() ) + { + filename = iter.next(); + buffer = ALBufferMap.get( filename ); + if( buffer != null ) + { + AL10.alDeleteBuffers( buffer ); + checkALError(); + buffer.clear(); + } + } + + bufferMap.clear(); + AL.destroy(); + + bufferMap = null; + listenerPositionAL = null; + listenerOrientation = null; + listenerVelocity = null; + } + +/** + * Pre-loads a sound into memory. + * @param filenameURL Filename/URL of the sound file to load. + * @return True if the sound loaded properly. + */ + @Override + public boolean loadSound( FilenameURL filenameURL ) + { + // Make sure the buffer map exists: + if( bufferMap == null ) + { + bufferMap = new HashMap(); + importantMessage( "Buffer Map was null in method 'loadSound'" ); + } + // Make sure the OpenAL buffer map exists: + if( ALBufferMap == null ) + { + ALBufferMap = new HashMap(); + importantMessage( "Open AL Buffer Map was null in method" + + "'loadSound'" ); + } + + // make sure they gave us a filename: + if( errorCheck( filenameURL == null, + "Filename/URL not specified in method 'loadSound'" ) ) + return false; + + // check if it is already loaded: + if( bufferMap.get( filenameURL.getFilename() ) != null ) + return true; + + ICodec codec = SoundSystemConfig.getCodec( filenameURL.getFilename() ); + if( errorCheck( codec == null, "No codec found for file '" + + filenameURL.getFilename() + + "' in method 'loadSound'" ) ) + return false; + codec.reverseByteOrder( true ); + + URL url = filenameURL.getURL(); + if( errorCheck( url == null, "Unable to open file '" + + filenameURL.getFilename() + + "' in method 'loadSound'" ) ) + return false; + + codec.initialize( url ); + SoundBuffer buffer = codec.readAll(); + codec.cleanup(); + codec = null; + if( errorCheck( buffer == null, + "Sound buffer null in method 'loadSound'" ) ) + return false; + + bufferMap.put( filenameURL.getFilename(), buffer ); + + AudioFormat audioFormat = buffer.audioFormat; + int soundFormat = 0; + if( audioFormat.getChannels() == 1 ) + { + if( audioFormat.getSampleSizeInBits() == 8 ) + { + soundFormat = AL10.AL_FORMAT_MONO8; + } + else if( audioFormat.getSampleSizeInBits() == 16 ) + { + soundFormat = AL10.AL_FORMAT_MONO16; + } + else + { + errorMessage( "Illegal sample size in method 'loadSound'" ); + return false; + } + } + else if( audioFormat.getChannels() == 2 ) + { + if( audioFormat.getSampleSizeInBits() == 8 ) + { + soundFormat = AL10.AL_FORMAT_STEREO8; + } + else if( audioFormat.getSampleSizeInBits() == 16 ) + { + soundFormat = AL10.AL_FORMAT_STEREO16; + } + else + { + errorMessage( "Illegal sample size in method 'loadSound'" ); + return false; + } + } + else + { + errorMessage( "File neither mono nor stereo in method " + + "'loadSound'" ); + return false; + } + + IntBuffer intBuffer = BufferUtils.createIntBuffer( 1 ); + AL10.alGenBuffers( intBuffer ); + if( errorCheck( AL10.alGetError() != AL10.AL_NO_ERROR, + "alGenBuffers error when loading " + + filenameURL.getFilename() ) ) + return false; + +// AL10.alBufferData( intBuffer.get( 0 ), soundFormat, +// ByteBuffer.wrap( buffer.audioData ), +// (int) audioFormat.getSampleRate() ); + AL10.alBufferData( intBuffer.get( 0 ), soundFormat, + (ByteBuffer) BufferUtils.createByteBuffer( + buffer.audioData.length ).put( + buffer.audioData ).flip(), + (int) audioFormat.getSampleRate() ); + + if( errorCheck( AL10.alGetError() != AL10.AL_NO_ERROR, + "alBufferData error when loading " + + filenameURL.getFilename() ) ) + + + if( errorCheck( intBuffer == null, + "Sound buffer was not created for " + + filenameURL.getFilename() ) ) + return false; + + ALBufferMap.put( filenameURL.getFilename(), intBuffer ); + + return true; + } + +/** + * Saves the specified sample data, under the specified identifier. This + * identifier can be later used in place of 'filename' parameters to reference + * the sample data. + * @param buffer the sample data and audio format to save. + * @param identifier What to call the sample. + * @return True if there weren't any problems. + */ + @Override + public boolean loadSound( SoundBuffer buffer, String identifier ) + { + // Make sure the buffer map exists: + if( bufferMap == null ) + { + bufferMap = new HashMap(); + importantMessage( "Buffer Map was null in method 'loadSound'" ); + } + // Make sure the OpenAL buffer map exists: + if( ALBufferMap == null ) + { + ALBufferMap = new HashMap(); + importantMessage( "Open AL Buffer Map was null in method" + + "'loadSound'" ); + } + + // make sure they gave us an identifier: + if( errorCheck( identifier == null, + "Identifier not specified in method 'loadSound'" ) ) + return false; + + // check if it is already loaded: + if( bufferMap.get( identifier ) != null ) + return true; + + if( errorCheck( buffer == null, + "Sound buffer null in method 'loadSound'" ) ) + return false; + + bufferMap.put( identifier, buffer ); + + AudioFormat audioFormat = buffer.audioFormat; + int soundFormat = 0; + if( audioFormat.getChannels() == 1 ) + { + if( audioFormat.getSampleSizeInBits() == 8 ) + { + soundFormat = AL10.AL_FORMAT_MONO8; + } + else if( audioFormat.getSampleSizeInBits() == 16 ) + { + soundFormat = AL10.AL_FORMAT_MONO16; + } + else + { + errorMessage( "Illegal sample size in method 'loadSound'" ); + return false; + } + } + else if( audioFormat.getChannels() == 2 ) + { + if( audioFormat.getSampleSizeInBits() == 8 ) + { + soundFormat = AL10.AL_FORMAT_STEREO8; + } + else if( audioFormat.getSampleSizeInBits() == 16 ) + { + soundFormat = AL10.AL_FORMAT_STEREO16; + } + else + { + errorMessage( "Illegal sample size in method 'loadSound'" ); + return false; + } + } + else + { + errorMessage( "File neither mono nor stereo in method " + + "'loadSound'" ); + return false; + } + + IntBuffer intBuffer = BufferUtils.createIntBuffer( 1 ); + AL10.alGenBuffers( intBuffer ); + if( errorCheck( AL10.alGetError() != AL10.AL_NO_ERROR, + "alGenBuffers error when saving " + + identifier ) ) + return false; + +// AL10.alBufferData( intBuffer.get( 0 ), soundFormat, +// ByteBuffer.wrap( buffer.audioData ), +// (int) audioFormat.getSampleRate() ); + AL10.alBufferData( intBuffer.get( 0 ), soundFormat, + (ByteBuffer) BufferUtils.createByteBuffer( + buffer.audioData.length ).put( + buffer.audioData ).flip(), + (int) audioFormat.getSampleRate() ); + + if( errorCheck( AL10.alGetError() != AL10.AL_NO_ERROR, + "alBufferData error when saving " + + identifier ) ) + + + if( errorCheck( intBuffer == null, + "Sound buffer was not created for " + + identifier ) ) + return false; + + ALBufferMap.put( identifier, intBuffer ); + + return true; + } + +/** + * Removes a pre-loaded sound from memory. This is a good method to use for + * freeing up memory after a large sound file is no longer needed. NOTE: the + * source will remain in memory after this method has been called, for as long + * as the sound is attached to an existing source. + * @param filename Filename/identifier of the sound file to unload. + */ + @Override + public void unloadSound( String filename ) + { + ALBufferMap.remove( filename ); + super.unloadSound( filename ); + } + + /** + * Sets the overall volume to the specified value, affecting all sources. + * @param value New volume, float value ( 0.0f - 1.0f ). + */ + @Override + public void setMasterVolume( float value ) + { + super.setMasterVolume( value ); + + AL10.alListenerf( AL10.AL_GAIN, value ); + checkALError(); + } + +/** + * Creates a new source and places it into the source map. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param toStream Setting this to true will load the sound in pieces rather than all at once. + * @param toLoop Should this source loop, or play only once. + * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename. + * @param filenameURL Filename/URL of the sound file to play at this source. + * @param x X position for this source. + * @param y Y position for this source. + * @param z Z position for this source. + * @param attModel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel". + */ + @Override + public void newSource( boolean priority, boolean toStream, boolean toLoop, + String sourcename, FilenameURL filenameURL, float x, + float y, float z, int attModel, float distOrRoll ) + { + IntBuffer myBuffer = null; + if( !toStream ) + { + // Grab the sound buffer for this file: + myBuffer = ALBufferMap.get( filenameURL.getFilename() ); + + // if not found, try loading it: + if( myBuffer == null ) + { + if( !loadSound( filenameURL ) ) + { + errorMessage( "Source '" + sourcename + "' was not created " + + "because an error occurred while loading " + + filenameURL.getFilename() ); + return; + } + } + + // try and grab the sound buffer again: + myBuffer = ALBufferMap.get( filenameURL.getFilename() ); + // see if it was there this time: + if( myBuffer == null ) + { + errorMessage( "Source '" + sourcename + "' was not created " + + "because a sound buffer was not found for " + + filenameURL.getFilename() ); + return; + } + } + SoundBuffer buffer = null; + + if( !toStream ) + { + // Grab the audio data for this file: + buffer = bufferMap.get( filenameURL.getFilename() ); + // if not found, try loading it: + if( buffer == null ) + { + if( !loadSound( filenameURL ) ) + { + errorMessage( "Source '" + sourcename + "' was not created " + + "because an error occurred while loading " + + filenameURL.getFilename() ); + return; + } + } + // try and grab the sound buffer again: + buffer = bufferMap.get( filenameURL.getFilename() ); + // see if it was there this time: + if( buffer == null ) + { + errorMessage( "Source '" + sourcename + "' was not created " + + "because audio data was not found for " + + filenameURL.getFilename() ); + return; + } + } + + sourceMap.put( sourcename, + new SourceLWJGLOpenAL( listenerPositionAL, myBuffer, + priority, toStream, toLoop, + sourcename, filenameURL, buffer, x, + y, z, attModel, distOrRoll, + false ) ); + } + + /** + * Opens a direct line for streaming audio data. + * @param audioFormat Format that the data will be in. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename. + * @param x X position for this source. + * @param y Y position for this source. + * @param z Z position for this source. + * @param attModel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel". + */ + @Override + public void rawDataStream( AudioFormat audioFormat, boolean priority, + String sourcename, float x, float y, + float z, int attModel, float distOrRoll ) + { + sourceMap.put( sourcename, + new SourceLWJGLOpenAL( listenerPositionAL, audioFormat, + priority, sourcename, x, y, z, + attModel, distOrRoll ) ); + } + +/** + * Creates and immediately plays a new source. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param toStream Setting this to true will load the sound in pieces rather than all at once. + * @param toLoop Should this source loop, or play only once. + * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename. + * @param filenameURL Filename/URL of the sound file to play at this source. + * @param x X position for this source. + * @param y Y position for this source. + * @param z Z position for this source. + * @param attModel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel". + * @param temporary Whether or not this source should be removed after it finishes playing. + */ + @Override + public void quickPlay( boolean priority, boolean toStream, boolean toLoop, + String sourcename, FilenameURL filenameURL, float x, + float y, float z, int attModel, float distOrRoll, + boolean temporary ) + { + IntBuffer myBuffer = null; + if( !toStream ) + { + // Grab the sound buffer for this file: + myBuffer = ALBufferMap.get( filenameURL.getFilename() ); + // if not found, try loading it: + if( myBuffer == null ) + loadSound( filenameURL ); + // try and grab the sound buffer again: + myBuffer = ALBufferMap.get( filenameURL.getFilename() ); + // see if it was there this time: + if( myBuffer == null ) + { + errorMessage( "Sound buffer was not created for " + + filenameURL.getFilename() ); + return; + } + } + + SoundBuffer buffer = null; + + if( !toStream ) + { + // Grab the sound buffer for this file: + buffer = bufferMap.get( filenameURL.getFilename() ); + // if not found, try loading it: + if( buffer == null ) + { + if( !loadSound( filenameURL ) ) + { + errorMessage( "Source '" + sourcename + "' was not created " + + "because an error occurred while loading " + + filenameURL.getFilename() ); + return; + } + } + // try and grab the sound buffer again: + buffer = bufferMap.get( filenameURL.getFilename() ); + // see if it was there this time: + if( buffer == null ) + { + errorMessage( "Source '" + sourcename + "' was not created " + + "because audio data was not found for " + + filenameURL.getFilename() ); + return; + } + } + SourceLWJGLOpenAL s = new SourceLWJGLOpenAL( listenerPositionAL, + myBuffer, priority, + toStream, toLoop, + sourcename, filenameURL, + buffer, x, y, z, + attModel, distOrRoll, + false ); + + sourceMap.put( sourcename, s ); + play( s ); + if( temporary ) + s.setTemporary( true ); +} + +/** + * Creates sources based on the source map provided. + * @param srcMap Sources to copy. + */ + @Override + public void copySources( HashMap srcMap ) + { + if( srcMap == null ) + return; + Set keys = srcMap.keySet(); + Iterator iter = keys.iterator(); + String sourcename; + Source source; + + // Make sure the buffer map exists: + if( bufferMap == null ) + { + bufferMap = new HashMap(); + importantMessage( "Buffer Map was null in method 'copySources'" ); + } + // Make sure the OpenAL buffer map exists: + if( ALBufferMap == null ) + { + ALBufferMap = new HashMap(); + importantMessage( "Open AL Buffer Map was null in method" + + "'copySources'" ); + } + + // remove any existing sources before starting: + sourceMap.clear(); + + SoundBuffer buffer; + // loop through and copy all the sources: + while( iter.hasNext() ) + { + sourcename = iter.next(); + source = srcMap.get( sourcename ); + if( source != null ) + { + buffer = null; + if( !source.toStream ) + { + loadSound( source.filenameURL ); + buffer = bufferMap.get( source.filenameURL.getFilename() ); + } + if( source.toStream || buffer != null ) + sourceMap.put( sourcename, new SourceLWJGLOpenAL( + listenerPositionAL, + ALBufferMap.get( + source.filenameURL.getFilename() ), + source, buffer ) ); + } + } + } + +/** + * Changes the listener's position. + * @param x Destination X coordinate. + * @param y Destination Y coordinate. + * @param z Destination Z coordinate. + */ + @Override + public void setListenerPosition( float x, float y, float z ) + { + super.setListenerPosition( x, y, z ); + + listenerPositionAL.put( 0, x ); + listenerPositionAL.put( 1, y ); + listenerPositionAL.put( 2, z ); + + // Update OpenAL listener position: + AL10.alListener( AL10.AL_POSITION, listenerPositionAL ); + // Check for errors: + checkALError(); + } + +/** + * Changes the listeners orientation to the specified 'angle' radians + * counterclockwise around the y-Axis. + * @param angle Radians. + */ + @Override + public void setListenerAngle( float angle ) + { + super.setListenerAngle( angle ); + + listenerOrientation.put( 0, listener.lookAt.x ); + listenerOrientation.put( 2, listener.lookAt.z ); + + // Update OpenAL listener orientation: + AL10.alListener( AL10.AL_ORIENTATION, listenerOrientation ); + // Check for errors: + checkALError(); + } + +/** + * Changes the listeners orientation using the specified coordinates. + * @param lookX X element of the look-at direction. + * @param lookY Y element of the look-at direction. + * @param lookZ Z element of the look-at direction. + * @param upX X element of the up direction. + * @param upY Y element of the up direction. + * @param upZ Z element of the up direction. + */ + @Override + public void setListenerOrientation( float lookX, float lookY, float lookZ, + float upX, float upY, float upZ ) + { + super.setListenerOrientation( lookX, lookY, lookZ, upX, upY, upZ ); + listenerOrientation.put( 0, lookX ); + listenerOrientation.put( 1, lookY ); + listenerOrientation.put( 2, lookZ ); + listenerOrientation.put( 3, upX ); + listenerOrientation.put( 4, upY ); + listenerOrientation.put( 5, upZ ); + AL10.alListener( AL10.AL_ORIENTATION, listenerOrientation ); + checkALError(); + } + +/** + * Changes the listeners position and orientation using the specified listener + * data. + * @param l Listener data to use. + */ + @Override + public void setListenerData( ListenerData l ) + { + super.setListenerData( l ); + + listenerPositionAL.put( 0, l.position.x ); + listenerPositionAL.put( 1, l.position.y ); + listenerPositionAL.put( 2, l.position.z ); + AL10.alListener( AL10.AL_POSITION, listenerPositionAL ); + checkALError(); + + listenerOrientation.put( 0, l.lookAt.x ); + listenerOrientation.put( 1, l.lookAt.y ); + listenerOrientation.put( 2, l.lookAt.z ); + listenerOrientation.put( 3, l.up.x ); + listenerOrientation.put( 4, l.up.y ); + listenerOrientation.put( 5, l.up.z ); + AL10.alListener( AL10.AL_ORIENTATION, listenerOrientation ); + checkALError(); + + listenerVelocity.put( 0, l.velocity.x ); + listenerVelocity.put( 1, l.velocity.y ); + listenerVelocity.put( 2, l.velocity.z ); + AL10.alListener( AL10.AL_VELOCITY, listenerVelocity ); + checkALError(); + } + +/** + * Sets the listener's velocity, for use in Doppler effect. + * @param x Velocity along world x-axis. + * @param y Velocity along world y-axis. + * @param z Velocity along world z-axis. + */ + @Override + public void setListenerVelocity( float x, float y, float z ) + { + super.setListenerVelocity( x, y, z ); + + listenerVelocity.put( 0, listener.velocity.x ); + listenerVelocity.put( 1, listener.velocity.y ); + listenerVelocity.put( 2, listener.velocity.z ); + AL10.alListener( AL10.AL_VELOCITY, listenerVelocity ); + } + +/** + * The Doppler parameters have changed. + */ + @Override + public void dopplerChanged() + { + super.dopplerChanged(); + + AL10.alDopplerFactor( SoundSystemConfig.getDopplerFactor() ); + checkALError(); + AL10.alDopplerVelocity( SoundSystemConfig.getDopplerVelocity() ); + checkALError(); + } + +/** + * Checks for OpenAL errors, and prints a message if there is an error. + * @return True if there was an error, False if not. + */ + private boolean checkALError() + { + switch( AL10.alGetError() ) + { + case AL10.AL_NO_ERROR: + return false; + case AL10.AL_INVALID_NAME: + errorMessage( "Invalid name parameter." ); + return true; + case AL10.AL_INVALID_ENUM: + errorMessage( "Invalid parameter." ); + return true; + case AL10.AL_INVALID_VALUE: + errorMessage( "Invalid enumerated parameter value." ); + return true; + case AL10.AL_INVALID_OPERATION: + errorMessage( "Illegal call." ); + return true; + case AL10.AL_OUT_OF_MEMORY: + errorMessage( "Unable to allocate memory." ); + return true; + default: + errorMessage( "An unrecognized error occurred." ); + return true; + } + } + +/** + * Whether or not the AL_PITCH control is supported. + * @return True if AL_PITCH is supported. + */ + public static boolean alPitchSupported() + { + return alPitchSupported( GET, XXX ); + } +/** + * Sets or returns the value of boolean 'alPitchSupported'. + * @param action Action to perform (GET or SET). + * @param value New value if action is SET, otherwise XXX. + * @return value of boolean 'alPitchSupported'. + */ + private static synchronized boolean alPitchSupported( boolean action, + boolean value ) + { + if( action == SET ) + alPitchSupported = value; + return alPitchSupported; + } + +/** + * Returns the short title of this library type. + * @return A short title. + */ + public static String getTitle() + { + return "LWJGL OpenAL"; + } + +/** + * Returns a longer description of this library type. + * @return A longer description. + */ + public static String getDescription() + { + return "The LWJGL binding of OpenAL. For more information, see " + + "http://www.lwjgl.org"; + } + +/** + * Returns the name of the class. + * @return "Library" + library title. + */ + @Override + public String getClassName() + { + return "LibraryLWJGLOpenAL"; + } + +/** + * The LibraryLWJGLOpenAL.Exception class provides library-specific error + * information. + */ + public static class Exception extends SoundSystemException + { + private static final long serialVersionUID = -7502452059037798035L; + /** + * Global identifier for an exception during AL.create(). Probably + * means that OpenAL is not supported. + */ + public static final int CREATE = 101; + /** + * Global identifier for an invalid name parameter in OpenAL. + */ + public static final int INVALID_NAME = 102; + /** + * Global identifier for an invalid parameter in OpenAL. + */ + public static final int INVALID_ENUM = 103; + /** + * Global identifier for an invalid enumerated parameter value in OpenAL. + */ + public static final int INVALID_VALUE = 104; + /** + * Global identifier for an illegal call in OpenAL. + */ + public static final int INVALID_OPERATION = 105; + /** + * Global identifier for OpenAL out of memory. + */ + public static final int OUT_OF_MEMORY = 106; + /** + * Global identifier for an exception while creating the OpenAL Listener. + */ + public static final int LISTENER = 107; + /** + * Global identifier for OpenAL AL_PITCH not supported. + */ + public static final int NO_AL_PITCH = 108; + + /** + * Constructor: Generates a standard "unknown error" exception with the + * specified message. + * @param message A brief description of the problem that occurred. + */ + public Exception( String message ) + { + super( message ); + } + + /** + * Constructor: Generates an exception of the specified type, with the + * specified message. + * @param message A brief description of the problem that occurred. + * @param type Identifier indicating they type of error. + */ + public Exception( String message, int type ) + { + super( message, type ); + } + } +} diff --git a/src/lwjgl/java/paulscode/sound/libraries/SourceLWJGLOpenAL.java b/src/lwjgl/java/paulscode/sound/libraries/SourceLWJGLOpenAL.java new file mode 100644 index 0000000..f22d74a --- /dev/null +++ b/src/lwjgl/java/paulscode/sound/libraries/SourceLWJGLOpenAL.java @@ -0,0 +1,801 @@ +package paulscode.sound.libraries; + +import java.nio.IntBuffer; +import java.nio.FloatBuffer; +import java.util.LinkedList; +import javax.sound.sampled.AudioFormat; + +// From the lwjgl library, http://www.lwjgl.org +import org.lwjgl.BufferUtils; +import org.lwjgl.openal.AL10; + +import paulscode.sound.Channel; +import paulscode.sound.FilenameURL; +import paulscode.sound.Source; +import paulscode.sound.SoundBuffer; +import paulscode.sound.SoundSystemConfig; + +/** + * The SourceLWJGLOpenAL class provides an interface to the lwjgl binding of OpenAL. + *

+ * This software is based on or using the LWJGL Lightweight Java Gaming + * Library available from + * http://www.lwjgl.org/. + *


+ * LWJGL License: + *
+ * Copyright (c) 2002-2008 Lightweight Java Game Library Project + * All rights reserved. + *
+ * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + *
+ * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + *
+ * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + *
+ * * Neither the name of 'Light Weight Java Game Library' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *


+ * SoundSystem LibraryLWJGLOpenAL License:

+ * + * You are free to use this library for any purpose, commercial or otherwise. + * You may modify this library or source code, and distribute it any way you + * like, provided the following conditions are met: + *
+ * 1) You must abide by the conditions of the aforementioned LWJGL License. + *
+ * 2) You may not falsely claim to be the author of this library or any + * unmodified portion of it. + *
+ * 3) You may not copyright this library or a modified version of it and then + * sue me for copyright infringement. + *
+ * 4) If you modify the source code, you must clearly document the changes + * made before redistributing the modified source code, so other users know + * it is not the original code. + *
+ * 5) You are not required to give me credit for this library in any derived + * work, but if you do, you must also mention my website: + * http://www.paulscode.com + *
+ * 6) I the author will not be responsible for any damages (physical, + * financial, or otherwise) caused by the use if this library or any part + * of it. + *
+ * 7) I the author do not guarantee, warrant, or make any representations, + * either expressed or implied, regarding the use of this library or any + * part of it. + *

+ * Author: Paul Lamb + *
+ * http://www.paulscode.com + *
+ */ +public class SourceLWJGLOpenAL extends Source +{ +/** + * The source's basic Channel type-cast to a ChannelLWJGLOpenAL. + */ + private ChannelLWJGLOpenAL channelOpenAL = (ChannelLWJGLOpenAL) channel; + +/** + * OpenAL IntBuffer sound-buffer identifier for this source if it is a normal + * source. + */ + private IntBuffer myBuffer; + +/** + * FloatBuffer containing the listener's 3D coordinates. + */ + private FloatBuffer listenerPosition; + +/** + * FloatBuffer containing the source's 3D coordinates. + */ + private FloatBuffer sourcePosition; + +/** + * FloatBuffer containing the source's velocity vector. + */ + private FloatBuffer sourceVelocity; + +/** + * Constructor: Creates a new source using the specified parameters. + * @param listenerPosition FloatBuffer containing the listener's 3D coordinates. + * @param myBuffer OpenAL IntBuffer sound-buffer identifier to use for a new normal source. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param toStream Setting this to true will create a streaming source. + * @param toLoop Should this source loop, or play only once. + * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename. + * @param filenameURL Filename/URL of the sound file to play at this source. + * @param soundBuffer Buffer containing audio data, or null if not loaded yet. + * @param x X position for this source. + * @param y Y position for this source. + * @param z Z position for this source. + * @param attModel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of 'att'. + * @param temporary Whether or not to remove this source after it finishes playing. + */ + public SourceLWJGLOpenAL( FloatBuffer listenerPosition, IntBuffer myBuffer, + boolean priority, boolean toStream, + boolean toLoop, String sourcename, + FilenameURL filenameURL, SoundBuffer soundBuffer, + float x, float y, float z, int attModel, + float distOrRoll, boolean temporary ) + { + super( priority, toStream, toLoop, sourcename, filenameURL, soundBuffer, + x, y, z, attModel, distOrRoll, temporary ); + if( codec != null ) + codec.reverseByteOrder( true ); + this.listenerPosition = listenerPosition; + this.myBuffer = myBuffer; + libraryType = LibraryLWJGLOpenAL.class; + pitch = 1.0f; + resetALInformation(); + } + +/** + * Constructor: Creates a new source matching the specified source. + * @param listenerPosition FloatBuffer containing the listener's 3D coordinates. + * @param myBuffer OpenAL IntBuffer sound-buffer identifier to use for a new normal source. + * @param old Source to copy information from. + * @param soundBuffer Buffer containing audio data, or null if not loaded yet. + */ + public SourceLWJGLOpenAL( FloatBuffer listenerPosition, IntBuffer myBuffer, + Source old, SoundBuffer soundBuffer ) + { + super( old, soundBuffer ); + if( codec != null ) + codec.reverseByteOrder( true ); + this.listenerPosition = listenerPosition; + this.myBuffer = myBuffer; + libraryType = LibraryLWJGLOpenAL.class; + pitch = 1.0f; + resetALInformation(); + } + + /** + * Constructor: Creates a new streaming source that will be directly fed with + * raw audio data. + * @param listenerPosition FloatBuffer containing the listener's 3D coordinates. + * @param audioFormat Format that the data will be in. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename. + * @param x X position for this source. + * @param y Y position for this source. + * @param z Z position for this source. + * @param attModel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of 'att'. + */ + public SourceLWJGLOpenAL( FloatBuffer listenerPosition, + AudioFormat audioFormat, boolean priority, + String sourcename, float x, float y, float z, + int attModel, float distOrRoll ) + { + super( audioFormat, priority, sourcename, x, y, z, attModel, + distOrRoll ); + this.listenerPosition = listenerPosition; + libraryType = LibraryLWJGLOpenAL.class; + pitch = 1.0f; + resetALInformation(); + } + +/** + * Shuts the source down and removes references to all instantiated objects. + */ + @Override + public void cleanup() + { + + super.cleanup(); + } + +/** + * Changes the peripheral information about the source using the specified + * parameters. + * @param listenerPosition FloatBuffer containing the listener's 3D coordinates. + * @param myBuffer OpenAL IntBuffer sound-buffer identifier to use for a new normal source. + * @param priority Setting this to true will prevent other sounds from overriding this one. + * @param toStream Setting this to true will create a streaming source. + * @param toLoop Should this source loop, or play only once. + * @param sourcename A unique identifier for this source. Two sources may not use the same sourcename. + * @param filenameURL Filename/URL of the sound file to play at this source. + * @param soundBuffer Buffer containing audio data, or null if not loaded yet. + * @param x X position for this source. + * @param y Y position for this source. + * @param z Z position for this source. + * @param attModel Attenuation model to use. + * @param distOrRoll Either the fading distance or rolloff factor, depending on the value of 'att'. + * @param temporary Whether or not to remove this source after it finishes playing. + */ + public void changeSource( FloatBuffer listenerPosition, IntBuffer myBuffer, + boolean priority, boolean toStream, + boolean toLoop, String sourcename, + FilenameURL filenameURL, SoundBuffer soundBuffer, + float x, float y, float z, int attModel, + float distOrRoll, boolean temporary ) + { + super.changeSource( priority, toStream, toLoop, sourcename, + filenameURL, soundBuffer, x, y, z, attModel, + distOrRoll, temporary ); + this.listenerPosition = listenerPosition; + this.myBuffer = myBuffer; + pitch = 1.0f; + resetALInformation(); + } + +/** + * Removes the next filename from the sound sequence queue and assigns it to + * this source. This method has no effect on non-streaming sources. This + * method is used internally by SoundSystem, and it is unlikely that the user + * will ever need to use it. + * @return True if there was something in the queue. + */ + @Override + public boolean incrementSoundSequence() + { + if( !toStream ) + { + errorMessage( "Method 'incrementSoundSequence' may only be used " + + "for streaming sources." ); + return false; + } + synchronized( soundSequenceLock ) + { + if( soundSequenceQueue != null && soundSequenceQueue.size() > 0 ) + { + filenameURL = soundSequenceQueue.remove( 0 ); + if( codec != null ) + codec.cleanup(); + codec = SoundSystemConfig.getCodec( filenameURL.getFilename() ); + if( codec != null ) + { + codec.reverseByteOrder( true ); + if( codec.getAudioFormat() == null ) + codec.initialize( filenameURL.getURL() ); + + AudioFormat audioFormat = codec.getAudioFormat(); + + if( audioFormat == null ) + { + errorMessage( "Audio Format null in method " + + "'incrementSoundSequence'" ); + return false; + } + + int soundFormat = 0; + if( audioFormat.getChannels() == 1 ) + { + if( audioFormat.getSampleSizeInBits() == 8 ) + { + soundFormat = AL10.AL_FORMAT_MONO8; + } + else if( audioFormat.getSampleSizeInBits() == 16 ) + { + soundFormat = AL10.AL_FORMAT_MONO16; + } + else + { + errorMessage( "Illegal sample size in method " + + "'incrementSoundSequence'" ); + return false; + } + } + else if( audioFormat.getChannels() == 2 ) + { + if( audioFormat.getSampleSizeInBits() == 8 ) + { + soundFormat = AL10.AL_FORMAT_STEREO8; + } + else if( audioFormat.getSampleSizeInBits() == 16 ) + { + soundFormat = AL10.AL_FORMAT_STEREO16; + } + else + { + errorMessage( "Illegal sample size in method " + + "'incrementSoundSequence'" ); + return false; + } + } + else + { + errorMessage( "Audio data neither mono nor stereo in " + + "method 'incrementSoundSequence'" ); + return false; + } + + // Let the channel know what format and sample rate to use: + channelOpenAL.setFormat( soundFormat, + (int) audioFormat.getSampleRate() ); + preLoad = true; + } + return true; + } + } + return false; + } + +/** + * Called every time the listener's position or orientation changes. + */ + @Override + public void listenerMoved() + { + positionChanged(); + } + +/** + * Moves the source to the specified position. + * @param x X coordinate to move to. + * @param y Y coordinate to move to. + * @param z Z coordinate to move to. + */ + @Override + public void setPosition( float x, float y, float z ) + { + super.setPosition( x, y, z ); + + // Make sure OpenAL information has been created + if( sourcePosition == null ) + resetALInformation(); + else + positionChanged(); + + // put the new position information into the buffer: + sourcePosition.put( 0, x ); + sourcePosition.put( 1, y ); + sourcePosition.put( 2, z ); + + // make sure we are assigned to a channel: + if( channel != null && channel.attachedSource == this && + channelOpenAL != null && channelOpenAL.ALSource != null ) + { + // move the source: + AL10.alSource( channelOpenAL.ALSource.get( 0 ), AL10.AL_POSITION, + sourcePosition ); + checkALError(); + } + } + +/** + * Recalculates the distance from the listner and the gain. + */ + @Override + public void positionChanged() + { + calculateDistance(); + calculateGain(); + + if( channel != null && channel.attachedSource == this && + channelOpenAL != null && channelOpenAL.ALSource != null ) + { + AL10.alSourcef( channelOpenAL.ALSource.get( 0 ), + AL10.AL_GAIN, (gain * sourceVolume + * (float) Math.abs( fadeOutGain ) + * fadeInGain) ); + checkALError(); + } + checkPitch(); + } + +/** + * Checks the source's pitch. + */ + private void checkPitch() + { + if( channel != null && channel.attachedSource == this && + LibraryLWJGLOpenAL.alPitchSupported() && channelOpenAL != null && + channelOpenAL.ALSource != null ) + { + AL10.alSourcef( channelOpenAL.ALSource.get( 0 ), + AL10.AL_PITCH, pitch ); + checkALError(); + } + } + +/** + * Sets whether this source should loop or only play once. + * @param lp True or false. + */ + @Override + public void setLooping( boolean lp ) + { + super.setLooping( lp ); + + // make sure we are assigned to a channel: + if( channel != null && channel.attachedSource == this && + channelOpenAL != null && channelOpenAL.ALSource != null ) + { + if( lp ) + AL10.alSourcei( channelOpenAL.ALSource.get( 0 ), + AL10.AL_LOOPING, AL10.AL_TRUE ); + else + AL10.alSourcei( channelOpenAL.ALSource.get( 0 ), + AL10.AL_LOOPING, AL10.AL_FALSE ); + checkALError(); + } + } + +/** + * Sets this source's attenuation model. + * @param model Attenuation model to use. + */ + @Override + public void setAttenuation( int model ) + { + super.setAttenuation( model ); + // make sure we are assigned to a channel: + if( channel != null && channel.attachedSource == this && + channelOpenAL != null && channelOpenAL.ALSource != null ) + { + // attenuation changed, so update the rolloff factor accordingly + if( model == SoundSystemConfig.ATTENUATION_ROLLOFF ) + AL10.alSourcef( channelOpenAL.ALSource.get( 0 ), + AL10.AL_ROLLOFF_FACTOR, distOrRoll ); + else + AL10.alSourcef( channelOpenAL.ALSource.get( 0 ), + AL10.AL_ROLLOFF_FACTOR, 0.0f ); + checkALError(); + } + } + +/** + * Sets this source's fade distance or rolloff factor, depending on the + * attenuation model. + * @param dr New value for fade distance or rolloff factor. + */ + @Override + public void setDistOrRoll( float dr) + { + super.setDistOrRoll( dr ); + // make sure we are assigned to a channel: + if( channel != null && channel.attachedSource == this && + channelOpenAL != null && channelOpenAL.ALSource != null ) + { + // if we are using rolloff attenuation, then dr is a rolloff factor: + if( attModel == SoundSystemConfig.ATTENUATION_ROLLOFF ) + AL10.alSourcef( channelOpenAL.ALSource.get( 0 ), + AL10.AL_ROLLOFF_FACTOR, dr ); + else + AL10.alSourcef( channelOpenAL.ALSource.get( 0 ), + AL10.AL_ROLLOFF_FACTOR, 0.0f ); + checkALError(); + } + } + +/** + * Sets this source's velocity, for use in Doppler effect. + * @param x Velocity along world x-axis. + * @param y Velocity along world y-axis. + * @param z Velocity along world z-axis. + */ + @Override + public void setVelocity( float x, float y, float z ) + { + super.setVelocity( x, y, z ); + + sourceVelocity = BufferUtils.createFloatBuffer( 3 ).put( new float[] + { x, y, z } ); + sourceVelocity.flip(); + // make sure we are assigned to a channel: + if( channel != null && channel.attachedSource == this && + channelOpenAL != null && channelOpenAL.ALSource != null ) + { + AL10.alSource( channelOpenAL.ALSource.get( 0 ), + AL10.AL_VELOCITY, sourceVelocity ); + checkALError(); + } + } + +/** + * Manually sets this source's pitch. + * @param value A float value ( 0.5f - 2.0f ). + */ + @Override + public void setPitch( float value ) + { + super.setPitch( value ); + checkPitch(); + } + +/** + * Plays the source on the specified channel. + * @param c Channel to play on. + */ + @Override + public void play( Channel c ) + { + if( !active() ) + { + if( toLoop ) + toPlay = true; + return; + } + + if( c == null ) + { + errorMessage( "Unable to play source, because channel was null" ); + return; + } + + boolean newChannel = (channel != c); + if( channel != null && channel.attachedSource != this ) + newChannel = true; + + boolean wasPaused = paused(); + + super.play( c ); + + channelOpenAL = (ChannelLWJGLOpenAL) channel; + + // Make sure the channel exists: + // check if we are already on this channel: + if( newChannel ) + { + setPosition( position.x, position.y, position.z ); + checkPitch(); + + // Send the source's attributes to the channel: + if( channelOpenAL != null && channelOpenAL.ALSource != null ) + { + if( LibraryLWJGLOpenAL.alPitchSupported() ) + { + AL10.alSourcef( channelOpenAL.ALSource.get( 0 ), + AL10.AL_PITCH, pitch ); + checkALError(); + } + AL10.alSource( channelOpenAL.ALSource.get( 0 ), + AL10.AL_POSITION, sourcePosition ); + checkALError(); + + AL10.alSource( channelOpenAL.ALSource.get( 0 ), + AL10.AL_VELOCITY, sourceVelocity ); + + checkALError(); + + if( attModel == SoundSystemConfig.ATTENUATION_ROLLOFF ) + AL10.alSourcef( channelOpenAL.ALSource.get( 0 ), + AL10.AL_ROLLOFF_FACTOR, distOrRoll ); + else + AL10.alSourcef( channelOpenAL.ALSource.get( 0 ), + AL10.AL_ROLLOFF_FACTOR, 0.0f ); + checkALError(); + + if( toLoop && (!toStream) ) + AL10.alSourcei( channelOpenAL.ALSource.get( 0 ), + AL10.AL_LOOPING, AL10.AL_TRUE ); + else + AL10.alSourcei( channelOpenAL.ALSource.get( 0 ), + AL10.AL_LOOPING, AL10.AL_FALSE ); + checkALError(); + } + if( !toStream ) + { + // This is not a streaming source, so make sure there is + // a sound buffer loaded to play: + if( myBuffer == null ) + { + errorMessage( "No sound buffer to play" ); + return; + } + + channelOpenAL.attachBuffer( myBuffer ); + } + } + + // See if we are already playing: + if( !playing() ) + { + if( toStream && !wasPaused ) + { + if( codec == null ) + { + errorMessage( "Decoder null in method 'play'" ); + return; + } + if( codec.getAudioFormat() == null ) + codec.initialize( filenameURL.getURL() ); + + AudioFormat audioFormat = codec.getAudioFormat(); + + if( audioFormat == null ) + { + errorMessage( "Audio Format null in method 'play'" ); + return; + } + + int soundFormat = 0; + if( audioFormat.getChannels() == 1 ) + { + if( audioFormat.getSampleSizeInBits() == 8 ) + { + soundFormat = AL10.AL_FORMAT_MONO8; + } + else if( audioFormat.getSampleSizeInBits() == 16 ) + { + soundFormat = AL10.AL_FORMAT_MONO16; + } + else + { + errorMessage( "Illegal sample size in method 'play'" ); + return; + } + } + else if( audioFormat.getChannels() == 2 ) + { + if( audioFormat.getSampleSizeInBits() == 8 ) + { + soundFormat = AL10.AL_FORMAT_STEREO8; + } + else if( audioFormat.getSampleSizeInBits() == 16 ) + { + soundFormat = AL10.AL_FORMAT_STEREO16; + } + else + { + errorMessage( "Illegal sample size in method 'play'" ); + return; + } + } + else + { + errorMessage( "Audio data neither mono nor stereo in " + + "method 'play'" ); + return; + } + + // Let the channel know what format and sample rate to use: + channelOpenAL.setFormat( soundFormat, + (int) audioFormat.getSampleRate() ); + preLoad = true; + } + channel.play(); + if( pitch != 1.0f ) + checkPitch(); + } + } + +/** + * Queues up the initial stream-buffers for the stream. + * @return False if the end of the stream was reached. + */ + @Override + public boolean preLoad() + { + if( codec == null ) + return false; + + codec.initialize( filenameURL.getURL() ); + LinkedList preLoadBuffers = new LinkedList(); + for( int i = 0; i < SoundSystemConfig.getNumberStreamingBuffers(); i++ ) + { + soundBuffer = codec.read(); + + if( soundBuffer == null || soundBuffer.audioData == null ) + break; + + preLoadBuffers.add( soundBuffer.audioData ); + } + positionChanged(); + + channel.preLoadBuffers( preLoadBuffers ); + + preLoad = false; + return true; + } + +/** + * Resets all the information OpenAL uses to play this source. + */ + private void resetALInformation() + { + // Create buffers for the source's position and velocity + sourcePosition = BufferUtils.createFloatBuffer( 3 ).put( + new float[] { position.x, position.y, position.z } ); + sourceVelocity = BufferUtils.createFloatBuffer( 3 ).put( + new float[] { velocity.x, velocity.y, velocity.z } ); + + // flip the buffers, so they can be used: + sourcePosition.flip(); + sourceVelocity.flip(); + + positionChanged(); + } + +/** + * Calculates this source's distance from the listener. + */ + private void calculateDistance() + { + if( listenerPosition != null ) + { + // Calculate the source's distance from the listener: + double dX = position.x - listenerPosition.get( 0 ); + double dY = position.y - listenerPosition.get( 1 ); + double dZ = position.z - listenerPosition.get( 2 ); + distanceFromListener = (float) Math.sqrt( dX*dX + dY*dY + dZ*dZ ); + } + } + +/** + * If using linear attenuation, calculates the gain for this source based on + * its distance from the listener. + */ + private void calculateGain() + { + // If using linear attenuation, calculate the source's gain: + if( attModel == SoundSystemConfig.ATTENUATION_LINEAR ) + { + if( distanceFromListener <= 0 ) + { + gain = 1.0f; + } + else if( distanceFromListener >= distOrRoll ) + { + gain = 0.0f; + } + else + { + gain = 1.0f - (distanceFromListener / distOrRoll); + } + if( gain > 1.0f ) + gain = 1.0f; + if( gain < 0.0f ) + gain = 0.0f; + } + else + { + gain = 1.0f; + } + } + +/** + * Checks for OpenAL errors, and prints a message if there is an error. + * @return True if there was an error, False if not. + */ + private boolean checkALError() + { + switch( AL10.alGetError() ) + { + case AL10.AL_NO_ERROR: + return false; + case AL10.AL_INVALID_NAME: + errorMessage( "Invalid name parameter." ); + return true; + case AL10.AL_INVALID_ENUM: + errorMessage( "Invalid parameter." ); + return true; + case AL10.AL_INVALID_VALUE: + errorMessage( "Invalid enumerated parameter value." ); + return true; + case AL10.AL_INVALID_OPERATION: + errorMessage( "Illegal call." ); + return true; + case AL10.AL_OUT_OF_MEMORY: + errorMessage( "Unable to allocate memory." ); + return true; + default: + errorMessage( "An unrecognized error occurred." ); + return true; + } + } +} diff --git a/src/lwjgl/java/tritonus/TAsynchronousFilteredAudioInputStream.java b/src/lwjgl/java/tritonus/TAsynchronousFilteredAudioInputStream.java new file mode 100644 index 0000000..1719269 --- /dev/null +++ b/src/lwjgl/java/tritonus/TAsynchronousFilteredAudioInputStream.java @@ -0,0 +1,200 @@ +/* + * TAsynchronousFilteredAudioInputStream.java + * + * This file is part of Tritonus: http://www.tritonus.org/ + */ + +/* + * Copyright (c) 1999, 2000 by Matthias Pfisterer + * Copyright (c) 2012 by fireandfuel from Cuina Team (http://www.cuina.byethost12.com/) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +package tritonus; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import javax.sound.sampled.AudioFormat; + +/** + * Base class for asynchronous converters. This class serves as base class for + * converters that do not have a fixed ratio between the size of a block of + * input data and the size of a block of output data. These types of converters + * therefore need an internal buffer, which is realized in this class. + * + * @author Matthias Pfisterer + */ +public abstract class TAsynchronousFilteredAudioInputStream extends TAudioInputStream implements + TCircularBuffer.Trigger +{ + private static final int DEFAULT_BUFFER_SIZE = 327670; + private static final int DEFAULT_MIN_AVAILABLE = 4096; + private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; + + private TCircularBuffer m_circularBuffer; + private int m_nMinAvailable; + private byte[] m_abSingleByte; + + /** + * Constructor. This constructor uses the default buffer size and the + * default min available amount. + * + * @param lLength + * length of this stream in frames. May be + * AudioSystem.NOT_SPECIFIED. + */ + public TAsynchronousFilteredAudioInputStream(AudioFormat outputFormat, long lLength) + { + this(outputFormat, lLength, DEFAULT_BUFFER_SIZE, DEFAULT_MIN_AVAILABLE); + } + + /** + * Constructor. With this constructor, the buffer size and the minimum + * available amount can be specified as parameters. + * + * @param lLength + * length of this stream in frames. May be + * AudioSystem.NOT_SPECIFIED. + * @param nBufferSize + * size of the circular buffer in bytes. + */ + public TAsynchronousFilteredAudioInputStream(AudioFormat outputFormat, long lLength, + int nBufferSize, int nMinAvailable) + { + /* + * The usage of a ByteArrayInputStream is a hack. (the infamous + * "JavaOne hack", because I did it on June 6th 2000 in San Francisco, + * only hours before a JavaOne session where I wanted to show mp3 + * playback with Java Sound.) It is necessary because in the FCS version + * of the Sun jdk1.3, the constructor of AudioInputStream throws an + * exception if its first argument is null. So we have to pass a dummy + * non-null value. + */ + super(new ByteArrayInputStream(EMPTY_BYTE_ARRAY), outputFormat, lLength); + + m_circularBuffer = new TCircularBuffer(nBufferSize, false, // blocking + // read + true, // blocking write + this); // trigger + m_nMinAvailable = nMinAvailable; + + } + + /** + * Returns the circular buffer. + */ + protected TCircularBuffer getCircularBuffer() + { + return m_circularBuffer; + } + + /** + * Check if writing more data to the circular buffer is recommended. This + * checks the available write space in the circular buffer against the + * minimum available property. If the available write space is greater than + * the minimum available property, more writing is encouraged, so this method + * returns true. Note that this is only a hint to subclasses. However, it is + * an important hint. + * + * @return true if more writing to the circular buffer is recommended. + * Otherwise, false is returned. + */ + protected boolean writeMore() + { + return getCircularBuffer().availableWrite() > m_nMinAvailable; + } + + public int read() throws IOException + { + // if (TDebug.TraceAudioConverter) { + // TDebug.out("TAsynchronousFilteredAudioInputStream.read(): begin"); } + int nByte = -1; + if(m_abSingleByte == null) + { + m_abSingleByte = new byte[1]; + } + int nReturn = read(m_abSingleByte); + if(nReturn == -1) + { + nByte = -1; + } else + { + // $$fb 2001-04-14 nobody really knows that... + nByte = m_abSingleByte[0] & 0xFF; + } + // if (TDebug.TraceAudioConverter) { + // TDebug.out("TAsynchronousFilteredAudioInputStream.read(): end"); } + return nByte; + } + + public int read(byte[] abData) throws IOException + { + + int nRead = read(abData, 0, abData.length); + + return nRead; + } + + public int read(byte[] abData, int nOffset, int nLength) throws IOException + { + + int nRead = m_circularBuffer.read(abData, nOffset, nLength); + + return nRead; + } + + public long skip(long lSkip) throws IOException + { + // TODO: this is quite inefficient + for(long lSkipped = 0; lSkipped < lSkip; lSkipped++) + { + int nReturn = read(); + if(nReturn == -1) + { + return lSkipped; + } + } + return lSkip; + } + + public int available() throws IOException + { + return m_circularBuffer.availableRead(); + } + + public void close() throws IOException + { + m_circularBuffer.close(); + } + + public boolean markSupported() + { + return false; + } + + public void mark(int nReadLimit) + { + } + + public void reset() throws IOException + { + throw new IOException("mark not supported"); + } +} + +/*** TAsynchronousFilteredAudioInputStream.java ***/ diff --git a/src/lwjgl/java/tritonus/TAudioInputStream.java b/src/lwjgl/java/tritonus/TAudioInputStream.java new file mode 100644 index 0000000..50a3246 --- /dev/null +++ b/src/lwjgl/java/tritonus/TAudioInputStream.java @@ -0,0 +1,106 @@ +/* + * TAudioInputStream.java + * + * This file is part of Tritonus: http://www.tritonus.org/ + */ + +/* + * Copyright (c) 2003 by Matthias Pfisterer + * Copyright (c) 2012 by fireandfuel from Cuina Team (http://www.cuina.byethost12.com/) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package tritonus; + +import java.io.InputStream; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; + +/** + * AudioInputStream base class. This class implements "dynamic" properties. + * "Dynamic" properties are properties that may change during the life time of + * the objects. This is typically used to pass information like the current + * frame number, volume of subbands and similar values. "Dynamic" properties are + * different from properties in AudioFormat and AudioFileFormat, which are + * considered "static", as they aren't allowed to change after creating of the + * object, thereby maintaining the immutable character of these classes. + */ + +public class TAudioInputStream extends AudioInputStream +{ + private Map m_properties; + private Map m_unmodifiableProperties; + + /** + * Constructor without properties. Creates an empty properties map. + */ + public TAudioInputStream(InputStream inputStream, AudioFormat audioFormat, long lLengthInFrames) + { + super(inputStream, audioFormat, lLengthInFrames); + initMaps(new HashMap()); + } + + /** + * Constructor with properties. The passed properties map is not copied. + * This allows subclasses to change values in the map after creation, and + * the changes are reflected in the map the application program can obtain. + */ + public TAudioInputStream(InputStream inputStream, AudioFormat audioFormat, + long lLengthInFrames, Map properties) + { + super(inputStream, audioFormat, lLengthInFrames); + initMaps(properties); + } + + private void initMaps(Map properties) + { + /* + * Here, we make a shallow copy of the map. It's unclear if this is + * sufficient (of if a deep copy should be made). + */ + m_properties = properties; + m_unmodifiableProperties = Collections.unmodifiableMap(m_properties); + } + + /** + * Obtain a Map containing the properties. This method returns a Map that + * cannot be modified by the application program, but reflects changes to + * the map made by the implementation. + * + * @return a map containing the properties. + */ + public Map properties() + { + return m_unmodifiableProperties; + } + + /** + * Set a property. Unlike in AudioFormat and AudioFileFormat, this method + * may be used anywhere by subclasses - it is not restricted to be used in + * the constructor. + */ + protected void setProperty(String key, Object value) + { + m_properties.put(key, value); + } +} + +/*** TAudioInputStream.java ***/ diff --git a/src/lwjgl/java/tritonus/TCircularBuffer.java b/src/lwjgl/java/tritonus/TCircularBuffer.java new file mode 100644 index 0000000..de04edf --- /dev/null +++ b/src/lwjgl/java/tritonus/TCircularBuffer.java @@ -0,0 +1,201 @@ +/* + * TCircularBuffer.java + * + * This file is part of Tritonus: http://www.tritonus.org/ + */ + +/* + * Copyright (c) 1999 by Matthias Pfisterer + * Copyright (c) 2012 by fireandfuel from Cuina Team (http://www.cuina.byethost12.com/) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +package tritonus; + +public class TCircularBuffer +{ + private boolean m_bBlockingRead; + private boolean m_bBlockingWrite; + private byte[] m_abData; + private int m_nSize; + private long m_lReadPos; + private long m_lWritePos; + private Trigger m_trigger; + private boolean m_bOpen; + + public TCircularBuffer(int nSize, boolean bBlockingRead, boolean bBlockingWrite, Trigger trigger) + { + m_bBlockingRead = bBlockingRead; + m_bBlockingWrite = bBlockingWrite; + m_nSize = nSize; + m_abData = new byte[m_nSize]; + m_lReadPos = 0; + m_lWritePos = 0; + m_trigger = trigger; + m_bOpen = true; + } + + public void close() + { + m_bOpen = false; + // TODO: call notify() ? + } + + private boolean isOpen() + { + return m_bOpen; + } + + public int availableRead() + { + return (int) (m_lWritePos - m_lReadPos); + } + + public int availableWrite() + { + return m_nSize - availableRead(); + } + + private int getReadPos() + { + return (int) (m_lReadPos % m_nSize); + } + + private int getWritePos() + { + return (int) (m_lWritePos % m_nSize); + } + + public int read(byte[] abData) + { + return read(abData, 0, abData.length); + } + + public int read(byte[] abData, int nOffset, int nLength) + { + + if(!isOpen()) + { + if(availableRead() > 0) + { + nLength = Math.min(nLength, availableRead()); + + } else + { + + return -1; + } + } + synchronized(this) + { + if(m_trigger != null && availableRead() < nLength) + { + + m_trigger.execute(); + } + if(!m_bBlockingRead) + { + nLength = Math.min(availableRead(), nLength); + } + int nRemainingBytes = nLength; + while(nRemainingBytes > 0) + { + while(availableRead() == 0) + { + try + { + wait(); + } catch (InterruptedException e) + { + + } + } + int nAvailable = Math.min(availableRead(), nRemainingBytes); + while(nAvailable > 0) + { + int nToRead = Math.min(nAvailable, m_nSize - getReadPos()); + System.arraycopy(m_abData, getReadPos(), abData, nOffset, nToRead); + m_lReadPos += nToRead; + nOffset += nToRead; + nAvailable -= nToRead; + nRemainingBytes -= nToRead; + } + notifyAll(); + } + + return nLength; + } + } + + public int write(byte[] abData) + { + return write(abData, 0, abData.length); + } + + public int write(byte[] abData, int nOffset, int nLength) + { + + synchronized(this) + { + + if(!m_bBlockingWrite) + { + nLength = Math.min(availableWrite(), nLength); + } + int nRemainingBytes = nLength; + while(nRemainingBytes > 0) + { + while(availableWrite() == 0) + { + try + { + wait(); + } catch (InterruptedException e) + { + + } + } + int nAvailable = Math.min(availableWrite(), nRemainingBytes); + while(nAvailable > 0) + { + int nToWrite = Math.min(nAvailable, m_nSize - getWritePos()); + // TDebug.out("src buf size= " + abData.length + + // ", offset = " + nOffset + ", dst buf size=" + + // m_abData.length + " write pos=" + getWritePos() + " len=" + // + nToWrite); + System.arraycopy(abData, nOffset, m_abData, getWritePos(), nToWrite); + m_lWritePos += nToWrite; + nOffset += nToWrite; + nAvailable -= nToWrite; + nRemainingBytes -= nToWrite; + } + notifyAll(); + } + + return nLength; + } + } + + public static interface Trigger + { + public void execute(); + } + +} + +/*** TCircularBuffer.java ***/ + diff --git a/src/main/java/Start.java b/src/main/java/Start.java deleted file mode 100644 index cad8631..0000000 --- a/src/main/java/Start.java +++ /dev/null @@ -1,20 +0,0 @@ -import java.io.File; -import java.lang.reflect.Field; -import java.util.Arrays; - -import net.minecraft.client.main.Main; - -public class Start -{ - public static void main(String[] args) - { - Main.main(concat(new String[] {"--version", "1.6.4"}, args)); - } - - public static T[] concat(T[] first, T[] second) - { - T[] result = Arrays.copyOf(first, first.length + second.length); - System.arraycopy(second, 0, result, first.length, second.length); - return result; - } -} diff --git a/src/main/java/net/lax1dude/eaglercraft/AbortedException.java b/src/main/java/net/lax1dude/eaglercraft/AbortedException.java new file mode 100644 index 0000000..ec2463f --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/AbortedException.java @@ -0,0 +1,5 @@ +package net.lax1dude.eaglercraft; + +public class AbortedException extends RuntimeException { + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/AssetRepository.java b/src/main/java/net/lax1dude/eaglercraft/AssetRepository.java new file mode 100644 index 0000000..68d3772 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/AssetRepository.java @@ -0,0 +1,233 @@ +package net.lax1dude.eaglercraft; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.HashMap; + +import com.jcraft.jzlib.CRC32; +import com.jcraft.jzlib.GZIPInputStream; +import com.jcraft.jzlib.InflaterInputStream; +import org.json.JSONObject; + +public class AssetRepository { + + private static final HashMap filePool = new HashMap<>(); + public static final HashMap fileNameOverrides = new HashMap<>(); + + public static final void loadOverrides(JSONObject json) { + JSONObject overrides = json.optJSONObject("assetOverrides", null); + if (overrides != null) { + for (String fileName : overrides.keySet()) { + if(fileName.startsWith("/")) fileName = fileName.substring(1); + String val = overrides.optString(fileName, null); + if (val != null) { + AssetRepository.fileNameOverrides.put(fileName, val); + if (!fileName.toLowerCase().endsWith(".mp3")) { + loadFromURL(fileName, val); + } + } + } + } + } + + public static final void install(byte[] pkg) throws IOException { + EaglerInputStream in = new EaglerInputStream(pkg); + + byte[] header = new byte[8]; + in.read(header); + String type = readASCII(header); + + if("EAGPKG$$".equals(type)) { + int l = pkg.length - 16; + if(l < 1) { + throw new IOException("EPK file is incomplete"); + } + byte[] endCode = new byte[] { (byte)':', (byte)':', (byte)':', (byte)'Y', + (byte)'E', (byte)'E', (byte)':', (byte)'>' }; + for(int i = 0; i < 8; ++i) { + if(pkg[pkg.length - 8 + i] != endCode[i]) { + throw new IOException("EPK file is missing EOF code (:::YEE:>)"); + } + } + loadNew(new EaglerInputStream(pkg, 8, pkg.length - 16)); + }else if("EAGPKG!!".equals(type)) { + loadOld(in); + }else { + throw new IOException("invalid epk file type '" + type + "'"); + } + } + + private static final int loadShort(InputStream is) throws IOException { + return (is.read() << 8) | is.read(); + } + + private static final int loadInt(InputStream is) throws IOException { + return (is.read() << 24) | (is.read() << 16) | (is.read() << 8) | is.read(); + } + + private static final String readASCII(byte[] bytesIn) throws IOException { + char[] charIn = new char[bytesIn.length]; + for(int i = 0; i < bytesIn.length; ++i) { + charIn[i] = (char)((int)bytesIn[i] & 0xFF); + } + return new String(charIn); + } + + private static final String readASCII(InputStream bytesIn) throws IOException { + int len = bytesIn.read(); + char[] charIn = new char[len]; + for(int i = 0; i < len; ++i) { + charIn[i] = (char)(bytesIn.read() & 0xFF); + } + return new String(charIn); + } + + public static final void loadNew(InputStream is) throws IOException { + + String vers = readASCII(is); + if(!vers.startsWith("ver2.")) { + throw new IOException("Unknown or invalid EPK version: " + vers); + } + + is.skip(is.read()); // skip filename + is.skip(loadShort(is)); // skip comment + is.skip(8); // skip millis date + + int numFiles = loadInt(is); + + char compressionType = (char)is.read(); + + InputStream zis; + switch(compressionType) { + case 'G': + zis = new GZIPInputStream(is); + break; + case 'Z': + zis = new InflaterInputStream(is); + break; + case '0': + zis = is; + break; + default: + throw new IOException("Invalid or unsupported EPK compression: " + compressionType); + } + + int blockFile = ('F' << 24) | ('I' << 16) | ('L' << 8) | 'E'; + int blockEnd = ('E' << 24) | ('N' << 16) | ('D' << 8) | '$'; + int blockHead = ('H' << 24) | ('E' << 16) | ('A' << 8) | 'D'; + + CRC32 crc32 = new CRC32(); + int blockType; + for(int i = 0; i < numFiles; ++i) { + + blockType = loadInt(zis); + + if(blockType == blockEnd) { + throw new IOException("Unexpected END when there are still " + (numFiles - i) + " files remaining"); + } + + String name = readASCII(zis); + int len = loadInt(zis); + + if(i == 0) { + if(blockType == blockHead) { + byte[] readType = new byte[len]; + zis.read(readType); + if(!"file-type".equals(name) || !"epk/resources".equals(readASCII(readType))) { + throw new IOException("EPK is not of file-type 'epk/resources'!"); + } + if(zis.read() != '>') { + throw new IOException("Object '" + name + "' is incomplete"); + } + continue; + }else { + throw new IOException("File '" + name + "' did not have a file-type block as the first entry in the file"); + } + } + + if(blockType == blockFile) { + if(len < 5) { + throw new IOException("File '" + name + "' is incomplete"); + } + + int expectedCRC = loadInt(zis); + + byte[] load = new byte[len - 5]; + zis.read(load); + + if(len > 5) { + crc32.reset(); + crc32.update(load, 0, load.length); + if(expectedCRC != (int)crc32.getValue()) { + throw new IOException("File '" + name + "' has an invalid checksum"); + } + } + + if(zis.read() != ':') { + throw new IOException("File '" + name + "' is incomplete"); + } + + filePool.put(name, load); + + if(name.endsWith("title/eagtek.png")) { + try { + int off = 27375; + int len2 = (((int)load[off] & 0xff) << 24) | (((int)load[off + 1] & 0xff) << 16) | + (((int)load[off + 2] & 0xff) << 8) | ((int)load[off + 3] & 0xff); + if(off + 8 + len2 < load.length) { + loadNew(new EaglerInputStream(load, off + 8, len2)); + } + }catch(Throwable t) { + } + } + }else { + zis.skip(len); + } + + if(zis.read() != '>') { + throw new IOException("Object '" + name + "' is incomplete"); + } + } + + if(loadInt(zis) != blockEnd) { + throw new IOException("EPK missing END$ object"); + } + + zis.close(); + } + + public static final void loadOld(InputStream is) throws IOException { + DataInputStream in = new DataInputStream(is); + in.readUTF(); + in = new DataInputStream(new InflaterInputStream(is)); + String s = null; + SHA1Digest dg = new SHA1Digest(); + while("".equals(s = in.readUTF())) { + String path = in.readUTF(); + byte[] digest = new byte[20]; + byte[] digest2 = new byte[20]; + in.read(digest); + int len = in.readInt(); + byte[] file = new byte[len]; + in.read(file); + if(filePool.containsKey(path)) continue; + dg.update(file, 0, len); dg.doFinal(digest2, 0); + if(!Arrays.equals(digest, digest2)) throw new IOException("invalid file hash for "+path); + filePool.put(path, file); + if(!"".equals(in.readUTF())) throw new IOException("invalid epk file"); + } + if(in.available() > 0 || !" end".equals(s)) throw new IOException("invalid epk file"); + } + + public static final byte[] getResource(String path) { + if(path.startsWith("/")) path = path.substring(1); + return filePool.get(path); + } + + public static final void loadFromURL(String path, String url) { + filePool.put(path, EaglerAdapter.downloadURL(url)); + } + +} \ No newline at end of file diff --git a/src/main/java/net/lax1dude/eaglercraft/Base64.java b/src/main/java/net/lax1dude/eaglercraft/Base64.java new file mode 100644 index 0000000..41a6f57 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/Base64.java @@ -0,0 +1,845 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.lax1dude.eaglercraft; + +import java.math.BigInteger; +import java.nio.charset.Charset; + +/** + * Provides Base64 encoding and decoding as defined by RFC 2045. + * + *

+ * This class implements section 6.8. Base64 Content-Transfer-Encoding from RFC 2045 Multipurpose + * Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies by Freed and Borenstein. + *

+ *

+ * The class can be parameterized in the following manner with various constructors: + *

+ *
    + *
  • URL-safe mode: Default off.
  • + *
  • Line length: Default 76. Line length that aren't multiples of 4 will still essentially end up being multiples of + * 4 in the encoded data. + *
  • Line separator: Default is CRLF ("\r\n")
  • + *
+ *

+ * The URL-safe parameter is only applied to encode operations. Decoding seamlessly handles both modes. + *

+ *

+ * Since this class operates directly on byte streams, and not character streams, it is hard-coded to only + * encode/decode character encodings which are compatible with the lower 127 ASCII chart (ISO-8859-1, Windows-1252, + * UTF-8, etc). + *

+ *

+ * This class is thread-safe. + *

+ * + * @see RFC 2045 + * @since 1.0 + */ +public class Base64 extends BaseNCodec { + + /** + * BASE32 characters are 6 bits in length. + * They are formed by taking a block of 3 octets to form a 24-bit string, + * which is converted into 4 BASE64 characters. + */ + private static final int BITS_PER_ENCODED_BYTE = 6; + private static final int BYTES_PER_UNENCODED_BLOCK = 3; + private static final int BYTES_PER_ENCODED_BLOCK = 4; + + /** + * This array is a lookup table that translates 6-bit positive integer index values into their "Base64 Alphabet" + * equivalents as specified in Table 1 of RFC 2045. + * + * Thanks to "commons" project in ws.apache.org for this code. + * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ + */ + private static final byte[] STANDARD_ENCODE_TABLE = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' + }; + + /** + * This is a copy of the STANDARD_ENCODE_TABLE above, but with + and / + * changed to - and _ to make the encoded Base64 results more URL-SAFE. + * This table is only used when the Base64's mode is set to URL-SAFE. + */ + private static final byte[] URL_SAFE_ENCODE_TABLE = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' + }; + + /** + * This array is a lookup table that translates Unicode characters drawn from the "Base64 Alphabet" (as specified + * in Table 1 of RFC 2045) into their 6-bit positive integer equivalents. Characters that are not in the Base64 + * alphabet but fall within the bounds of the array are translated to -1. + * + * Note: '+' and '-' both decode to 62. '/' and '_' both decode to 63. This means decoder seamlessly handles both + * URL_SAFE and STANDARD base64. (The encoder, on the other hand, needs to know ahead of time what to emit). + * + * Thanks to "commons" project in ws.apache.org for this code. + * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ + */ + private static final byte[] DECODE_TABLE = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00-0f + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10-1f + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, // 20-2f + - / + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, // 30-3f 0-9 + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 40-4f A-O + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, // 50-5f P-Z _ + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 60-6f a-o + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 // 70-7a p-z + }; + + /** + * Base64 uses 6-bit fields. + */ + /** Mask used to extract 6 bits, used when encoding */ + private static final int MASK_6BITS = 0x3f; + /** Mask used to extract 4 bits, used when decoding final trailing character. */ + private static final int MASK_4BITS = 0xf; + /** Mask used to extract 2 bits, used when decoding final trailing character. */ + private static final int MASK_2BITS = 0x3; + + // The static final fields above are used for the original static byte[] methods on Base64. + // The private member fields below are used with the new streaming approach, which requires + // some state be preserved between calls of encode() and decode(). + + /** + * Decodes Base64 data into octets. + *

+ * Note: this method seamlessly handles data encoded in URL-safe or normal mode. + *

+ * + * @param base64Data + * Byte array containing Base64 data + * @return Array containing decoded data. + */ + public static byte[] decodeBase64(final byte[] base64Data) { + return new Base64().decode(base64Data); + } + + /** + * Decodes a Base64 String into octets. + *

+ * Note: this method seamlessly handles data encoded in URL-safe or normal mode. + *

+ * + * @param base64String + * String containing Base64 data + * @return Array containing decoded data. + * @since 1.4 + */ + public static byte[] decodeBase64(final String base64String) { + return new Base64().decode(base64String); + } + + // Implementation of integer encoding used for crypto + /** + * Decodes a byte64-encoded integer according to crypto standards such as W3C's XML-Signature. + * + * @param pArray + * a byte array containing base64 character data + * @return A BigInteger + * @since 1.4 + */ + public static BigInteger decodeInteger(final byte[] pArray) { + return new BigInteger(1, decodeBase64(pArray)); + } + + /** + * Encodes binary data using the base64 algorithm but does not chunk the output. + * + * @param binaryData + * binary data to encode + * @return byte[] containing Base64 characters in their UTF-8 representation. + */ + public static byte[] encodeBase64(final byte[] binaryData) { + return encodeBase64(binaryData, false); + } + + /** + * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks. + * + * @param binaryData + * Array containing binary data to encode. + * @param isChunked + * if {@code true} this encoder will chunk the base64 output into 76 character blocks + * @return Base64-encoded data. + * @throws IllegalArgumentException + * Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE} + */ + public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked) { + return encodeBase64(binaryData, isChunked, false); + } + + /** + * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks. + * + * @param binaryData + * Array containing binary data to encode. + * @param isChunked + * if {@code true} this encoder will chunk the base64 output into 76 character blocks + * @param urlSafe + * if {@code true} this encoder will emit - and _ instead of the usual + and / characters. + * Note: no padding is added when encoding using the URL-safe alphabet. + * @return Base64-encoded data. + * @throws IllegalArgumentException + * Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE} + * @since 1.4 + */ + public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked, final boolean urlSafe) { + return encodeBase64(binaryData, isChunked, urlSafe, Integer.MAX_VALUE); + } + + /** + * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks. + * + * @param binaryData + * Array containing binary data to encode. + * @param isChunked + * if {@code true} this encoder will chunk the base64 output into 76 character blocks + * @param urlSafe + * if {@code true} this encoder will emit - and _ instead of the usual + and / characters. + * Note: no padding is added when encoding using the URL-safe alphabet. + * @param maxResultSize + * The maximum result size to accept. + * @return Base64-encoded data. + * @throws IllegalArgumentException + * Thrown when the input array needs an output array bigger than maxResultSize + * @since 1.4 + */ + public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked, + final boolean urlSafe, final int maxResultSize) { + if (binaryData == null || binaryData.length == 0) { + return binaryData; + } + + // Create this so can use the super-class method + // Also ensures that the same roundings are performed by the ctor and the code + final Base64 b64 = isChunked ? new Base64(urlSafe) : new Base64(0, CHUNK_SEPARATOR, urlSafe); + final long len = b64.getEncodedLength(binaryData); + if (len > maxResultSize) { + throw new IllegalArgumentException("Input array too big, the output array would be bigger (" + + len + + ") than the specified maximum size of " + + maxResultSize); + } + + return b64.encode(binaryData); + } + + /** + * Encodes binary data using the base64 algorithm and chunks the encoded output into 76 character blocks + * + * @param binaryData + * binary data to encode + * @return Base64 characters chunked in 76 character blocks + */ + public static byte[] encodeBase64Chunked(final byte[] binaryData) { + return encodeBase64(binaryData, true); + } + + /** + * Encodes binary data using the base64 algorithm but does not chunk the output. + * + * NOTE: We changed the behavior of this method from multi-line chunking (commons-codec-1.4) to + * single-line non-chunking (commons-codec-1.5). + * + * @param binaryData + * binary data to encode + * @return String containing Base64 characters. + * @since 1.4 (NOTE: 1.4 chunked the output, whereas 1.5 does not). + */ + public static String encodeBase64String(final byte[] binaryData) { + return new String(encodeBase64(binaryData, false), Charset.forName("UTF-8")); + } + + /** + * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The + * url-safe variation emits - and _ instead of + and / characters. + * Note: no padding is added. + * @param binaryData + * binary data to encode + * @return byte[] containing Base64 characters in their UTF-8 representation. + * @since 1.4 + */ + public static byte[] encodeBase64URLSafe(final byte[] binaryData) { + return encodeBase64(binaryData, false, true); + } + + /** + * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The + * url-safe variation emits - and _ instead of + and / characters. + * Note: no padding is added. + * @param binaryData + * binary data to encode + * @return String containing Base64 characters + * @since 1.4 + */ + public static String encodeBase64URLSafeString(final byte[] binaryData) { + return new String(encodeBase64(binaryData, false, true), Charset.forName("UTF-8")); + } + + /** + * Encodes to a byte64-encoded integer according to crypto standards such as W3C's XML-Signature. + * + * @param bigInteger + * a BigInteger + * @return A byte array containing base64 character data + * @throws NullPointerException + * if null is passed in + * @since 1.4 + */ + public static byte[] encodeInteger(final BigInteger bigInteger) { + return encodeBase64(toIntegerBytes(bigInteger), false); + } + + /** + * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the + * method treats whitespace as valid. + * + * @param arrayOctet + * byte array to test + * @return {@code true} if all bytes are valid characters in the Base64 alphabet or if the byte array is empty; + * {@code false}, otherwise + * @deprecated 1.5 Use {@link #isBase64(byte[])}, will be removed in 2.0. + */ + @Deprecated + public static boolean isArrayByteBase64(final byte[] arrayOctet) { + return isBase64(arrayOctet); + } + + /** + * Returns whether or not the {@code octet} is in the base 64 alphabet. + * + * @param octet + * The value to test + * @return {@code true} if the value is defined in the the base 64 alphabet, {@code false} otherwise. + * @since 1.4 + */ + public static boolean isBase64(final byte octet) { + return octet == PAD_DEFAULT || (octet >= 0 && octet < DECODE_TABLE.length && DECODE_TABLE[octet] != -1); + } + + /** + * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the + * method treats whitespace as valid. + * + * @param arrayOctet + * byte array to test + * @return {@code true} if all bytes are valid characters in the Base64 alphabet or if the byte array is empty; + * {@code false}, otherwise + * @since 1.5 + */ + public static boolean isBase64(final byte[] arrayOctet) { + for (int i = 0; i < arrayOctet.length; i++) { + if (!isBase64(arrayOctet[i]) && !isWhiteSpace(arrayOctet[i])) { + return false; + } + } + return true; + } + + /** + * Tests a given String to see if it contains only valid characters within the Base64 alphabet. Currently the + * method treats whitespace as valid. + * + * @param base64 + * String to test + * @return {@code true} if all characters in the String are valid characters in the Base64 alphabet or if + * the String is empty; {@code false}, otherwise + * @since 1.5 + */ + public static boolean isBase64(final String base64) { + return isBase64(base64.getBytes(Charset.forName("UTF-8"))); + } + + /** + * Returns a byte-array representation of a {@code BigInteger} without sign bit. + * + * @param bigInt + * {@code BigInteger} to be converted + * @return a byte array representation of the BigInteger parameter + */ + static byte[] toIntegerBytes(final BigInteger bigInt) { + int bitlen = bigInt.bitLength(); + // round bitlen + bitlen = ((bitlen + 7) >> 3) << 3; + final byte[] bigBytes = bigInt.toByteArray(); + + if (((bigInt.bitLength() % 8) != 0) && (((bigInt.bitLength() / 8) + 1) == (bitlen / 8))) { + return bigBytes; + } + // set up params for copying everything but sign bit + int startSrc = 0; + int len = bigBytes.length; + + // if bigInt is exactly byte-aligned, just skip signbit in copy + if ((bigInt.bitLength() % 8) == 0) { + startSrc = 1; + len--; + } + final int startDst = bitlen / 8 - len; // to pad w/ nulls as per spec + final byte[] resizedBytes = new byte[bitlen / 8]; + System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, len); + return resizedBytes; + } + + /** + * Encode table to use: either STANDARD or URL_SAFE. Note: the DECODE_TABLE above remains static because it is able + * to decode both STANDARD and URL_SAFE streams, but the encodeTable must be a member variable so we can switch + * between the two modes. + */ + private final byte[] encodeTable; + + // Only one decode table currently; keep for consistency with Base32 code + private final byte[] decodeTable = DECODE_TABLE; + + /** + * Line separator for encoding. Not used when decoding. Only used if lineLength > 0. + */ + private final byte[] lineSeparator; + + /** + * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing. + * {@code decodeSize = 3 + lineSeparator.length;} + */ + private final int decodeSize; + + /** + * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing. + * {@code encodeSize = 4 + lineSeparator.length;} + */ + private final int encodeSize; + + /** + * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. + *

+ * When encoding the line length is 0 (no chunking), and the encoding table is STANDARD_ENCODE_TABLE. + *

+ * + *

+ * When decoding all variants are supported. + *

+ */ + public Base64() { + this(0); + } + + /** + * Creates a Base64 codec used for decoding (all modes) and encoding in the given URL-safe mode. + *

+ * When encoding the line length is 76, the line separator is CRLF, and the encoding table is STANDARD_ENCODE_TABLE. + *

+ * + *

+ * When decoding all variants are supported. + *

+ * + * @param urlSafe + * if {@code true}, URL-safe encoding is used. In most cases this should be set to + * {@code false}. + * @since 1.4 + */ + public Base64(final boolean urlSafe) { + this(MIME_CHUNK_SIZE, CHUNK_SEPARATOR, urlSafe); + } + + /** + * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. + *

+ * When encoding the line length is given in the constructor, the line separator is CRLF, and the encoding table is + * STANDARD_ENCODE_TABLE. + *

+ *

+ * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data. + *

+ *

+ * When decoding all variants are supported. + *

+ * + * @param lineLength + * Each line of encoded data will be at most of the given length (rounded down to nearest multiple of + * 4). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when + * decoding. + * @since 1.4 + */ + public Base64(final int lineLength) { + this(lineLength, CHUNK_SEPARATOR); + } + + /** + * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. + *

+ * When encoding the line length and line separator are given in the constructor, and the encoding table is + * STANDARD_ENCODE_TABLE. + *

+ *

+ * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data. + *

+ *

+ * When decoding all variants are supported. + *

+ * + * @param lineLength + * Each line of encoded data will be at most of the given length (rounded down to nearest multiple of + * 4). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when + * decoding. + * @param lineSeparator + * Each line of encoded data will end with this sequence of bytes. + * @throws IllegalArgumentException + * Thrown when the provided lineSeparator included some base64 characters. + * @since 1.4 + */ + public Base64(final int lineLength, final byte[] lineSeparator) { + this(lineLength, lineSeparator, false); + } + + /** + * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. + *

+ * When encoding the line length and line separator are given in the constructor, and the encoding table is + * STANDARD_ENCODE_TABLE. + *

+ *

+ * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data. + *

+ *

+ * When decoding all variants are supported. + *

+ * + * @param lineLength + * Each line of encoded data will be at most of the given length (rounded down to nearest multiple of + * 4). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when + * decoding. + * @param lineSeparator + * Each line of encoded data will end with this sequence of bytes. + * @param urlSafe + * Instead of emitting '+' and '/' we emit '-' and '_' respectively. urlSafe is only applied to encode + * operations. Decoding seamlessly handles both modes. + * Note: no padding is added when using the URL-safe alphabet. + * @throws IllegalArgumentException + * Thrown when the {@code lineSeparator} contains Base64 characters. + * @since 1.4 + */ + public Base64(final int lineLength, final byte[] lineSeparator, final boolean urlSafe) { + this(lineLength, lineSeparator, urlSafe, CodecPolicy.LENIANT); + } + + /** + * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. + *

+ * When encoding the line length and line separator are given in the constructor, and the encoding table is + * STANDARD_ENCODE_TABLE. + *

+ *

+ * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data. + *

+ *

+ * When decoding all variants are supported. + *

+ * + * @param lineLength + * Each line of encoded data will be at most of the given length (rounded down to nearest multiple of + * 4). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when + * decoding. + * @param lineSeparator + * Each line of encoded data will end with this sequence of bytes. + * @param urlSafe + * Instead of emitting '+' and '/' we emit '-' and '_' respectively. urlSafe is only applied to encode + * operations. Decoding seamlessly handles both modes. + * Note: no padding is added when using the URL-safe alphabet. + * @param decodingPolicy The decoding policy. + * @throws IllegalArgumentException + * Thrown when the {@code lineSeparator} contains Base64 characters. + * @since 1.15 + */ + public Base64(final int lineLength, final byte[] lineSeparator, final boolean urlSafe, final CodecPolicy decodingPolicy) { + super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, + lineLength, + lineSeparator == null ? 0 : lineSeparator.length, + PAD_DEFAULT, + decodingPolicy); + // TODO could be simplified if there is no requirement to reject invalid line sep when length <=0 + // @see test case Base64Test.testConstructors() + if (lineSeparator != null) { + if (containsAlphabetOrPad(lineSeparator)) { + final String sep = new String(lineSeparator, Charset.forName("UTF-8")); + throw new IllegalArgumentException("lineSeparator must not contain base64 characters: [" + sep + "]"); + } + if (lineLength > 0){ // null line-sep forces no chunking rather than throwing IAE + this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparator.length; + this.lineSeparator = new byte[lineSeparator.length]; + System.arraycopy(lineSeparator, 0, this.lineSeparator, 0, lineSeparator.length); + } else { + this.encodeSize = BYTES_PER_ENCODED_BLOCK; + this.lineSeparator = null; + } + } else { + this.encodeSize = BYTES_PER_ENCODED_BLOCK; + this.lineSeparator = null; + } + this.decodeSize = this.encodeSize - 1; + this.encodeTable = urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE; + } + + // Implementation of the Encoder Interface + + /** + *

+ * Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at least twice: once + * with the data to decode, and once with inAvail set to "-1" to alert decoder that EOF has been reached. The "-1" + * call is not necessary when decoding, but it doesn't hurt, either. + *

+ *

+ * Ignores all non-base64 characters. This is how chunked (e.g. 76 character) data is handled, since CR and LF are + * silently ignored, but has implications for other bytes, too. This method subscribes to the garbage-in, + * garbage-out philosophy: it will not check the provided data for validity. + *

+ *

+ * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach. + * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ + *

+ * + * @param in + * byte[] array of ascii data to base64 decode. + * @param inPos + * Position to start reading data from. + * @param inAvail + * Amount of bytes available from input for decoding. + * @param context + * the context to be used + */ + @Override + void decode(final byte[] in, int inPos, final int inAvail, final Context context) { + if (context.eof) { + return; + } + if (inAvail < 0) { + context.eof = true; + } + for (int i = 0; i < inAvail; i++) { + final byte[] buffer = ensureBufferSize(decodeSize, context); + final byte b = in[inPos++]; + if (b == pad) { + // We're done. + context.eof = true; + break; + } + if (b >= 0 && b < DECODE_TABLE.length) { + final int result = DECODE_TABLE[b]; + if (result >= 0) { + context.modulus = (context.modulus+1) % BYTES_PER_ENCODED_BLOCK; + context.ibitWorkArea = (context.ibitWorkArea << BITS_PER_ENCODED_BYTE) + result; + if (context.modulus == 0) { + buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 16) & MASK_8BITS); + buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS); + buffer[context.pos++] = (byte) (context.ibitWorkArea & MASK_8BITS); + } + } + } + } + + // Two forms of EOF as far as base64 decoder is concerned: actual + // EOF (-1) and first time '=' character is encountered in stream. + // This approach makes the '=' padding characters completely optional. + if (context.eof && context.modulus != 0) { + final byte[] buffer = ensureBufferSize(decodeSize, context); + + // We have some spare bits remaining + // Output all whole multiples of 8 bits and ignore the rest + switch (context.modulus) { +// case 0 : // impossible, as excluded above + case 1 : // 6 bits - either ignore entirely, or raise an exception + validateTrailingCharacter(); + break; + case 2 : // 12 bits = 8 + 4 + validateCharacter(MASK_4BITS, context); + context.ibitWorkArea = context.ibitWorkArea >> 4; // dump the extra 4 bits + buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS); + break; + case 3 : // 18 bits = 8 + 8 + 2 + validateCharacter(MASK_2BITS, context); + context.ibitWorkArea = context.ibitWorkArea >> 2; // dump 2 bits + buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS); + buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS); + break; + default: + throw new IllegalStateException("Impossible modulus " + context.modulus); + } + } + } + + /** + *

+ * Encodes all of the provided data, starting at inPos, for inAvail bytes. Must be called at least twice: once with + * the data to encode, and once with inAvail set to "-1" to alert encoder that EOF has been reached, to flush last + * remaining bytes (if not multiple of 3). + *

+ *

Note: no padding is added when encoding using the URL-safe alphabet.

+ *

+ * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach. + * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ + *

+ * + * @param in + * byte[] array of binary data to base64 encode. + * @param inPos + * Position to start reading data from. + * @param inAvail + * Amount of bytes available from input for encoding. + * @param context + * the context to be used + */ + @Override + void encode(final byte[] in, int inPos, final int inAvail, final Context context) { + if (context.eof) { + return; + } + // inAvail < 0 is how we're informed of EOF in the underlying data we're + // encoding. + if (inAvail < 0) { + context.eof = true; + if (0 == context.modulus && lineLength == 0) { + return; // no leftovers to process and not using chunking + } + final byte[] buffer = ensureBufferSize(encodeSize, context); + final int savedPos = context.pos; + switch (context.modulus) { // 0-2 + case 0 : // nothing to do here + break; + case 1 : // 8 bits = 6 + 2 + // top 6 bits: + buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 2) & MASK_6BITS]; + // remaining 2: + buffer[context.pos++] = encodeTable[(context.ibitWorkArea << 4) & MASK_6BITS]; + // URL-SAFE skips the padding to further reduce size. + if (encodeTable == STANDARD_ENCODE_TABLE) { + buffer[context.pos++] = pad; + buffer[context.pos++] = pad; + } + break; + + case 2 : // 16 bits = 6 + 6 + 4 + buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 10) & MASK_6BITS]; + buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 4) & MASK_6BITS]; + buffer[context.pos++] = encodeTable[(context.ibitWorkArea << 2) & MASK_6BITS]; + // URL-SAFE skips the padding to further reduce size. + if (encodeTable == STANDARD_ENCODE_TABLE) { + buffer[context.pos++] = pad; + } + break; + default: + throw new IllegalStateException("Impossible modulus " + context.modulus); + } + context.currentLinePos += context.pos - savedPos; // keep track of current line position + // if currentPos == 0 we are at the start of a line, so don't add CRLF + if (lineLength > 0 && context.currentLinePos > 0) { + System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length); + context.pos += lineSeparator.length; + } + } else { + for (int i = 0; i < inAvail; i++) { + final byte[] buffer = ensureBufferSize(encodeSize, context); + context.modulus = (context.modulus+1) % BYTES_PER_UNENCODED_BLOCK; + int b = in[inPos++]; + if (b < 0) { + b += 256; + } + context.ibitWorkArea = (context.ibitWorkArea << 8) + b; // BITS_PER_BYTE + if (0 == context.modulus) { // 3 bytes = 24 bits = 4 * 6 bits to extract + buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 18) & MASK_6BITS]; + buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 12) & MASK_6BITS]; + buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 6) & MASK_6BITS]; + buffer[context.pos++] = encodeTable[context.ibitWorkArea & MASK_6BITS]; + context.currentLinePos += BYTES_PER_ENCODED_BLOCK; + if (lineLength > 0 && lineLength <= context.currentLinePos) { + System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length); + context.pos += lineSeparator.length; + context.currentLinePos = 0; + } + } + } + } + } + + /** + * Returns whether or not the {@code octet} is in the Base64 alphabet. + * + * @param octet + * The value to test + * @return {@code true} if the value is defined in the the Base64 alphabet {@code false} otherwise. + */ + @Override + protected boolean isInAlphabet(final byte octet) { + return octet >= 0 && octet < decodeTable.length && decodeTable[octet] != -1; + } + + /** + * Returns our current encode mode. True if we're URL-SAFE, false otherwise. + * + * @return true if we're in URL-SAFE mode, false otherwise. + * @since 1.4 + */ + public boolean isUrlSafe() { + return this.encodeTable == URL_SAFE_ENCODE_TABLE; + } + + /** + * Validates whether decoding the final trailing character is possible in the context + * of the set of possible base 64 values. + * + *

The character is valid if the lower bits within the provided mask are zero. This + * is used to test the final trailing base-64 digit is zero in the bits that will be discarded. + * + * @param emptyBitsMask The mask of the lower bits that should be empty + * @param context the context to be used + * + * @throws IllegalArgumentException if the bits being checked contain any non-zero value + */ + private void validateCharacter(final int emptyBitsMask, final Context context) { + if (isStrictDecoding() && (context.ibitWorkArea & emptyBitsMask) != 0) { + throw new IllegalArgumentException( + "Strict decoding: Last encoded character (before the paddings if any) is a valid base 64 alphabet but not a possible encoding. " + + "Expected the discarded bits from the character to be zero."); + } + } + + /** + * Validates whether decoding allows an entire final trailing character that cannot be + * used for a complete byte. + * + * @throws IllegalArgumentException if strict decoding is enabled + */ + private void validateTrailingCharacter() { + if (isStrictDecoding()) { + throw new IllegalArgumentException( + "Strict decoding: Last encoded character (before the paddings if any) is a valid base 64 alphabet but not a possible encoding. " + + "Decoding requires at least two trailing 6-bit characters to create bytes."); + } + } + +} \ No newline at end of file diff --git a/src/main/java/net/lax1dude/eaglercraft/BaseNCodec.java b/src/main/java/net/lax1dude/eaglercraft/BaseNCodec.java new file mode 100644 index 0000000..cd78ed3 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/BaseNCodec.java @@ -0,0 +1,672 @@ +package net.lax1dude.eaglercraft; + +import java.nio.charset.Charset; +import java.util.Arrays; + +public abstract class BaseNCodec { + + static enum CodecPolicy { + STRICT,LENIANT; + } + + /** + * Holds thread context so classes can be thread-safe. + * + * This class is not itself thread-safe; each thread must allocate its own copy. + * + * @since 1.7 + */ + static class Context { + + /** + * Place holder for the bytes we're dealing with for our based logic. + * Bitwise operations store and extract the encoding or decoding from this variable. + */ + int ibitWorkArea; + + /** + * Place holder for the bytes we're dealing with for our based logic. + * Bitwise operations store and extract the encoding or decoding from this variable. + */ + long lbitWorkArea; + + /** + * Buffer for streaming. + */ + byte[] buffer; + + /** + * Position where next character should be written in the buffer. + */ + int pos; + + /** + * Position where next character should be read from the buffer. + */ + int readPos; + + /** + * Boolean flag to indicate the EOF has been reached. Once EOF has been reached, this object becomes useless, + * and must be thrown away. + */ + boolean eof; + + /** + * Variable tracks how many characters have been written to the current line. Only used when encoding. We use + * it to make sure each encoded line never goes beyond lineLength (if lineLength > 0). + */ + int currentLinePos; + + /** + * Writes to the buffer only occur after every 3/5 reads when encoding, and every 4/8 reads when decoding. This + * variable helps track that. + */ + int modulus; + + Context() { + } + + /** + * Returns a String useful for debugging (especially within a debugger.) + * + * @return a String useful for debugging. + */ + @SuppressWarnings("boxing") // OK to ignore boxing here + @Override + public String toString() { + return String.format("%s[buffer=%s, currentLinePos=%s, eof=%s, ibitWorkArea=%s, lbitWorkArea=%s, " + + "modulus=%s, pos=%s, readPos=%s]", this.getClass().getSimpleName(), Arrays.toString(buffer), + currentLinePos, eof, ibitWorkArea, lbitWorkArea, modulus, pos, readPos); + } + } + + /** + * EOF + * + * @since 1.7 + */ + static final int EOF = -1; + + /** + * MIME chunk size per RFC 2045 section 6.8. + * + *

+ * The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any + * equal signs. + *

+ * + * @see RFC 2045 section 6.8 + */ + public static final int MIME_CHUNK_SIZE = 76; + + /** + * PEM chunk size per RFC 1421 section 4.3.2.4. + * + *

+ * The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any + * equal signs. + *

+ * + * @see RFC 1421 section 4.3.2.4 + */ + public static final int PEM_CHUNK_SIZE = 64; + + private static final int DEFAULT_BUFFER_RESIZE_FACTOR = 2; + + /** + * Defines the default buffer size - currently {@value} + * - must be large enough for at least one encoded block+separator + */ + private static final int DEFAULT_BUFFER_SIZE = 8192; + + /** + * The maximum size buffer to allocate. + * + *

This is set to the same size used in the JDK {@code java.util.ArrayList}:

+ *
+ * Some VMs reserve some header words in an array. + * Attempts to allocate larger arrays may result in + * OutOfMemoryError: Requested array size exceeds VM limit. + *
+ */ + private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8; + + /** Mask used to extract 8 bits, used in decoding bytes */ + protected static final int MASK_8BITS = 0xff; + + /** + * Byte used to pad output. + */ + protected static final byte PAD_DEFAULT = '='; // Allow static access to default + + /** + * Chunk separator per RFC 2045 section 2.1. + * + * @see RFC 2045 section 2.1 + */ + static final byte[] CHUNK_SEPARATOR = {'\r', '\n'}; + + /** + * Compares two {@code int} values numerically treating the values + * as unsigned. Taken from JDK 1.8. + * + *

TODO: Replace with JDK 1.8 Integer::compareUnsigned(int, int).

+ * + * @param x the first {@code int} to compare + * @param y the second {@code int} to compare + * @return the value {@code 0} if {@code x == y}; a value less + * than {@code 0} if {@code x < y} as unsigned values; and + * a value greater than {@code 0} if {@code x > y} as + * unsigned values + */ + private static int compareUnsigned(final int xx, final int yy) { + int x = xx + Integer.MIN_VALUE; + int y = yy + Integer.MIN_VALUE; + return (x < y) ? -1 : ((x == y) ? 0 : 1); + } + + /** + * Create a positive capacity at least as large the minimum required capacity. + * If the minimum capacity is negative then this throws an OutOfMemoryError as no array + * can be allocated. + * + * @param minCapacity the minimum capacity + * @return the capacity + * @throws OutOfMemoryError if the {@code minCapacity} is negative + */ + private static int createPositiveCapacity(final int minCapacity) { + if (minCapacity < 0) { + // overflow + throw new OutOfMemoryError("Unable to allocate array size: " + (minCapacity & 0xffffffffL)); + } + // This is called when we require buffer expansion to a very big array. + // Use the conservative maximum buffer size if possible, otherwise the biggest required. + // + // Note: In this situation JDK 1.8 java.util.ArrayList returns Integer.MAX_VALUE. + // This excludes some VMs that can exceed MAX_BUFFER_SIZE but not allocate a full + // Integer.MAX_VALUE length array. + // The result is that we may have to allocate an array of this size more than once if + // the capacity must be expanded again. + return (minCapacity > MAX_BUFFER_SIZE) ? + minCapacity : + MAX_BUFFER_SIZE; + } + + /** + * Gets a copy of the chunk separator per RFC 2045 section 2.1. + * + * @return the chunk separator + * @see RFC 2045 section 2.1 + * @since 1.15 + */ + public static byte[] getChunkSeparator() { + return CHUNK_SEPARATOR.clone(); + } + + /** + * Checks if a byte value is whitespace or not. + * Whitespace is taken to mean: space, tab, CR, LF + * @param byteToCheck + * the byte to check + * @return true if byte is whitespace, false otherwise + */ + protected static boolean isWhiteSpace(final byte byteToCheck) { + switch (byteToCheck) { + case ' ' : + case '\n' : + case '\r' : + case '\t' : + return true; + default : + return false; + } + } + + /** + * Increases our buffer by the {@link #DEFAULT_BUFFER_RESIZE_FACTOR}. + * @param context the context to be used + * @param minCapacity the minimum required capacity + * @return the resized byte[] buffer + * @throws OutOfMemoryError if the {@code minCapacity} is negative + */ + private static byte[] resizeBuffer(final Context context, final int minCapacity) { + // Overflow-conscious code treats the min and new capacity as unsigned. + final int oldCapacity = context.buffer.length; + int newCapacity = oldCapacity * DEFAULT_BUFFER_RESIZE_FACTOR; + if (compareUnsigned(newCapacity, minCapacity) < 0) { + newCapacity = minCapacity; + } + if (compareUnsigned(newCapacity, MAX_BUFFER_SIZE) > 0) { + newCapacity = createPositiveCapacity(minCapacity); + } + + final byte[] b = new byte[newCapacity]; + System.arraycopy(context.buffer, 0, b, 0, context.buffer.length); + context.buffer = b; + return b; + } + + /** + * @deprecated Use {@link #pad}. Will be removed in 2.0. + */ + @Deprecated + protected final byte PAD = PAD_DEFAULT; // instance variable just in case it needs to vary later + + protected final byte pad; // instance variable just in case it needs to vary later + + /** Number of bytes in each full block of unencoded data, e.g. 4 for Base64 and 5 for Base32 */ + private final int unencodedBlockSize; + + /** Number of bytes in each full block of encoded data, e.g. 3 for Base64 and 8 for Base32 */ + private final int encodedBlockSize; + + /** + * Chunksize for encoding. Not used when decoding. + * A value of zero or less implies no chunking of the encoded data. + * Rounded down to nearest multiple of encodedBlockSize. + */ + protected final int lineLength; + + /** + * Size of chunk separator. Not used unless {@link #lineLength} > 0. + */ + private final int chunkSeparatorLength; + + /** + * Defines the decoding behavior when the input bytes contain leftover trailing bits that + * cannot be created by a valid encoding. These can be bits that are unused from the final + * character or entire characters. The default mode is lenient decoding. Set this to + * {@code true} to enable strict decoding. + *
    + *
  • Lenient: Any trailing bits are composed into 8-bit bytes where possible. + * The remainder are discarded. + *
  • Strict: The decoding will raise an {@link IllegalArgumentException} if trailing bits + * are not part of a valid encoding. Any unused bits from the final character must + * be zero. Impossible counts of entire final characters are not allowed. + *
+ * + *

When strict decoding is enabled it is expected that the decoded bytes will be re-encoded + * to a byte array that matches the original, i.e. no changes occur on the final + * character. This requires that the input bytes use the same padding and alphabet + * as the encoder. + */ + private final CodecPolicy decodingPolicy; + + /** + * Note {@code lineLength} is rounded down to the nearest multiple of the encoded block size. + * If {@code chunkSeparatorLength} is zero, then chunking is disabled. + * @param unencodedBlockSize the size of an unencoded block (e.g. Base64 = 3) + * @param encodedBlockSize the size of an encoded block (e.g. Base64 = 4) + * @param lineLength if > 0, use chunking with a length {@code lineLength} + * @param chunkSeparatorLength the chunk separator length, if relevant + */ + protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize, + final int lineLength, final int chunkSeparatorLength) { + this(unencodedBlockSize, encodedBlockSize, lineLength, chunkSeparatorLength, PAD_DEFAULT); + } + + /** + * Note {@code lineLength} is rounded down to the nearest multiple of the encoded block size. + * If {@code chunkSeparatorLength} is zero, then chunking is disabled. + * @param unencodedBlockSize the size of an unencoded block (e.g. Base64 = 3) + * @param encodedBlockSize the size of an encoded block (e.g. Base64 = 4) + * @param lineLength if > 0, use chunking with a length {@code lineLength} + * @param chunkSeparatorLength the chunk separator length, if relevant + * @param pad byte used as padding byte. + */ + protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize, + final int lineLength, final int chunkSeparatorLength, final byte pad) { + this(unencodedBlockSize, encodedBlockSize, lineLength, chunkSeparatorLength, pad, CodecPolicy.LENIANT); + } + + /** + * Note {@code lineLength} is rounded down to the nearest multiple of the encoded block size. + * If {@code chunkSeparatorLength} is zero, then chunking is disabled. + * @param unencodedBlockSize the size of an unencoded block (e.g. Base64 = 3) + * @param encodedBlockSize the size of an encoded block (e.g. Base64 = 4) + * @param lineLength if > 0, use chunking with a length {@code lineLength} + * @param chunkSeparatorLength the chunk separator length, if relevant + * @param pad byte used as padding byte. + * @param decodingPolicy Decoding policy. + * @since 1.15 + */ + protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize, + final int lineLength, final int chunkSeparatorLength, final byte pad, final CodecPolicy decodingPolicy) { + this.unencodedBlockSize = unencodedBlockSize; + this.encodedBlockSize = encodedBlockSize; + final boolean useChunking = lineLength > 0 && chunkSeparatorLength > 0; + this.lineLength = useChunking ? (lineLength / encodedBlockSize) * encodedBlockSize : 0; + this.chunkSeparatorLength = chunkSeparatorLength; + this.pad = pad; + this.decodingPolicy = decodingPolicy; + } + + /** + * Returns the amount of buffered data available for reading. + * + * @param context the context to be used + * @return The amount of buffered data available for reading. + */ + int available(final Context context) { // package protected for access from I/O streams + return context.buffer != null ? context.pos - context.readPos : 0; + } + + /** + * Tests a given byte array to see if it contains any characters within the alphabet or PAD. + * + * Intended for use in checking line-ending arrays + * + * @param arrayOctet + * byte array to test + * @return {@code true} if any byte is a valid character in the alphabet or PAD; {@code false} otherwise + */ + protected boolean containsAlphabetOrPad(final byte[] arrayOctet) { + if (arrayOctet == null) { + return false; + } + for (final byte element : arrayOctet) { + if (pad == element || isInAlphabet(element)) { + return true; + } + } + return false; + } + + /** + * Decodes a byte[] containing characters in the Base-N alphabet. + * + * @param pArray + * A byte array containing Base-N character data + * @return a byte array containing binary data + */ + public byte[] decode(final byte[] pArray) { + if (pArray == null || pArray.length == 0) { + return pArray; + } + final Context context = new Context(); + decode(pArray, 0, pArray.length, context); + decode(pArray, 0, EOF, context); // Notify decoder of EOF. + final byte[] result = new byte[context.pos]; + readResults(result, 0, result.length, context); + return result; + } + + // package protected for access from I/O streams + abstract void decode(byte[] pArray, int i, int length, Context context); + + /** + * Decodes an Object using the Base-N algorithm. This method is provided in order to satisfy the requirements of + * the Decoder interface, and will throw a DecoderException if the supplied object is not of type byte[] or String. + * + * @param obj + * Object to decode + * @return An object (of type byte[]) containing the binary data which corresponds to the byte[] or String + * supplied. + * @throws DecoderException + * if the parameter supplied is not of type byte[] + */ + public Object decode(final Object obj) { + if (obj instanceof byte[]) { + return decode((byte[]) obj); + } else if (obj instanceof String) { + return decode((String) obj); + } else { + return null; + } + } + + /** + * Decodes a String containing characters in the Base-N alphabet. + * + * @param pArray + * A String containing Base-N character data + * @return a byte array containing binary data + */ + public byte[] decode(final String pArray) { + return decode(pArray.getBytes(Charset.forName("UTF-8"))); + } + + /** + * Encodes a byte[] containing binary data, into a byte[] containing characters in the alphabet. + * + * @param pArray + * a byte array containing binary data + * @return A byte array containing only the base N alphabetic character data + */ + public byte[] encode(final byte[] pArray) { + if (pArray == null || pArray.length == 0) { + return pArray; + } + return encode(pArray, 0, pArray.length); + } + + /** + * Encodes a byte[] containing binary data, into a byte[] containing + * characters in the alphabet. + * + * @param pArray + * a byte array containing binary data + * @param offset + * initial offset of the subarray. + * @param length + * length of the subarray. + * @return A byte array containing only the base N alphabetic character data + * @since 1.11 + */ + public byte[] encode(final byte[] pArray, final int offset, final int length) { + if (pArray == null || pArray.length == 0) { + return pArray; + } + final Context context = new Context(); + encode(pArray, offset, length, context); + encode(pArray, offset, EOF, context); // Notify encoder of EOF. + final byte[] buf = new byte[context.pos - context.readPos]; + readResults(buf, 0, buf.length, context); + return buf; + } + + // package protected for access from I/O streams + abstract void encode(byte[] pArray, int i, int length, Context context); + + /** + * Encodes an Object using the Base-N algorithm. This method is provided in order to satisfy the requirements of + * the Encoder interface, and will throw an EncoderException if the supplied object is not of type byte[]. + * + * @param obj + * Object to encode + * @return An object (of type byte[]) containing the Base-N encoded data which corresponds to the byte[] supplied. + * @throws EncoderException + * if the parameter supplied is not of type byte[] + */ + public Object encode(final Object obj) { + return encode((byte[]) obj); + } + + /** + * Encodes a byte[] containing binary data, into a String containing characters in the appropriate alphabet. + * Uses UTF8 encoding. + * + * @param pArray a byte array containing binary data + * @return String containing only character data in the appropriate alphabet. + * @since 1.5 + * This is a duplicate of {@link #encodeToString(byte[])}; it was merged during refactoring. + */ + public String encodeAsString(final byte[] pArray){ + return new String(encode(pArray), Charset.forName("UTF-8")); + } + + /** + * Encodes a byte[] containing binary data, into a String containing characters in the Base-N alphabet. + * Uses UTF8 encoding. + * + * @param pArray + * a byte array containing binary data + * @return A String containing only Base-N character data + */ + public String encodeToString(final byte[] pArray) { + return new String(encode(pArray), Charset.forName("UTF-8")); + } + + /** + * Ensure that the buffer has room for {@code size} bytes + * + * @param size minimum spare space required + * @param context the context to be used + * @return the buffer + */ + protected byte[] ensureBufferSize(final int size, final Context context){ + if (context.buffer == null) { + context.buffer = new byte[Math.max(size, getDefaultBufferSize())]; + context.pos = 0; + context.readPos = 0; + + // Overflow-conscious: + // x + y > z == x + y - z > 0 + } else if (context.pos + size - context.buffer.length > 0) { + return resizeBuffer(context, context.pos + size); + } + return context.buffer; + } + + /** + * Returns the decoding behavior policy. + * + *

+ * The default is lenient. If the decoding policy is strict, then decoding will raise an + * {@link IllegalArgumentException} if trailing bits are not part of a valid encoding. Decoding will compose + * trailing bits into 8-bit bytes and discard the remainder. + *

+ * + * @return true if using strict decoding + * @since 1.15 + */ + public CodecPolicy getCodecPolicy() { + return decodingPolicy; + } + + /** + * Get the default buffer size. Can be overridden. + * + * @return the default buffer size. + */ + protected int getDefaultBufferSize() { + return DEFAULT_BUFFER_SIZE; + } + + /** + * Calculates the amount of space needed to encode the supplied array. + * + * @param pArray byte[] array which will later be encoded + * + * @return amount of space needed to encoded the supplied array. + * Returns a long since a max-len array will require > Integer.MAX_VALUE + */ + public long getEncodedLength(final byte[] pArray) { + // Calculate non-chunked size - rounded up to allow for padding + // cast to long is needed to avoid possibility of overflow + long len = ((pArray.length + unencodedBlockSize-1) / unencodedBlockSize) * (long) encodedBlockSize; + if (lineLength > 0) { // We're using chunking + // Round up to nearest multiple + len += ((len + lineLength-1) / lineLength) * chunkSeparatorLength; + } + return len; + } + + /** + * Returns true if this object has buffered data for reading. + * + * @param context the context to be used + * @return true if there is data still available for reading. + */ + boolean hasData(final Context context) { // package protected for access from I/O streams + return context.buffer != null; + } + + /** + * Returns whether or not the {@code octet} is in the current alphabet. + * Does not allow whitespace or pad. + * + * @param value The value to test + * + * @return {@code true} if the value is defined in the current alphabet, {@code false} otherwise. + */ + protected abstract boolean isInAlphabet(byte value); + + /** + * Tests a given byte array to see if it contains only valid characters within the alphabet. + * The method optionally treats whitespace and pad as valid. + * + * @param arrayOctet byte array to test + * @param allowWSPad if {@code true}, then whitespace and PAD are also allowed + * + * @return {@code true} if all bytes are valid characters in the alphabet or if the byte array is empty; + * {@code false}, otherwise + */ + public boolean isInAlphabet(final byte[] arrayOctet, final boolean allowWSPad) { + for (final byte octet : arrayOctet) { + if (!isInAlphabet(octet) && + (!allowWSPad || (octet != pad) && !isWhiteSpace(octet))) { + return false; + } + } + return true; + } + + /** + * Tests a given String to see if it contains only valid characters within the alphabet. + * The method treats whitespace and PAD as valid. + * + * @param basen String to test + * @return {@code true} if all characters in the String are valid characters in the alphabet or if + * the String is empty; {@code false}, otherwise + * @see #isInAlphabet(byte[], boolean) + */ + public boolean isInAlphabet(final String basen) { + return isInAlphabet(basen.getBytes(Charset.forName("UTF-8")), true); + } + + /** + * Returns true if decoding behavior is strict. Decoding will raise an {@link IllegalArgumentException} if trailing + * bits are not part of a valid encoding. + * + *

+ * The default is false for lenient decoding. Decoding will compose trailing bits into 8-bit bytes and discard the + * remainder. + *

+ * + * @return true if using strict decoding + * @since 1.15 + */ + public boolean isStrictDecoding() { + return decodingPolicy == CodecPolicy.STRICT; + } + + /** + * Extracts buffered data into the provided byte[] array, starting at position bPos, up to a maximum of bAvail + * bytes. Returns how many bytes were actually extracted. + *

+ * Package protected for access from I/O streams. + * + * @param b + * byte[] array to extract the buffered data into. + * @param bPos + * position in byte[] array to start extraction at. + * @param bAvail + * amount of bytes we're allowed to extract. We may extract fewer (if fewer are available). + * @param context + * the context to be used + * @return The number of bytes successfully extracted into the provided byte[] array. + */ + int readResults(final byte[] b, final int bPos, final int bAvail, final Context context) { + if (context.buffer != null) { + final int len = Math.min(available(context), bAvail); + System.arraycopy(context.buffer, context.readPos, b, bPos, len); + context.readPos += len; + if (context.readPos >= context.pos) { + context.buffer = null; // so hasData() will return false, and this method can return -1 + } + return len; + } + return context.eof ? EOF : 0; + } +} \ No newline at end of file diff --git a/src/main/java/net/lax1dude/eaglercraft/ConfigConstants.java b/src/main/java/net/lax1dude/eaglercraft/ConfigConstants.java new file mode 100644 index 0000000..58b64dd --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/ConfigConstants.java @@ -0,0 +1,30 @@ +package net.lax1dude.eaglercraft; + +import java.util.List; + +public class ConfigConstants { + + public static boolean profanity = false; + + public static final String version = "1.5.2-sp2.01"; + public static final String mainMenuString = "eaglercraft " + version; + + public static final String forkMe = null; + + public static String ayonullTitle = null; + public static String ayonullLink = null; + + public static String mainMenuItemLine0 = null; + public static String mainMenuItemLine1 = null; + public static String mainMenuItemLine2 = null; + public static String mainMenuItemLink = null; + + public static List splashTexts = null; + + public static List relays = null; + + public static boolean eaglercraftTitleLogo = false; + + public static boolean panoramaBlur = true; + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/DebugIconImpl.java b/src/main/java/net/lax1dude/eaglercraft/DebugIconImpl.java new file mode 100644 index 0000000..8e13d2e --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/DebugIconImpl.java @@ -0,0 +1,81 @@ +package net.lax1dude.eaglercraft; + +import net.minecraft.src.Icon; + +public class DebugIconImpl implements Icon { + + private final int sheetW; + private final int sheetH; + + public DebugIconImpl() { + this(1024, 1024); + } + + public DebugIconImpl(int sheetW, int sheetH) { + this.sheetW = sheetW; + this.sheetH = sheetH; + } + + public int getOriginX() { + return 0; + } + + public int getOriginY() { + return 0; + } + + @Override + public int getIconWidth() { + return 0; + } + + @Override + public int getIconHeight() { + return 0; + } + + @Override + public float getMinU() { + return 0; + } + + @Override + public float getMaxU() { + return 1; + } + + @Override + public float getInterpolatedU(double var1) { + return (float)var1 / 16.0f; + } + + @Override + public float getMinV() { + return 0; + } + + @Override + public float getMaxV() { + return 1; + } + + @Override + public float getInterpolatedV(double var1) { + return (float)var1 / 16.0f; + } + + @Override + public String getIconName() { + return "debug_icon"; + } + + public int getSheetWidth() { + return sheetW; + } + + public int getSheetHeight() { + return sheetH; + } + + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/DefaultSkinRenderer.java b/src/main/java/net/lax1dude/eaglercraft/DefaultSkinRenderer.java new file mode 100644 index 0000000..2a9d2b1 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/DefaultSkinRenderer.java @@ -0,0 +1,729 @@ +package net.lax1dude.eaglercraft; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map.Entry; + +import net.lax1dude.eaglercraft.EaglerProfile.EaglerProfileCape; +import net.minecraft.src.Minecraft; +import net.minecraft.src.EntityClientPlayerMP; +import net.minecraft.src.EntityOtherPlayerMP; +import net.minecraft.src.EntityPlayer; +import net.minecraft.src.ModelBiped; +import net.minecraft.src.ModelBlaze; +import net.minecraft.src.ModelEnderman; +import net.minecraft.src.ModelSkeleton; +import net.minecraft.src.ModelVillager; +import net.minecraft.src.ModelZombie; +import net.minecraft.src.OpenGlHelper; +import net.minecraft.src.Packet250CustomPayload; +import net.minecraft.src.RenderEnderman; +import net.minecraft.src.RenderHelper; + +public class DefaultSkinRenderer { + + public static final TextureLocation[] defaultVanillaSkins = new TextureLocation[] { + new TextureLocation("/skins/01.default_steve.png"), + new TextureLocation("/skins/02.default_alex.png"), + new TextureLocation("/skins/03.tennis_steve.png"), + new TextureLocation("/skins/04.tennis_alex.png"), + new TextureLocation("/skins/05.tuxedo_steve.png"), + new TextureLocation("/skins/06.tuxedo_alex.png"), + new TextureLocation("/skins/07.athlete_steve.png"), + new TextureLocation("/skins/08.athlete_alex.png"), + new TextureLocation("/skins/09.cyclist_steve.png"), + new TextureLocation("/skins/10.cyclist_alex.png"), + new TextureLocation("/skins/11.boxer_steve.png"), + new TextureLocation("/skins/12.boxer_alex.png"), + new TextureLocation("/skins/13.prisoner_steve.png"), + new TextureLocation("/skins/14.prisoner_alex.png"), + new TextureLocation("/skins/15.scottish_steve.png"), + new TextureLocation("/skins/16.scottish_alex.png"), + new TextureLocation("/skins/17.dev_steve.png"), + new TextureLocation("/skins/18.dev_alex.png"), + new TextureLocation("/skins/19.herobrine.png"), + new TextureLocation("/mob/enderman.png"), + new TextureLocation("/mob/skeleton.png"), + new TextureLocation("/mob/fire.png"), + new TextureLocation("/skins/20.barney.png"), + new TextureLocation("/skins/21.slime.png"), + new TextureLocation("/skins/22.noob.png"), + new TextureLocation("/skins/23.trump.png"), + new TextureLocation("/skins/24.notch.png"), + new TextureLocation("/skins/25.creeper.png"), + new TextureLocation("/skins/26.zombie.png"), + new TextureLocation("/skins/27.pig.png"), + new TextureLocation("/skins/28.squid.png"), + new TextureLocation("/skins/29.mooshroom.png"), + new TextureLocation("/mob/villager/villager.png"), + null, null, null, null, null + }; + + public static final TextureLocation[] defaultVanillaCapes = new TextureLocation[] { + null, + new TextureLocation("/skins/c01.minecon_2011.png"), + new TextureLocation("/skins/c02.minecon_2012.png"), + new TextureLocation("/skins/c03.minecon_2013.png"), + new TextureLocation("/skins/c04.minecon_2015.png"), + new TextureLocation("/skins/c05.minecon_2016.png"), + new TextureLocation("/skins/c06.microsoft_account.png"), + new TextureLocation("/skins/c07.mapmaker.png"), + new TextureLocation("/skins/c08.mojang_old.png"), + new TextureLocation("/skins/c09.mojang_new.png"), + new TextureLocation("/skins/c10.jira_mod.png"), + new TextureLocation("/skins/c11.mojang_very_old.png"), + new TextureLocation("/skins/c12.scrolls.png"), + new TextureLocation("/skins/c13.cobalt.png"), + new TextureLocation("/skins/c14.translator.png"), + new TextureLocation("/skins/c15.millionth_account.png"), + new TextureLocation("/skins/c16.prismarine.png"), + new TextureLocation("/skins/c17.snowman.png"), + new TextureLocation("/skins/c18.spade.png"), + new TextureLocation("/skins/c19.birthday.png"), + new TextureLocation("/skins/c20.db.png") + }; + + public static final HighPolySkin[] defaultHighPoly = new HighPolySkin[] { + null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, + null, null, null, + HighPolySkin.LONG_ARMS, HighPolySkin.WEIRD_CLIMBER_DUDE, HighPolySkin.LAXATIVE_DUDE, + HighPolySkin.BABY_CHARLES, HighPolySkin.BABY_WINSTON + }; + + public static final boolean[] defaultVanillaSkinClassicOrSlimVariants = new boolean[] { + false, true, + false, true, + false, true, + false, true, + false, true, + false, true, + false, true, + false, true, + false, true + }; + + private static final HashMap skinCookies = new HashMap<>(); + private static final HashMap skinGLUnits = new HashMap<>(); + private static final HashMap capeGLUnits = new HashMap<>(); + private static final HashMap skinGLTimeout = new HashMap<>(); + + private static long lastClean = 0l; + + public static void deleteOldSkins() { + long now = EaglerAdapter.steadyTimeMillis(); + if(now - lastClean > 60000l) { + lastClean = now; + Iterator> itr = skinGLTimeout.entrySet().iterator(); + while(itr.hasNext()) { + Entry ee = itr.next(); + if(now - ee.getValue() > 80000l) { + itr.remove(); + if(skinGLUnits.containsKey(ee.getKey())) { + Minecraft.getMinecraft().renderEngine.deleteTexture(skinGLUnits.remove(ee.getKey())); + } + if(capeGLUnits.containsKey(ee.getKey())) { + Minecraft.getMinecraft().renderEngine.deleteTexture(capeGLUnits.remove(ee.getKey())); + } + } + } + Iterator> itr2 = skinCookies.entrySet().iterator(); + while(itr2.hasNext()) { + Entry e = itr2.next(); + if(e.getValue().isDead) { + itr2.remove(); + } + } + } + } + + public static boolean bindSyncedSkin(EntityPlayer p) { + if(p instanceof EntityClientPlayerMP) { + return false; + }else if(p instanceof EntityOtherPlayerMP) { + EntityOtherPlayerMP pp = (EntityOtherPlayerMP) p; + if(pp.skinPacket != null) { + int type = ((int)pp.skinPacket[0] & 0xFF); + if(type != 4 && type >= 0 && type < EaglerProfile.SKIN_DATA_SIZE.length) { + if(!skinGLUnits.containsKey(pp)) { + byte[] skinToLoad = new byte[EaglerProfile.SKIN_DATA_SIZE[type]]; + System.arraycopy(pp.skinPacket, 1, skinToLoad, 0, skinToLoad.length); + int w, h; + + switch((int)pp.skinPacket[0] & 0xFF) { + default: + case 0: + w = 64; + h = 32; + break; + case 1: + case 5: + w = 64; + h = 64; + break; + } + + if(skinToLoad.length / 4 == w * h) { + skinGLUnits.put(pp, Minecraft.getMinecraft().renderEngine.setupTextureRaw(skinToLoad, w, h)); + } + } + skinGLTimeout.put(pp, EaglerAdapter.steadyTimeMillis()); + Integer i = skinGLUnits.get(pp); + if(i != null && i.intValue() > 0) { + Minecraft.getMinecraft().renderEngine.bindTexture(i.intValue()); + }else { + defaultVanillaSkins[0].bindTexture(); + } + }else { + int type2 = (int)pp.skinPacket[1] & 0xFF; + if(type2 < defaultVanillaSkins.length) { + TextureLocation loc = defaultVanillaSkins[type2]; + if(loc != null) { + loc.bindTexture(); + }else { + if(defaultHighPoly[type2] != null) { + defaultHighPoly[type2].fallbackTexture.bindTexture(); + return true; + }else { + return false; + } + } + } + } + return true; + }else { + requestSkin(pp); + } + return false; + }else { + return false; + } + } + + public static boolean bindSyncedCape(EntityPlayer p) { + EaglerAdapter.glMatrixMode(EaglerAdapter.GL_TEXTURE); + EaglerAdapter.glPushMatrix(); + EaglerAdapter.glMatrixMode(EaglerAdapter.GL_MODELVIEW); + if(p instanceof EntityClientPlayerMP) { + if(EaglerProfile.presetCapeId < 0) { + EaglerProfileCape cp = EaglerProfile.capes.get(EaglerProfile.customCapeId); + if(cp != null) { + Minecraft.getMinecraft().renderEngine.bindTexture(cp.glTex); + EaglerAdapter.glMatrixMode(EaglerAdapter.GL_TEXTURE); + EaglerAdapter.glScalef(2.0f, 1.0f, 1.0f); + EaglerAdapter.glMatrixMode(EaglerAdapter.GL_MODELVIEW); + return true; + }else { + return false; + } + }else { + if(EaglerProfile.presetCapeId < defaultVanillaCapes.length) { + TextureLocation loc = defaultVanillaCapes[EaglerProfile.presetCapeId]; + if(loc == null) { + return false; + }else { + loc.bindTexture(); + return true; + } + }else { + return false; + } + } + }else if(p instanceof EntityOtherPlayerMP) { + EntityOtherPlayerMP pp = (EntityOtherPlayerMP) p; + if(pp.skinPacket != null) { + int tp = ((int)pp.skinPacket[0] & 0xFF); + if(tp >= 0 && tp < EaglerProfile.SKIN_DATA_SIZE.length) { + int offset = 1 + EaglerProfile.SKIN_DATA_SIZE[tp]; + if(pp.skinPacket.length > offset + 1) { + int capeType = (int)pp.skinPacket[offset] & 0xFF; + if(capeType >= 0 && capeType < EaglerProfile.CAPE_DATA_SIZE.length) { + int len = EaglerProfile.CAPE_DATA_SIZE[capeType]; + if(pp.skinPacket.length > offset + len + 1) { + if(capeType != 2) { + if(!capeGLUnits.containsKey(pp)) { + byte[] dataToLoad = new byte[len]; + System.arraycopy(pp.skinPacket, offset + 2, dataToLoad, 0, len); + int w, h; + switch(capeType) { + case 0: + default: + w = 32; + h = 32; + break; + } + + if(dataToLoad.length / 4 == w * h) { + capeGLUnits.put(pp, Minecraft.getMinecraft().renderEngine.setupTextureRaw(dataToLoad, w, h)); + } + } + skinGLTimeout.put(pp, EaglerAdapter.steadyTimeMillis()); + Integer i = capeGLUnits.get(pp); + if(i != null && i.intValue() > 0) { + EaglerAdapter.glMatrixMode(EaglerAdapter.GL_TEXTURE); + EaglerAdapter.glScalef(2.0f, 1.0f, 1.0f); + EaglerAdapter.glMatrixMode(EaglerAdapter.GL_MODELVIEW); + Minecraft.getMinecraft().renderEngine.bindTexture(i.intValue()); + return true; + }else { + return false; + } + }else { + int preset = (int)pp.skinPacket[offset + 2] & 0xFF; + if(preset < defaultVanillaCapes.length) { + TextureLocation loc = defaultVanillaCapes[preset]; + if(loc == null) { + return false; + }else { + loc.bindTexture(); + return true; + } + }else { + return false; + } + } + } + } + + } + + } + }else { + requestSkin(pp); + } + } + return false; + } + + public static int getSkinLayerByte(EntityPlayer p) { + if(p instanceof EntityClientPlayerMP) { + return Minecraft.getMinecraft().gameSettings.getSkinLayers(); + }else if(p instanceof EntityOtherPlayerMP) { + EntityOtherPlayerMP pp = (EntityOtherPlayerMP) p; + if(pp.skinPacket != null) { + int tp = ((int)pp.skinPacket[0] & 0xFF); + if(tp >= 0 && tp < EaglerProfile.SKIN_DATA_SIZE.length) { + int offset = 1 + EaglerProfile.SKIN_DATA_SIZE[tp]; + if(pp.skinPacket.length > offset + 1) { + return (int)pp.skinPacket[offset + 1] & 0xFF; + } + } + } + } + return 0xFF; + } + + public static void updateSkinLayerByte(int skinFlags, byte[] pkt) { + if(pkt.length > 0) { + int tp = ((int)pkt[0] & 0xFF); + if(tp >= 0 && tp < EaglerProfile.SKIN_DATA_SIZE.length) { + int offset = 1 + EaglerProfile.SKIN_DATA_SIZE[tp]; + if(pkt.length > offset + 1) { + pkt[offset + 1] = (byte)skinFlags; + } + } + } + } + + private static void requestSkin(EntityOtherPlayerMP pp) { + if(!skinCookies.containsValue(pp)) { + int cookie = (int)(System.nanoTime() % 65536); + skinCookies.put(cookie, pp); + byte[] n = pp.username.getBytes(); + byte[] pkt = new byte[n.length + 2]; + System.arraycopy(n, 0, pkt, 2, n.length); + pkt[0] = (byte)(cookie & 0xFF); + pkt[1] = (byte)((cookie >> 8) & 0xFF); + Minecraft.getMinecraft().getNetHandler().addToSendQueue(new Packet250CustomPayload("EAG|FetchSkin", pkt)); + } + } + + public static void skinResponse(byte[] data) { + int cookie = ((int)data[0] & 0xFF) | (((int)data[1] & 0xFF) << 8); + if(skinCookies.containsKey(cookie) && (data.length > 3)) { + EntityOtherPlayerMP p = skinCookies.remove(cookie); + byte[] packet = new byte[data.length - 2]; + System.arraycopy(data, 2, packet, 0, packet.length); + p.skinPacket = packet; + } + } + + public static boolean isNewSkin(int id) { + return !(id == 0 || id == 2 || id == 4 || id == 6 || id == 8 || id == 10 || id == 12 || id == 14 || id == 18 || id == 28) && !isHighPoly(id); + } + + public static boolean isAlexSkin(int id) { + return id < defaultVanillaSkinClassicOrSlimVariants.length && defaultVanillaSkinClassicOrSlimVariants[id]; + } + + public static boolean isStandardModel(int id) { + return !isZombieModel(id) && !(id == 19 || id == 20 || id == 21 || id == 32 || id == 33 || id == 34) && !isHighPoly(id); + } + + public static boolean isZombieModel(int id) { + return id == 18 || id == 28; + } + + public static boolean isHighPoly(int id) { + return !(defaultVanillaSkins.length > id && id >= 0) ? false : defaultHighPoly[id] != null; + } + + public static boolean isPlayerNewSkin(EntityPlayer p) { + if(p instanceof EntityClientPlayerMP) { + if(EaglerProfile.presetSkinId <= -1) { + int type = EaglerProfile.getSkinSize(EaglerProfile.skins.get(EaglerProfile.customSkinId).data.length); + return (type == 1 || type == 3); + }else { + return isNewSkin(EaglerProfile.presetSkinId); + } + }else if(p instanceof EntityOtherPlayerMP) { + EntityOtherPlayerMP pp = (EntityOtherPlayerMP) p; + if(pp.skinPacket != null) { + if(pp.skinPacket[0] != (byte)4) { + return (pp.skinPacket[0] == (byte)1) || (pp.skinPacket[0] == (byte)3) || (pp.skinPacket[0] == (byte)5) || (pp.skinPacket[0] == (byte)6); + }else { + return isNewSkin((int)pp.skinPacket[1] & 0xFF); + } + } + } + return false; + } + + public static boolean isPlayerNewSkinSlim(EntityPlayer p) { + if(p instanceof EntityClientPlayerMP) { + if(EaglerProfile.presetSkinId == -1) { + return EaglerProfile.skins.get(EaglerProfile.customSkinId).slim; + }else { + return isAlexSkin(EaglerProfile.presetSkinId); + } + }else if(p instanceof EntityOtherPlayerMP) { + EntityOtherPlayerMP pp = (EntityOtherPlayerMP) p; + if(pp.skinPacket != null) { + if(pp.skinPacket[0] != (byte)4) { + return (pp.skinPacket[0] == (byte)5) || (pp.skinPacket[0] == (byte)6); + }else { + return isAlexSkin((int)pp.skinPacket[1] & 0xFF); + } + } + } + return false; + } + + public static boolean isPlayerHighPoly(EntityPlayer p) { + if(p instanceof EntityClientPlayerMP) { + if(EaglerProfile.presetSkinId == -1) { + return false; + }else { + return isHighPoly(EaglerProfile.presetSkinId); + } + }else if(p instanceof EntityOtherPlayerMP) { + EntityOtherPlayerMP pp = (EntityOtherPlayerMP) p; + if(pp.skinPacket != null) { + if(pp.skinPacket[0] != (byte)4) { + return false; + }else { + return isHighPoly((int)pp.skinPacket[1] & 0xFF); + } + } + } + return false; + } + + public static boolean isPlayerStandard(EntityPlayer p) { + if(p instanceof EntityClientPlayerMP) { + if(EaglerProfile.presetSkinId == -1) { + return true; + }else { + return isStandardModel(EaglerProfile.presetSkinId); + } + }else if(p instanceof EntityOtherPlayerMP) { + EntityOtherPlayerMP pp = (EntityOtherPlayerMP) p; + if(pp.skinPacket != null) { + if(pp.skinPacket[0] != (byte)4) { + return true; + }else { + return isStandardModel((int)pp.skinPacket[1] & 0xFF); + } + } + } + return true; + } + + public static int getPlayerRenderer(EntityPlayer p) { + if(p instanceof EntityClientPlayerMP) { + if(EaglerProfile.presetSkinId == -1) { + return 0; + }else { + return EaglerProfile.presetSkinId; + } + }else if(p instanceof EntityOtherPlayerMP) { + EntityOtherPlayerMP pp = (EntityOtherPlayerMP) p; + if(pp.skinPacket != null) { + if(pp.skinPacket[0] != (byte)4) { + return 0; + }else { + if(((int)pp.skinPacket[1] & 0xFF) >= DefaultSkinRenderer.defaultVanillaSkins.length) { + return 0; + }else { + return (int)pp.skinPacket[1] & 0xFF; + } + } + } + } + return 0; + } + + public static ModelBiped oldSkinRenderer = null; + public static ModelBipedNewSkins newSkinRenderer = null; + public static ModelBipedNewSkins newSkinRendererSlim = null; + public static ModelZombie zombieRenderer = null; + public static ModelVillager villagerRenderer = null; + public static ModelEnderman endermanRenderer = null; + public static ModelBlaze blazeRenderer = null; + public static ModelSkeleton skeletonRenderer = null; + + public static void renderPlayerPreview(int x, int y, int mx, int my, int id2) { + boolean capeMode = (id2 & 0x10000) == 0x10000; + if(capeMode) { + id2 -= 0x10000; + } + int id = id2 - EaglerProfile.skins.size(); + boolean highPoly = isHighPoly(id); + + EaglerAdapter.glEnable(EaglerAdapter.GL_TEXTURE_2D); + EaglerAdapter.glDisable(EaglerAdapter.GL_BLEND); + if(highPoly) { + EaglerAdapter.glEnable(EaglerAdapter.GL_CULL_FACE); + }else { + EaglerAdapter.glDisable(EaglerAdapter.GL_CULL_FACE); + } + EaglerAdapter.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + EaglerAdapter.glPushMatrix(); + EaglerAdapter.glTranslatef((float) x, (float) (y - 80), 100.0F); + EaglerAdapter.glScalef(50.0f, 50.0f, 50.0f); + EaglerAdapter.glRotatef(180.0f, 1.0f, 0.0f, 0.0f); + EaglerAdapter.glEnable(EaglerAdapter.GL_RESCALE_NORMAL); + EaglerAdapter.glScalef(1.0F, -1.0F, 1.0F); + RenderHelper.enableGUIStandardItemLighting(); + EaglerAdapter.glTranslatef(0.0F, 1.0F, 0.0F); + if(capeMode) { + EaglerAdapter.glRotatef(140.0f, 0.0f, 1.0f, 0.0f); + mx = x - (x - mx) - 20; + EaglerAdapter.glRotatef(((y - my) * -0.02f), 1.0f, 0.0f, 0.0f); + }else { + EaglerAdapter.glRotatef(((y - my) * -0.06f), 1.0f, 0.0f, 0.0f); + } + EaglerAdapter.glRotatef(((x - mx) * 0.06f), 0.0f, 1.0f, 0.0f); + EaglerAdapter.glTranslatef(0.0F, -1.0F, 0.0F); + + if(highPoly) { + EaglerAdapter.flipLightMatrix(); + EaglerAdapter.glPushMatrix(); + EaglerAdapter.glRotatef(180.0f, 0.0f, 0.0f, 1.0f); + EaglerAdapter.glTranslatef(0.0f, -1.5f, 0.0f); + EaglerAdapter.glScalef(HighPolySkin.highPolyScale, HighPolySkin.highPolyScale, HighPolySkin.highPolyScale); + HighPolySkin msh = defaultHighPoly[id]; + msh.texture.bindTexture(); + + if(msh.bodyModel != null) { + EaglerAdapter.drawHighPoly(msh.bodyModel.getModel()); + } + + if(msh.headModel != null) { + EaglerAdapter.drawHighPoly(msh.headModel.getModel()); + } + + if(msh.limbsModel != null && msh.limbsModel.length > 0) { + for(int i = 0; i < msh.limbsModel.length; ++i) { + float offset = 0.0f; + if(msh.limbsOffset != null) { + if(msh.limbsOffset.length == 1) { + offset = msh.limbsOffset[0]; + }else { + offset = msh.limbsOffset[i]; + } + } + if(offset != 0.0f || msh.limbsInitialRotation != 0.0f) { + EaglerAdapter.glPushMatrix(); + if(offset != 0.0f) { + EaglerAdapter.glTranslatef(0.0f, offset, 0.0f); + } + if(msh.limbsInitialRotation != 0.0f) { + EaglerAdapter.glRotatef(msh.limbsInitialRotation, 1.0f, 0.0f, 0.0f); + } + } + + EaglerAdapter.drawHighPoly(msh.limbsModel[i].getModel()); + + if(offset != 0.0f || msh.limbsInitialRotation != 0.0f) { + EaglerAdapter.glPopMatrix(); + } + } + } + + EaglerAdapter.glPopMatrix(); + EaglerAdapter.flipLightMatrix(); + }else { + if(id < 0) { + Minecraft.getMinecraft().renderEngine.bindTexture(EaglerProfile.skins.get(id2).glTex); + }else { + defaultVanillaSkins[id].bindTexture(); + } + + boolean gonnaShowCape = false; + if(isStandardModel(id) || id < 0) { + if(oldSkinRenderer == null) oldSkinRenderer = new ModelBiped(0.0F, 0.0F, 64, 32); + if(newSkinRenderer == null) newSkinRenderer = new ModelBipedNewSkins(0.0F, false); + if(newSkinRendererSlim == null) newSkinRendererSlim = new ModelBipedNewSkins(0.0F, true); + oldSkinRenderer.isChild = false; + newSkinRenderer.isChild = false; + newSkinRendererSlim.isChild = false; + boolean isNew = isNewSkin(id); + if(id < 0) { + int type = EaglerProfile.getSkinSize(EaglerProfile.skins.get(id2).data.length); + isNew = (type == 1 || type == 3); + } + if(isNew) { + if((id < 0 && EaglerProfile.skins.get(id2).slim) || (id >= 0 && isAlexSkin(id))) { + newSkinRendererSlim.blockTransparentSkin = true; + newSkinRendererSlim.render(null, 0.0f, 0.0f, (float)(EaglerAdapter.steadyTimeMillis() % 100000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625F); + newSkinRendererSlim.blockTransparentSkin = false; + }else { + newSkinRenderer.blockTransparentSkin = true; + newSkinRenderer.render(null, 0.0f, 0.0f, (float)(EaglerAdapter.steadyTimeMillis() % 100000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625F); + newSkinRenderer.blockTransparentSkin = false; + } + }else { + oldSkinRenderer.blockTransparentSkin = true; + oldSkinRenderer.render(null, 0.0f, 0.0f, (float)(EaglerAdapter.steadyTimeMillis() % 100000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625F); + oldSkinRenderer.blockTransparentSkin = false; + } + gonnaShowCape = capeMode; + }else if(isZombieModel(id)) { + if(zombieRenderer == null) zombieRenderer = new ModelZombie(0.0F, true); + zombieRenderer.isChild = false; + zombieRenderer.render(null, 0.0f, 0.0f, (float)(EaglerAdapter.steadyTimeMillis() % 100000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625F); + gonnaShowCape = capeMode; + }else if(id == 32) { + if(villagerRenderer == null) villagerRenderer = new ModelVillager(0.0F); + villagerRenderer.isChild = false; + villagerRenderer.render(null, 0.0f, 0.0f, (float)(EaglerAdapter.steadyTimeMillis() % 100000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625F); + }else if(id == 19) { + if(endermanRenderer == null) endermanRenderer = new ModelEnderman(); + endermanRenderer.isChild = false; + endermanRenderer.render(null, 0.0f, 0.0f, (float)(EaglerAdapter.steadyTimeMillis() % 100000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625F); + EaglerAdapter.glColor4f(1.4f, 1.4f, 1.4f, 1.0f); + //EaglerAdapter.glEnable(EaglerAdapter.GL_BLEND); + //EaglerAdapter.glDisable(EaglerAdapter.GL_ALPHA_TEST); + //EaglerAdapter.glBlendFunc(EaglerAdapter.GL_ONE, EaglerAdapter.GL_ONE); + EaglerAdapter.glDisable(EaglerAdapter.GL_LIGHTING); + EaglerAdapter.glEnable(EaglerAdapter.GL_TEXTURE_2D); + EaglerAdapter.glDisable(EaglerAdapter.GL_DEPTH_TEST); + RenderEnderman.tex_eyes.bindTexture(); + endermanRenderer.render(null, 0.0f, 0.0f, (float)(EaglerAdapter.steadyTimeMillis() % 100000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625F); + EaglerAdapter.glBlendFunc(EaglerAdapter.GL_SRC_ALPHA, EaglerAdapter.GL_ONE_MINUS_SRC_ALPHA); + EaglerAdapter.glEnable(EaglerAdapter.GL_ALPHA_TEST); + EaglerAdapter.glEnable(EaglerAdapter.GL_DEPTH_TEST); + EaglerAdapter.glDisable(EaglerAdapter.GL_TEXTURE_2D); + EaglerAdapter.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + }else if(id == 20) { + if(skeletonRenderer == null) skeletonRenderer = new ModelSkeleton(0.0F); + skeletonRenderer.isChild = false; + skeletonRenderer.render(null, 0.0f, 0.0f, (float)(EaglerAdapter.steadyTimeMillis() % 100000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625F); + }else if(id == 21) { + if(blazeRenderer == null) blazeRenderer = new ModelBlaze(); + blazeRenderer.isChild = false; + EaglerAdapter.glColor4f(1.5f, 1.5f, 1.5f, 1.0f); + blazeRenderer.render(null, 0.0f, 0.0f, (float)(EaglerAdapter.steadyTimeMillis() % 100000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625F); + } + if(gonnaShowCape && !(EaglerProfile.presetCapeId >= 0 && defaultVanillaCapes[EaglerProfile.presetCapeId] == null)) { + EaglerAdapter.glPushMatrix(); + EaglerAdapter.glTranslatef(0.0F, 0.0F, 0.150F); + EaglerAdapter.glRotatef(180.0F, 0.0F, 1.0F, 0.0F); + EaglerAdapter.glRotatef(-6.0F, 1.0F, 0.0F, 0.0F); + + if(EaglerProfile.presetCapeId < 0) { + Minecraft.getMinecraft().renderEngine.bindTexture(EaglerProfile.capes.get(EaglerProfile.customCapeId).glTex); + EaglerAdapter.glMatrixMode(EaglerAdapter.GL_TEXTURE); + EaglerAdapter.glPushMatrix(); + EaglerAdapter.glScalef(2.0f, 1.0f, 1.0f); + EaglerAdapter.glMatrixMode(EaglerAdapter.GL_MODELVIEW); + }else { + defaultVanillaCapes[EaglerProfile.presetCapeId].bindTexture(); + } + + if(oldSkinRenderer == null) oldSkinRenderer = new ModelBiped(0.0F, 0.0F, 64, 32); + oldSkinRenderer.bipedCloak.render(0.0625F); + + if(EaglerProfile.presetCapeId < 0) { + EaglerAdapter.glMatrixMode(EaglerAdapter.GL_TEXTURE); + EaglerAdapter.glPopMatrix(); + EaglerAdapter.glMatrixMode(EaglerAdapter.GL_MODELVIEW); + } + + EaglerAdapter.glPopMatrix(); + } + } + + EaglerAdapter.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + + EaglerAdapter.glPopMatrix(); + EaglerAdapter.glDisable(EaglerAdapter.GL_RESCALE_NORMAL); + OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit); + EaglerAdapter.glDisable(EaglerAdapter.GL_TEXTURE_2D); + OpenGlHelper.setActiveTexture(OpenGlHelper.defaultTexUnit); + EaglerAdapter.glDisable(EaglerAdapter.GL_LIGHTING); + } + + public static void renderAlexOrSteve(int x, int y, int mx, int my, boolean alex) { + ModelBipedNewSkins bp; + if(alex) { + if(newSkinRendererSlim == null) { + newSkinRendererSlim = new ModelBipedNewSkins(0.0F, true); + } + bp = newSkinRendererSlim; + }else { + if(newSkinRenderer == null) { + newSkinRenderer = new ModelBipedNewSkins(0.0F, false); + } + bp = newSkinRenderer; + } + + EaglerAdapter.glEnable(EaglerAdapter.GL_TEXTURE_2D); + EaglerAdapter.glDisable(EaglerAdapter.GL_BLEND); + EaglerAdapter.glDisable(EaglerAdapter.GL_CULL_FACE); + EaglerAdapter.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + EaglerAdapter.glPushMatrix(); + EaglerAdapter.glTranslatef((float) x, (float) (y - 80), 100.0F); + EaglerAdapter.glScalef(50.0f, 50.0f, 50.0f); + EaglerAdapter.glRotatef(180.0f, 1.0f, 0.0f, 0.0f); + EaglerAdapter.glEnable(EaglerAdapter.GL_RESCALE_NORMAL); + EaglerAdapter.glScalef(1.0F, -1.0F, 1.0F); + RenderHelper.enableGUIStandardItemLighting(); + EaglerAdapter.glTranslatef(0.0F, 1.0F, 0.0F); + EaglerAdapter.glRotatef(((y - my) * -0.06f), 1.0f, 0.0f, 0.0f); + EaglerAdapter.glRotatef(((x - mx) * 0.06f), 0.0f, 1.0f, 0.0f); + EaglerAdapter.glTranslatef(0.0F, -1.0F, 0.0F); + + bp.isChild = false; + bp.render(null, 0.0f, 0.0f, (float)(EaglerAdapter.steadyTimeMillis() % 100000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625F); + + EaglerAdapter.glPopMatrix(); + EaglerAdapter.glDisable(EaglerAdapter.GL_RESCALE_NORMAL); + OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit); + EaglerAdapter.glDisable(EaglerAdapter.GL_TEXTURE_2D); + OpenGlHelper.setActiveTexture(OpenGlHelper.defaultTexUnit); + EaglerAdapter.glDisable(EaglerAdapter.GL_LIGHTING); + } + + public static boolean isPlayerPreviewNew(int id2) { + int id = id2 - EaglerProfile.skins.size(); + if(id < 0) { + return EaglerProfile.skins.get(id2).data.length == EaglerProfile.SKIN_DATA_SIZE[1] || EaglerProfile.skins.get(id2).data.length == EaglerProfile.SKIN_DATA_SIZE[3]; + }else { + return false; + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/EPK2Compiler.java b/src/main/java/net/lax1dude/eaglercraft/EPK2Compiler.java new file mode 100644 index 0000000..2316993 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/EPK2Compiler.java @@ -0,0 +1,151 @@ +package net.lax1dude.eaglercraft; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.util.Date; + +import com.jcraft.jzlib.CRC32; + +public class EPK2Compiler { + + private final ByteArrayOutputStream os; + private final CRC32 checkSum = new CRC32(); + private int lengthIntegerOffset = 0; + private int totalFileCount = 0; + + public EPK2Compiler() { + String name = "__TEXTUREPACK__"; + String owner = "__INTERNAL__"; + String type = "epk/resources"; + os = new ByteArrayOutputStream(0x200000); + try { + + os.write(new byte[]{(byte)69,(byte)65,(byte)71,(byte)80,(byte)75,(byte)71,(byte)36,(byte)36}); // EAGPKG$$ + os.write(new byte[]{(byte)6,(byte)118,(byte)101,(byte)114,(byte)50,(byte)46,(byte)48}); // 6 + ver2.0 + Date d = new Date(); + + byte[] filename = (name + ".epk").getBytes(StandardCharsets.UTF_8); + os.write(filename.length); + os.write(filename); + + byte[] comment = ("\n\n # Eagler EPK v2.0\n\n") + .getBytes(StandardCharsets.UTF_8); + + os.write((comment.length >> 8) & 255); + os.write(comment.length & 255); + os.write(comment); + + writeLong(d.getTime(), os); + + lengthIntegerOffset = os.size(); + os.write(new byte[]{(byte)255,(byte)255,(byte)255,(byte)255}); // this will be replaced with the file count + + os.write('0'); // compression type: none + + os.write(new byte[]{(byte)72,(byte)69,(byte)65,(byte)68}); // HEAD + os.write(new byte[]{(byte)9,(byte)102,(byte)105,(byte)108,(byte)101,(byte)45,(byte)116,(byte)121, + (byte)112,(byte)101}); // 9 + file-type + + byte[] typeBytes = type.getBytes(StandardCharsets.UTF_8); + writeInt(typeBytes.length, os); + os.write(typeBytes); // write type + os.write('>'); + + ++totalFileCount; + + os.write(new byte[]{(byte)72,(byte)69,(byte)65,(byte)68}); // HEAD + os.write(new byte[]{(byte)10,(byte)119,(byte)111,(byte)114,(byte)108,(byte)100,(byte)45,(byte)110, + (byte)97,(byte)109,(byte)101}); // 10 + name + + byte[] nameBytes = name.getBytes(StandardCharsets.UTF_8); + writeInt(nameBytes.length, os); + os.write(nameBytes); // write name + os.write('>'); + + ++totalFileCount; + + os.write(new byte[]{(byte)72,(byte)69,(byte)65,(byte)68}); // HEAD + os.write(new byte[]{(byte)11,(byte)119,(byte)111,(byte)114,(byte)108,(byte)100,(byte)45,(byte)111, + (byte)119,(byte)110,(byte)101,(byte)114}); // 11 + owner + + byte[] ownerBytes = owner.getBytes(StandardCharsets.UTF_8); + writeInt(ownerBytes.length, os); + os.write(ownerBytes); // write owner + os.write('>'); + + ++totalFileCount; + + }catch(IOException ex) { + throw new RuntimeException("This happened somehow", ex); + } + } + + public void append(String name, byte[] dat) { + try { + + checkSum.reset(); + checkSum.update(dat, 0, dat.length); + long sum = checkSum.getValue(); + + os.write(new byte[]{(byte)70,(byte)73,(byte)76,(byte)69}); // FILE + + byte[] nameBytes = name.getBytes(StandardCharsets.UTF_8); + os.write(nameBytes.length); + os.write(nameBytes); + + writeInt(dat.length + 5, os); + writeInt((int)sum, os); + + os.write(dat); + + os.write(':'); + os.write('>'); + + ++totalFileCount; + + }catch(IOException ex) { + throw new RuntimeException("This happened somehow", ex); + } + } + + public byte[] complete() { + try { + + os.write(new byte[]{(byte)69,(byte)78,(byte)68,(byte)36}); // END$ + os.write(new byte[]{(byte)58,(byte)58,(byte)58,(byte)89,(byte)69,(byte)69,(byte)58,(byte)62}); // :::YEE:> + + byte[] ret = os.toByteArray(); + + ret[lengthIntegerOffset] = (byte)((totalFileCount >> 24) & 0xFF); + ret[lengthIntegerOffset + 1] = (byte)((totalFileCount >> 16) & 0xFF); + ret[lengthIntegerOffset + 2] = (byte)((totalFileCount >> 8) & 0xFF); + ret[lengthIntegerOffset + 3] = (byte)(totalFileCount & 0xFF); + + return ret; + + }catch(IOException ex) { + throw new RuntimeException("This happened somehow", ex); + } + } + + public static void writeInt(int i, OutputStream os) throws IOException { + os.write((i >> 24) & 0xFF); + os.write((i >> 16) & 0xFF); + os.write((i >> 8) & 0xFF); + os.write(i & 0xFF); + } + + public static void writeLong(long i, OutputStream os) throws IOException { + os.write((int)((i >> 56) & 0xFF)); + os.write((int)((i >> 48) & 0xFF)); + os.write((int)((i >> 40) & 0xFF)); + os.write((int)((i >> 32) & 0xFF)); + os.write((int)((i >> 24) & 0xFF)); + os.write((int)((i >> 16) & 0xFF)); + os.write((int)((i >> 8) & 0xFF)); + os.write((int)(i & 0xFF)); + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/EPKDecompiler.java b/src/main/java/net/lax1dude/eaglercraft/EPKDecompiler.java new file mode 100644 index 0000000..3e63190 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/EPKDecompiler.java @@ -0,0 +1,216 @@ +package net.lax1dude.eaglercraft; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; + +import com.jcraft.jzlib.CRC32; +import com.jcraft.jzlib.GZIPInputStream; +import com.jcraft.jzlib.InflaterInputStream; + +public class EPKDecompiler { + + public static class FileEntry { + public final String type; + public final String name; + public final byte[] data; + protected FileEntry(String type, String name, byte[] data) { + this.type = type; + this.name = name; + this.data = data; + } + } + + private EaglerInputStream in2; + private DataInputStream in; + private InputStream zis; + private SHA1Digest dg; + private CRC32 crc32; + private int numFiles; + private boolean isFinished = false; + private boolean isOldFormat = false; + + public EPKDecompiler(byte[] data) throws IOException { + in2 = new EaglerInputStream(data); + + byte[] header = new byte[8]; + in2.read(header); + + if(Arrays.equals(header, new byte[]{(byte)69,(byte)65,(byte)71,(byte)80,(byte)75,(byte)71,(byte)36,(byte)36})) { + byte[] endCode = new byte[] { (byte)':', (byte)':', (byte)':', (byte)'Y', + (byte)'E', (byte)'E', (byte)':', (byte)'>' }; + for(int i = 0; i < 8; ++i) { + if(data[data.length - 8 + i] != endCode[i]) { + throw new IOException("EPK file is missing EOF code (:::YEE:>)"); + } + } + in2 = new EaglerInputStream(data, 8, data.length - 16); + initNew(); + }else if(Arrays.equals(header, new byte[]{(byte)69,(byte)65,(byte)71,(byte)80,(byte)75,(byte)71,(byte)33,(byte)33})) { + initOld(); + } + + } + + public boolean isOld() { + return isOldFormat; + } + + public FileEntry readFile() throws IOException { + if(!isOldFormat) { + return readFileNew(); + }else { + return readFileOld(); + } + } + + private void initNew() throws IOException { + InputStream is = in2; + + String vers = readASCII(is); + if(!vers.startsWith("ver2.")) { + throw new IOException("Unknown or invalid EPK version: " + vers); + } + + is.skip(is.read()); // skip filename + is.skip(loadShort(is)); // skip comment + is.skip(8); // skip millis date + + numFiles = loadInt(is); + + char compressionType = (char)is.read(); + + switch(compressionType) { + case 'G': + zis = new GZIPInputStream(is); + break; + case 'Z': + zis = new InflaterInputStream(is); + break; + case '0': + zis = is; + break; + default: + throw new IOException("Invalid or unsupported EPK compression: " + compressionType); + } + + crc32 = new CRC32(); + + } + + private FileEntry readFileNew() throws IOException { + if(isFinished) { + return null; + } + + byte[] typeBytes = new byte[4]; + zis.read(typeBytes); + String type = readASCII(typeBytes); + + if(numFiles == 0) { + if(!"END$".equals(type)) { + throw new IOException("EPK file is missing END code (END$)"); + } + isFinished = true; + return null; + }else { + if("END$".equals(type)) { + throw new IOException("Unexpected END when there are still " + numFiles + " files remaining"); + }else { + String name = readASCII(zis); + int len = loadInt(zis); + byte[] data; + + if("FILE".equals(type)) { + if(len < 5) { + throw new IOException("File '" + name + "' is incomplete (no crc)"); + } + + int loadedCrc = loadInt(zis); + + data = new byte[len - 5]; + zis.read(data); + + crc32.reset(); + crc32.update(data, 0, data.length); + if((int)crc32.getValue() != loadedCrc) { + throw new IOException("File '" + name + "' has an invalid checksum"); + } + + if(zis.read() != ':') { + throw new IOException("File '" + name + "' is incomplete"); + } + }else { + data = new byte[len]; + zis.read(data); + } + + if(zis.read() != '>') { + throw new IOException("Object '" + name + "' is incomplete"); + } + + --numFiles; + return new FileEntry(type, name, data); + } + } + } + + private static final int loadShort(InputStream is) throws IOException { + return (is.read() << 8) | is.read(); + } + + private static final int loadInt(InputStream is) throws IOException { + return (is.read() << 24) | (is.read() << 16) | (is.read() << 8) | is.read(); + } + + public static final String readASCII(byte[] bytesIn) throws IOException { + char[] charIn = new char[bytesIn.length]; + for(int i = 0; i < bytesIn.length; ++i) { + charIn[i] = (char)((int)bytesIn[i] & 0xFF); + } + return new String(charIn); + } + + private static final String readASCII(InputStream bytesIn) throws IOException { + int len = bytesIn.read(); + char[] charIn = new char[len]; + for(int i = 0; i < len; ++i) { + charIn[i] = (char)(bytesIn.read() & 0xFF); + } + return new String(charIn); + } + + private void initOld() throws IOException { + isOldFormat = true; + dg = new SHA1Digest(); + in = new DataInputStream(in2); + in.readUTF(); + in = new DataInputStream(new InflaterInputStream(in2)); + } + + private FileEntry readFileOld() throws IOException { + if(isFinished) { + return null; + } + String s = in.readUTF(); + if(s.equals(" end")) { + isFinished = true; + return null; + }else if(!s.equals("")) { + throw new IOException("invalid epk file"); + } + String path = in.readUTF(); + byte[] digest = new byte[20]; + byte[] digest2 = new byte[20]; + in.read(digest); + int len = in.readInt(); + byte[] file = new byte[len]; + in.read(file); + dg.update(file, 0, len); dg.doFinal(digest2, 0); + if(!Arrays.equals(digest, digest2)) throw new IOException("invalid file hash for "+path); + if(!"".equals(in.readUTF())) throw new IOException("invalid epk file"); + return new FileEntry("FILE", path, file); + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/EaglerAdapter.java b/src/main/java/net/lax1dude/eaglercraft/EaglerAdapter.java new file mode 100644 index 0000000..440c401 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/EaglerAdapter.java @@ -0,0 +1,11 @@ +package net.lax1dude.eaglercraft; + +import net.lax1dude.eaglercraft.glemu.EaglerAdapterGL30; + +public class EaglerAdapter extends EaglerAdapterGL30 { + + /* + * YOU EAGLR! + */ + +} \ No newline at end of file diff --git a/src/main/java/net/lax1dude/eaglercraft/EaglerImage.java b/src/main/java/net/lax1dude/eaglercraft/EaglerImage.java new file mode 100644 index 0000000..176c2c0 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/EaglerImage.java @@ -0,0 +1,44 @@ +package net.lax1dude.eaglercraft; + +public class EaglerImage { + + public final int[] data; + public final int w; + public final int h; + public final boolean alpha; + + public EaglerImage(int pw, int ph, boolean palpha) { + this.w = pw; + this.h = ph; + this.alpha = palpha; + this.data = new int[pw * ph]; + } + + public EaglerImage(int[] pdata, int pw, int ph, boolean palpha) { + if(pdata.length != pw*ph) { + throw new IllegalArgumentException("array size does not equal image size"); + } + this.w = pw; + this.h = ph; + this.alpha = palpha; + if(!palpha) { + for(int i = 0; i < pdata.length; ++i) { + pdata[i] = pdata[i] | 0xFF000000; + } + } + this.data = pdata; + } + + public static final EaglerImage loadImage(byte[] file) { + return EaglerAdapter.loadPNG(file); + } + + public EaglerImage getSubImage(int x, int y, int pw, int ph) { + int[] img = new int[pw * ph]; + for(int i = 0; i < ph; ++i) { + System.arraycopy(data, (i + y) * this.w + x, img, i * pw, pw); + } + return new EaglerImage(img, pw, ph, alpha); + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/EaglerInputStream.java b/src/main/java/net/lax1dude/eaglercraft/EaglerInputStream.java new file mode 100644 index 0000000..a20a316 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/EaglerInputStream.java @@ -0,0 +1,167 @@ +package net.lax1dude.eaglercraft; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Arrays; + +public class EaglerInputStream extends InputStream { + + protected byte buf[]; + protected int pos; + protected int mark = 0; + protected int count; + + public EaglerInputStream(byte[] buf) { + this.buf = buf; + this.pos = 0; + this.count = buf.length; + } + + public EaglerInputStream(byte buf[], int offset, int length) { + this.buf = buf; + this.pos = offset; + this.count = Math.min(offset + length, buf.length); + this.mark = offset; + } + + public int read() { + return (pos < count) ? (buf[pos++] & 0xff) : -1; + } + + public int read(byte b[], int off, int len) { + if (pos >= count) { + return -1; + } + + int avail = count - pos; + if (len > avail) { + len = avail; + } + if (len <= 0) { + return 0; + } + System.arraycopy(buf, pos, b, off, len); + pos += len; + return len; + } + + public byte[] readAllBytes() { + byte[] result = Arrays.copyOfRange(buf, pos, count); + pos = count; + return result; + } + + public int readNBytes(byte[] b, int off, int len) { + int n = read(b, off, len); + return n == -1 ? 0 : n; + } + + public long transferTo(OutputStream out) throws IOException { + int len = count - pos; + out.write(buf, pos, len); + pos = count; + return len; + } + + public static byte[] inputStreamToBytesQuiet(InputStream is) { + if (is == null) { + return null; + } + try { + return inputStreamToBytes(is); + } catch (IOException ex) { + return null; + } + } + + public long skip(long n) { + long k = count - pos; + if (n < k) { + k = n < 0 ? 0 : n; + } + + pos += k; + return k; + } + + public int available() { + return count - pos; + } + + public boolean markSupported() { + return true; + } + + public void mark(int readAheadLimit) { + mark = pos; + } + + public void reset() { + pos = mark; + } + + public void close() throws IOException { + } + + public static byte[] inputStreamToBytes(InputStream is) throws IOException { + try { + if (is instanceof EaglerInputStream) { + return ((EaglerInputStream) is).getAsArray(); + } else if (is instanceof ByteArrayInputStream) { + byte[] ret = new byte[is.available()]; + is.read(ret); + return ret; + } else { + ByteArrayOutputStream os = new ByteArrayOutputStream(1024); + byte[] buf = new byte[1024]; + int i; + while ((i = is.read(buf)) != -1) { + os.write(buf, 0, i); + } + return os.toByteArray(); + } + }finally { + is.close(); + } + } + + public static byte[] inputStreamToBytesNoClose(InputStream is) throws IOException { + ByteArrayOutputStream os = new ByteArrayOutputStream(1024); + byte[] buf = new byte[1024]; + int i; + while ((i = is.read(buf)) != -1) { + os.write(buf, 0, i); + } + return os.toByteArray(); + } + + public byte[] getAsArray() { + if (pos == 0 && count == buf.length) { + return buf; + } else { + byte[] ret = new byte[count]; + System.arraycopy(buf, pos, ret, 0, count); + return ret; + } + } + + public boolean canUseArrayDirectly() { + return pos == 0 && count == buf.length; + } + + public int getPosition() { + return pos; + } + + public int getMark() { + return mark; + } + + public int getCount() { + return count; + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/EaglerMisc.java b/src/main/java/net/lax1dude/eaglercraft/EaglerMisc.java new file mode 100644 index 0000000..25cfc6a --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/EaglerMisc.java @@ -0,0 +1,28 @@ +package net.lax1dude.eaglercraft; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.jcraft.jzlib.InflaterInputStream; + +public class EaglerMisc { + + public static byte[] uncompress(byte[] input) throws IOException { + return EaglerInputStream.inputStreamToBytes(new InflaterInputStream(new EaglerInputStream(input))); + } + + public static String bytesToString(byte[] bb) { + if (bb == null) + return ""; + return new String(bb, StandardCharsets.UTF_8); + } + + public static String[] bytesToLines(byte[] bb) { + String contents = bytesToString(bb); + if (contents.isEmpty()) { + return new String[0]; + } else { + return contents.replace("\r\n", "\n").split("[\r\n]"); + } + } +} diff --git a/src/main/java/net/lax1dude/eaglercraft/EaglerProfile.java b/src/main/java/net/lax1dude/eaglercraft/EaglerProfile.java new file mode 100644 index 0000000..e64fc39 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/EaglerProfile.java @@ -0,0 +1,254 @@ +package net.lax1dude.eaglercraft; + +import java.util.ArrayList; + +import net.minecraft.src.Minecraft; +import net.minecraft.src.NBTBase; +import net.minecraft.src.NBTTagByteArray; +import net.minecraft.src.NBTTagCompound; + +public class EaglerProfile { + + public static class EaglerProfileSkin { + public String name; + public byte[] data; + public boolean slim; + public int glTex; + public EaglerProfileSkin(String name, byte[] data, boolean slim, int glTex) { + this.name = name; + this.data = data; + this.slim = slim; + this.glTex = glTex; + } + } + + public static class EaglerProfileCape { + public String name; + public byte[] data; + public int glTex; + public EaglerProfileCape(String name, byte[] data, int glTex) { + this.name = name; + this.data = data; + this.glTex = glTex; + } + } + + public static String username; + public static int presetSkinId; + public static int customSkinId; + public static int presetCapeId; + public static int customCapeId; + + public static int newSkinNotificationIndex = 0; + + public static final int[] SKIN_DATA_SIZE = new int[] { 64*32*4, 64*64*4, -9, -9, 1, 64*64*4, -9 }; + public static final int[] CAPE_DATA_SIZE = new int[] { 32*32*4, -9, 1 }; + + public static ArrayList skins = new ArrayList<>(); + public static ArrayList capes = new ArrayList<>(); + + public static final EaglercraftRandom rand; + + public static int getSkinSize(int len) { + for(int i = 0; i < SKIN_DATA_SIZE.length; ++i) { + if(len == SKIN_DATA_SIZE[i]) { + return i; + } + } + return -1; + } + + public static int getCapeSize(int len) { + for(int i = 0; i < CAPE_DATA_SIZE.length; ++i) { + if(len == CAPE_DATA_SIZE[i]) { + return i; + } + } + return -1; + } + + public static byte[] getSkinPacket() { + if(presetSkinId == -1) { + byte[] d = skins.get(customSkinId).data; + if(d == null) { + return new byte[] { (byte)4, (byte)0 }; + } + byte[] d2 = new byte[1 + d.length]; + int sz = getSkinSize(d.length); + if(sz < 0) { + return new byte[] { (byte)4, (byte)0 }; + } + d2[0] = (byte) sz; + if(d2[0] == (byte)1 && skins.get(customSkinId).slim) { + d2[0] = (byte)5; + } + if(d2[0] == (byte)3 && skins.get(customSkinId).slim) { + d2[0] = (byte)6; + } + System.arraycopy(d, 0, d2, 1, d.length); + return d2; + }else { + return new byte[] { (byte)4, (byte)presetSkinId }; + } + } + + public static byte[] getCapePacket() { + int sf = Minecraft.getMinecraft().gameSettings.getSkinLayers(); + if(presetCapeId == -1) { + byte[] d = capes.get(customCapeId).data; + if(d == null) { + return new byte[] { (byte)2, (byte)sf, (byte)0 }; + } + byte[] d2 = new byte[2 + d.length]; + int sz = getCapeSize(d.length); + if(sz < 0) { + return new byte[] { (byte)2, (byte)sf, (byte)0 }; + } + d2[0] = (byte) sz; + d2[1] = (byte) sf; + System.arraycopy(d, 0, d2, 2, d.length); + return d2; + }else { + return new byte[] { (byte)2, (byte)sf, (byte)presetCapeId }; + } + } + + public static String[] concatArrays(String[] a, String[] b) { + String[] r = new String[a.length + b.length]; + System.arraycopy(a, 0, r, 0, a.length); + System.arraycopy(b, 0, r, a.length, b.length); + return r; + } + + public static int addSkin(String name, byte[] data, boolean slim) { + int i = -1; + for(int j = 0, l = skins.size(); j < l; ++j) { + if(skins.get(j).name.equalsIgnoreCase(name)) { + i = j; + break; + } + } + int t = getSkinSize(data.length); + + if(t == -1) { + return -1; + } + + int w, h; + + switch(t) { + default: + case 0: + w = 64; + h = 32; + break; + case 1: + case 5: + w = 64; + h = 64; + break; + } + + int im = Minecraft.getMinecraft().renderEngine.setupTextureRaw(data, w, h); + if(i == -1) { + i = skins.size(); + skins.add(new EaglerProfileSkin(name, data, slim, im)); + }else { + skins.get(i).glTex = im; + skins.get(i).data = data; + skins.get(i).slim = slim; + } + return i; + + } + + public static int addCape(String name, byte[] data) { + int i = -1; + for(int j = 0, l = capes.size(); j < l; ++j) { + if(capes.get(j).name.equalsIgnoreCase(name)) { + i = j; + break; + } + } + int t = getCapeSize(data.length); + + if(t == -1) { + return -1; + } + + int w, h; + + switch(t) { + default: + case 0: + w = 32; + h = 32; + break; + } + + int im = Minecraft.getMinecraft().renderEngine.setupTextureRaw(data, w, h); + if(i == -1) { + i = capes.size(); + capes.add(new EaglerProfileCape(name, data, im)); + }else { + capes.get(i).glTex = im; + capes.get(i).data = data; + } + return i; + + } + + static { + String[] usernameDefaultWords = ConfigConstants.profanity ? new String[] { + "Eagler", "Eagler", "Bitch", "Cock", "Milf", "Milf", "Yeer", "Groon", + "Eag", "Deevis", "Chode", "Deev", "Deev", "Fucker", "Fucking", + "Dumpster", "Dumpster", "Cum", "Chad", "Egg", "Fudgler", "Fudgli", + "Yee", "Yee", "Yee", "Yeet", "Flumpter", "Darvy", "Darver", "Darver", + "Fuck", "Fuck", "Frick", "Eagler", "Vigg", "Vigg", "Cunt", "Darvig" + } : new String[] { + "Yeeish", "Yeeish", "Yee", "Yee", "Yeer", "Yeeler", "Eagler", "Eagl", + "Darver", "Darvler", "Vool", "Vigg", "Vigg", "Deev", "Yigg", "Yeeg" + }; + + rand = new EaglercraftRandom(); + + do { + username = usernameDefaultWords[rand.nextInt(usernameDefaultWords.length)] + usernameDefaultWords[rand.nextInt(usernameDefaultWords.length)] + (10 + rand.nextInt(90)); + }while(username.length() > 16); + + presetSkinId = rand.nextInt(GuiScreenEditProfile.defaultOptions.length); + customSkinId = -1; + } + + public static void loadFromStorage() { + if(!LocalStorageManager.profileSettingsStorage.hasNoTags()) { + presetSkinId = LocalStorageManager.profileSettingsStorage.getInteger("ps"); + customSkinId = LocalStorageManager.profileSettingsStorage.getInteger("cs"); + presetCapeId = LocalStorageManager.profileSettingsStorage.getInteger("pc"); + customCapeId = LocalStorageManager.profileSettingsStorage.getInteger("cc"); + username = LocalStorageManager.profileSettingsStorage.getString("name"); + newSkinNotificationIndex = LocalStorageManager.profileSettingsStorage.getInteger("nsi"); + if(newSkinNotificationIndex == 0) { + newSkinNotificationIndex = GuiScreenEditProfile.newDefaultNotice; + } + NBTTagCompound n = LocalStorageManager.profileSettingsStorage.getCompoundTag("skins"); + for(Object s : NBTTagCompound.getTagMap(n).keySet()) { + String s2 = (String)s; + NBTBase k = n.getTag(s2); + if(k.getId() == (byte)7) { + addSkin(s2, ((NBTTagByteArray)k).byteArray, false); + }else if(k.getId() == (byte)10) { + addSkin(s2, ((NBTTagCompound)k).getByteArray("data"), ((NBTTagCompound)k).getBoolean("slim")); + } + } + n = LocalStorageManager.profileSettingsStorage.getCompoundTag("capes"); + for(Object s : NBTTagCompound.getTagMap(n).keySet()) { + NBTTagCompound ct = n.getCompoundTag((String)s); + addCape((String)s, ct.getByteArray("data")); + } + }else { + newSkinNotificationIndex = GuiScreenEditProfile.newDefaultNotice; + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/EaglercraftRandom.java b/src/main/java/net/lax1dude/eaglercraft/EaglercraftRandom.java new file mode 100644 index 0000000..72b0f8c --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/EaglercraftRandom.java @@ -0,0 +1,84 @@ +package net.lax1dude.eaglercraft; + +public class EaglercraftRandom { + + private static final long multiplier = 0x5DEECE66DL; + private static final long addend = 0xBL; + private static final long mask = (1L << 48) - 1; + + private static final double DOUBLE_UNIT = 0x1.0p-53; + private long seed = 69; + + public EaglercraftRandom() { + this(System.nanoTime()); + } + + public EaglercraftRandom(long seed) { + setSeed(seed); + } + + public void setSeed(long yeed) { + seed = yeed; + } + + protected int next(int bits) { + seed = (seed * multiplier + addend) & mask; + return (int)(seed >>> (48 - bits)); + } + + public void nextBytes(byte[] bytes) { + for (int i = 0, len = bytes.length; i < len; ) + for (int rnd = nextInt(), + n = Math.min(len - i, Integer.SIZE/Byte.SIZE); + n-- > 0; rnd >>= Byte.SIZE) + bytes[i++] = (byte)rnd; + } + public int nextInt() { + return next(32); + } + public int nextInt(int bound) { + int r = next(31); + int m = bound - 1; + if ((bound & m) == 0) // i.e., bound is a power of 2 + r = (int)((bound * (long)r) >> 31); + else { + for (int u = r; + u - (r = u % bound) + m < 0; + u = next(31)) + ; + } + return r; + } + public long nextLong() { + return ((long)(next(32)) << 32) + next(32); + } + public boolean nextBoolean() { + return next(1) != 0; + } + public float nextFloat() { + return next(24) / ((float)(1 << 24)); + } + public double nextDouble() { + return (((long)(next(26)) << 27) + next(27)) * DOUBLE_UNIT; + } + private double nextNextGaussian; + private boolean haveNextNextGaussian = false; + public double nextGaussian() { + // See Knuth, ACP, Section 3.4.1 Algorithm C. + if (haveNextNextGaussian) { + haveNextNextGaussian = false; + return nextNextGaussian; + } else { + double v1, v2, s; + do { + v1 = 2 * nextDouble() - 1; // between -1 and 1 + v2 = 2 * nextDouble() - 1; // between -1 and 1 + s = v1 * v1 + v2 * v2; + } while (s >= 1 || s == 0); + double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s); + nextNextGaussian = v2 * multiplier; + haveNextNextGaussian = true; + return v1 * multiplier; + } + } +} diff --git a/src/main/java/net/lax1dude/eaglercraft/EarlyLoadScreen.java b/src/main/java/net/lax1dude/eaglercraft/EarlyLoadScreen.java new file mode 100644 index 0000000..81fd018 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/EarlyLoadScreen.java @@ -0,0 +1,171 @@ +package net.lax1dude.eaglercraft; + +import static net.lax1dude.eaglercraft.EaglerAdapter.*; + +import java.nio.IntBuffer; + +import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.BufferArrayGL; +import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.BufferGL; +import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.ProgramGL; +import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.ShaderGL; +import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.TextureGL; +import net.minecraft.src.GLAllocation; + +public class EarlyLoadScreen { + + public static final String loadScreen = "iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAYAAABS3GwHAAAACXBIWXMAAAsTAAALEwEAmpwYAAAHx0lEQVR42u3da27jIBRAYbfqFp1FuovM/GLEMIDBhsRJviNVapsYY8y5vPz4ut/v9wX4UL4VAQgAEAAgAEAAgAAAAQACAAQACAAQACAAQACAAAABAAIABAAIABAAIABAAIAAAAEAAgAEAAgAEAAgAEAAgAAAAQACAAQACAAQACAAQACAAAABAAIABAAIABAAIABAAIAAAAEAAgAEAAgAEAAgAAgAEAAgAEAAgAAAAQACAAQACAAQACAAQACAAMBr86MI3ovf39/i/9Z1XdZ1VUgEeN/Kf7vdqt8hgC7QW6OCE+CjK/+2bcv9fieCLtDjux9x/1t/u1xOveWSlisBXmQASoB/+fr6+vv7/X7vHteE8hxZrrpAkyo/2mU42soSgAAfN8YZ3aoSQOV/GNu2ZX9vGdjPEuBnVmXIVYqePly8famCne0TtuS1tt/a9kfSbWnqZw2u9yQesc91XZv7/iO2a+I+iG3b7uu63pdl2f1Z17WaTksaaXrbtk3JaynvR/O5l6/WtPaON3d8tf3v7e9d+RkVPeIVyDRKpREtfL+nGdxL7/f3d9m2bTdS5VZL4/Rz0fcRszm32604jZrLUyi/UXlb1/WlunKhTE63iCMif0tkao1IaXqlqFWKlr2RsTUPpXRLrUnYpqVlircfdby9LUCpbHpa1lyeW8tgL51SmZ9N+2dE5GqJlrkI0xJxaumV0ixt0xrd07TDdrl+aDoeGNnfbzne0RE1HqSOaF3SljptyXP7qF3QN3zi4Yw9LdF0r5+Zs7u175mLirU85KJiLbK3pt2bj1qZ1CJaz356WoD0u2ejaq11XNf1708uf73jqqeOAXotbIlgZ/t0tfSPRulZ050j0jubRjz2CGU/clyRRvvwv1LPIR4X5r6TtlJPmwY9W5la54vfea5+Zhm2dnniyj+j3GtdxCsMzL+vWAmuyujK2dLXnVGGYSZsduXPlV0625Vbk0nlnFlXhrYAezdjPFOa2sD4GRetlY5hdhnmpoHjKcXZlb927Llp4JCvWYHy8leDxpHgbCH0zBo9s3vyiLK8QiBIxwiPaHWnjwFGZbjl9r5RAtxut92Fp5GLTqPHP735qpXDrK5QbjFz27b/Wp802IXu2Yz6cGoadDmwCHV0enVJFpbCfkqLQ6Mvg9g7riPToEfyfrYMl4ZLOUadw1rZh33H/ytNjcbnunfavakeX02As3P1rZVoT4KeVdBXESDN05HV4pFXDaQrxqkE6TnISfC0dYAZA5PSSu3orkeYiSil/Sl3cm3b9t+NKbMHxHtTpenvcT7C33Gez+b1e3QFvvrUY2nhZ/Qi0KtMC+f6/KWpytnnsjWoXuKWyNaZkyud/HTh55mVvTYt++h8zDiXlTFnkwS1wfhlBZgxj917acNe9H9mZWuJvjPuez0azJ5RPj1T3kMe/zJyUNMzkMpdJts6MNybyckNXo/cwLI0XtZ8ZkaldBwt2x65RHvGMRwZoO9dWLh3CfqofC0zZhtKU5fpiWkVIE4n3b423Zemf0SA5cQdVenxt9x70FJ+8TEfkbxUuXqDytnp0L2p0kewzJjeOnMSWtKKt92rQCNageXEDTot05xH1iZy5Xf2lsra9iMrZDjW2dG9ha/7wLuNS5ctpDevt9y2WBu0ptvnxh2l75YutOrtu+/1m+N8tw66022PlGHrcfVuP+NCwNrg+2ETFPcPI45yLSu8s1Yg8UY3xb8K6WP2WualrzJjhDl8f2Ll721iPeiWAG8hwMw+LQhw6co/cpWaPO/DR4wBchU23APQMiMy43EhuAZDp0FfaQxwRCJjAQK8xTigp0uk4hPgowbH+vkEAD4GL8gAAQACAAQACAAQACAAQACAAAABAAIABAAIABAAIABAAIAAAAEAAgAEAK7NJR6M9S6PLQzPHZr1sulSuXmCxQu3APHz+sNP6wOspr09/CL76ym3Tzr2t2sBHhk13+UYwgsmnvFeXwI8qUtRinZxZNq27e/3tm3Lvg8gjWRpxc09Rj3eb2l/ufTiZ5CG78Sfn305eO7durX8tH4W8pB+Pz32vTQJcGAcED+0Nv5//Pbw9GTl+sKh8sVRMo2WoWkPJy0WpiRB6XVFpa5IvF28v3RfvX36mpylBwKXPktbkjiI1I69liYBTg6E4wqTkyOWolRB4nTSE5XuszaI3dvfngRppM1F+9auTG4fuW1raeXendYiWk+aBBjQf44jZW/TWoriV3gRddwi9L57IPfY9lA5Q3nF6YZyq33WIkLt/NTSJMCAcUD4/Wzhxt2o3Hjg0a3emSdPt7Q2t9vtn3KrfXY0L7U091rWo599xBggjSgh0pSa79aTl4ugaR8913qU9ld6vWlvd6bn+7mB+96MUHpcLULtHftemlqAAwKEwVd6MtNBbK4C7kWLuMkuDT5zA+za/nKzMC0VOu0CtXQhal2UeKCfG2PUPsvNZrUcey3NV8Dj0Z/cvctNQ77DmogWAM0S7M0gQQvwluS6HFZ0CQA8DJdDgwAAAQACAAQACAAQACAAQACAAAABAAIABAAIABAAIABAAIAAAAEAAgAEAAgAEAAgAEAAgAAAAQACAAQACAAQACAAQACAAAABAAIABAAIABAAIABAAIAAAAEAAgAEAAgAEAAgAEAAgAAAAYBlWf4A1W4Hx65cJAoAAAAASUVORK5CYII="; + public static final String enableScreen = "iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAACXBIWXMAAC4jAAAuIwF4pT92AAAEAklEQVR42u2dvXbjIBBG7T0+xw+gTp06v//LmE6dO/VR5a3wGZNh+BGSFeveJgkIBrDy8TGKds8/Pz/PExyW8/P55AY4MP9YgmNzmeeZVUABAA8AKADgAQAFADwAoACABwAUAPAAgAIAHgBQAMADAAoAeABAAY7LOI7fpQDX65VPtZCt18w5d7rdbigAbOgBxnE8DcPwJnnDMCTrNJlsUVcizTnj9HWxeVvINfN9y361OdTEk30551ZZt3PsvYDYxOSChoPQ6sJ21mRLBm61jY0lpy61gDKWNdfcNcv5wErWLbfPF88I9/s9WtayzopXS85YtPqcMeT23SqedV1pucal1V4iTUooV/IaWSfbWHU5JmkvpmzrsayaB9DqfJnVTpMff72sc869/WzVlcjjOI7mOOVYfBzfT05exLfT5pqae008a71Ly6tPASV79CfPylvFjpm+teLH+tXiF5nA2LOAUMpCibckWpPBUOJT20btFuDjyK8p+S45Z4fX+ti+LDb3pef62PosWbfkDbBW8mFPhB/gt8Vr7gG+kZK9+C/GM2+ArffnnKRHbT5gSdJoK0+ydrziGyCW115LolLxnHOr59q3lt89b6U8Czg4pgdI5bUtKY3VzfOclGBtTLVSmmqn1cdyC7Iud+5791KX1MLJDz3Mg2s59pK6sM/asdTmLrRx5pzjS+e+awWw9lstVeuv1/a10rqwT8sn5LQr8RzaMVfmKrR2qfnFjs57/puLS0nyoTZp0fL8XGq+ap8v4AES+3Msx74kN2/tmblewWoXPl9o+RykZH5/5hTQYv+y+vj084XcPHpJbHmt1s7yGbV1q+UBnHO/gnoZje2RmuzK/Vr2F3sWEF6TGkvutqH5CG08qTmk5u77tLyK5Qtq62rgxRA8AO8FHBkygQeHLQAFADwAoACABwAUAPAAgAIAHgBQAMADAAoAeABAAQAPACgA4AEABQA8AKAAgAcAFAC+3gNM03Tqum7VQSyN4dtvMdZDKcBWC9oqhr8JoIEHeDwep77vf5VJfL0vl9fLa/u+f+vPfx9eszSGNXZo5AH6vlcXW36gsqykrzViwAIPYL3r3nXd63v5m6i9J2+VaT8viWGNHZQbYE97+KdjHPIGKH0XPSyL7eXSjPk2YZlsN03Tq21OjLAs598ZggIT2MpMbW3IMICFN0Dsv4xpfUbfAvIAK9wAcOAtAMgDwJHzAIACAB4AUADAAwAKAHgAQAEADwAoAOABAAUAPACgAIAHABQA8ACAAgAeAFAAwAMACgB4AEABAA8AKADgAQAFADwAoACABwAUAPAAgAIAHgBQAMADAAoAeABAAQAPACgA4AEABQA8AKAAgAcAFADwANCe/0of1jQ8XY5YAAAAAElFTkSuQmCC"; + + private static BufferGL vbo = null; + private static ProgramGL program = null; + + public static void paintScreen() { + + TextureGL tex = _wglGenTextures(); + _wglActiveTexture(_wGL_TEXTURE0); + glBindTexture(_wGL_TEXTURE_2D, tex); + _wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MAG_FILTER, _wGL_NEAREST); + _wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MIN_FILTER, _wGL_NEAREST); + _wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_S, _wGL_CLAMP); + _wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_T, _wGL_CLAMP); + //EaglerImage img = EaglerImage.loadImage(Base64.decodeBase64(loadScreen)); + EaglerImage img = EaglerAdapter.loadPNG(Base64.decodeBase64(loadScreen)); + IntBuffer upload = GLAllocation.createDirectIntBuffer(192*192); + upload.put(img.data); + upload.flip(); + _wglTexImage2D(_wGL_TEXTURE_2D, 0, _wGL_RGBA, 192, 192, 0, _wGL_RGBA, _wGL_UNSIGNED_BYTE, upload); + + upload.clear(); + upload.put(Float.floatToIntBits(0.0f)); upload.put(Float.floatToIntBits(0.0f)); + upload.put(Float.floatToIntBits(0.0f)); upload.put(Float.floatToIntBits(1.0f)); + upload.put(Float.floatToIntBits(1.0f)); upload.put(Float.floatToIntBits(0.0f)); + upload.put(Float.floatToIntBits(1.0f)); upload.put(Float.floatToIntBits(0.0f)); + upload.put(Float.floatToIntBits(0.0f)); upload.put(Float.floatToIntBits(1.0f)); + upload.put(Float.floatToIntBits(1.0f)); upload.put(Float.floatToIntBits(1.0f)); + upload.flip(); + + vbo = _wglCreateBuffer(); + _wglBindBuffer(_wGL_ARRAY_BUFFER, vbo); + _wglBufferData0(_wGL_ARRAY_BUFFER, upload, _wGL_STATIC_DRAW); + + ShaderGL vert = _wglCreateShader(_wGL_VERTEX_SHADER); + _wglShaderSource(vert, _wgetShaderHeader()+"\nprecision lowp float; in vec2 a_pos; out vec2 v_pos; void main() { gl_Position = vec4(((v_pos = a_pos) - 0.5) * vec2(2.0, -2.0), 0.0, 1.0); }"); + _wglCompileShader(vert); + + ShaderGL frag = _wglCreateShader(_wGL_FRAGMENT_SHADER); + _wglShaderSource(frag, _wgetShaderHeader()+"\nprecision lowp float; in vec2 v_pos; out vec4 fragColor; uniform sampler2D tex; uniform vec2 aspect; void main() { fragColor = vec4(texture(tex, clamp(v_pos * aspect - ((aspect - 1.0) * 0.5), 0.02, 0.98)).rgb, 1.0); }"); + _wglCompileShader(frag); + + program = _wglCreateProgram(); + + _wglAttachShader(program, vert); + _wglAttachShader(program, frag); + _wglBindAttributeLocation(program, 0, "a_pos"); + _wglLinkProgram(program); + _wglDetachShader(program, vert); + _wglDetachShader(program, frag); + _wglDeleteShader(vert); + _wglDeleteShader(frag); + + sleep(50); + + _wglUseProgram(program); + _wglUniform1i(_wglGetUniformLocation(program, "tex"), 0); + + int width = getCanvasWidth(); + int height = getCanvasHeight(); + float x, y; + if(width > height) { + x = (float)width / (float)height; + y = 1.0f; + }else { + x = 1.0f; + y = (float)height / (float)width; + } + + _wglActiveTexture(_wGL_TEXTURE0); + glBindTexture(_wGL_TEXTURE_2D, tex); + + _wglViewport(0, 0, width, height); + _wglClearColor(1.0f, 1.0f, 1.0f, 1.0f); + _wglClear(_wGL_COLOR_BUFFER_BIT | _wGL_DEPTH_BUFFER_BIT); + + _wglUniform2f(_wglGetUniformLocation(program, "aspect"), x, y); + + BufferArrayGL vao = _wglCreateVertexArray(); + _wglBindVertexArray0(vao); + _wglEnableVertexAttribArray(0); + _wglVertexAttribPointer(0, 2, _wGL_FLOAT, false, 8, 0); + _wglDrawArrays(_wGL_TRIANGLES, 0, 6); + _wglDisableVertexAttribArray(0); + _wglFlush(); + updateDisplay(0, false); + sleep(20); + + _wglUseProgram(null); + _wglBindBuffer(_wGL_ARRAY_BUFFER, null); + glBindTexture(_wGL_TEXTURE_2D, null); + _wglDeleteTextures(tex); + _wglDeleteVertexArray(vao); + } + + public static void paintEnable() { + + TextureGL tex = _wglGenTextures(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(_wGL_TEXTURE_2D, tex); + _wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MAG_FILTER, _wGL_NEAREST); + _wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MIN_FILTER, _wGL_NEAREST); + _wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_S, _wGL_CLAMP); + _wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_T, _wGL_CLAMP); + //EaglerImage img = EaglerImage.loadImage(Base64.decodeBase64(enableScreen)); + EaglerImage img = EaglerAdapter.loadPNG(Base64.decodeBase64(enableScreen)); + IntBuffer upload = GLAllocation.createDirectIntBuffer(128*128); + upload.put(img.data); + upload.flip(); + _wglTexImage2D(_wGL_TEXTURE_2D, 0, _wGL_RGBA, 128, 128, 0, _wGL_RGBA, _wGL_UNSIGNED_BYTE, upload); + + sleep(50); + + _wglUseProgram(program); + + int width = getCanvasWidth(); + int height = getCanvasHeight(); + float x, y; + if(width > height) { + x = (float)width / (float)height; + y = 1.0f; + }else { + x = 1.0f; + y = (float)height / (float)width; + } + + glActiveTexture(GL_TEXTURE0); + glBindTexture(_wGL_TEXTURE_2D, tex); + + _wglViewport(0, 0, width, height); + _wglClearColor(1.0f, 1.0f, 1.0f, 1.0f); + _wglClear(_wGL_COLOR_BUFFER_BIT | _wGL_DEPTH_BUFFER_BIT); + + _wglUniform2f(_wglGetUniformLocation(program, "aspect"), x, y); + + BufferArrayGL vao = _wglCreateVertexArray(); + _wglBindVertexArray0(vao); + _wglBindBuffer(_wGL_ARRAY_BUFFER, vbo); + _wglEnableVertexAttribArray(0); + _wglVertexAttribPointer(0, 2, _wGL_FLOAT, false, 8, 0); + _wglDrawArrays(_wGL_TRIANGLES, 0, 6); + _wglDisableVertexAttribArray(0); + _wglFlush(); + updateDisplay(0, false); + sleep(20); + + _wglUseProgram(null); + _wglBindBuffer(_wGL_ARRAY_BUFFER, null); + glBindTexture(_wGL_TEXTURE_2D, null); + _wglDeleteTextures(tex); + _wglDeleteVertexArray(vao); + + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/EnumBrowser.java b/src/main/java/net/lax1dude/eaglercraft/EnumBrowser.java new file mode 100644 index 0000000..8b3ca5b --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/EnumBrowser.java @@ -0,0 +1,47 @@ +package net.lax1dude.eaglercraft; + +public enum EnumBrowser { + + DESKTOP("Desktop"), CHROME("Chrome"), EDGE("Edge"), IE("IE"), FIREFOX("Firefox"), SAFARI("Safari"), OPERA("Opera"), WEBKIT("WebKit"), GECKO("Gecko"), UNKNOWN("Unknown"); + + public final String name; + + private EnumBrowser(String string) { + this.name = string; + } + + private static EnumBrowser identifiedBrowser = null; + + public static EnumBrowser getBrowser() { + if(identifiedBrowser == null) { + String ua = " " + EaglerAdapter.getUserAgent().toLowerCase(); + if(ua.contains(" edg/")) { + identifiedBrowser = EDGE; + }else if(ua.contains(" opr/")) { + identifiedBrowser = OPERA; + }else if(ua.contains(" chrome/")) { + identifiedBrowser = CHROME; + }else if(ua.contains(" firefox/")) { + identifiedBrowser = FIREFOX; + }else if(ua.contains(" safari/")) { + identifiedBrowser = SAFARI; + }else if(ua.contains(" trident/") || ua.contains(" msie")) { + identifiedBrowser = IE; + }else if(ua.contains(" webkit/")) { + identifiedBrowser = WEBKIT; + }else if(ua.contains(" gecko/")) { + identifiedBrowser = GECKO; + }else if(ua.contains(" desktop/")) { + identifiedBrowser = DESKTOP; + }else { + identifiedBrowser = UNKNOWN; + } + } + return identifiedBrowser; + } + + public String toString() { + return name; + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/ExpiringSet.java b/src/main/java/net/lax1dude/eaglercraft/ExpiringSet.java new file mode 100644 index 0000000..5d7e485 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/ExpiringSet.java @@ -0,0 +1,71 @@ +package net.lax1dude.eaglercraft; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; + +// note that there's a few things not implemented, but I don't care. + +public class ExpiringSet extends HashSet { + private final long expiration; + private final ExpiringEvent event; + + private final Map timestamps = new HashMap<>(); + + public ExpiringSet(long expiration) { + this.expiration = expiration; + this.event = null; + } + + public ExpiringSet(long expiration, ExpiringEvent event) { + this.expiration = expiration; + this.event = event; + } + + public interface ExpiringEvent { + void onExpiration(T item); + } + + public void checkForExpirations() { + Iterator iterator = this.timestamps.keySet().iterator(); + long now = EaglerAdapter.steadyTimeMillis(); + while (iterator.hasNext()) { + T element = iterator.next(); + if (super.contains(element)) { + if (this.timestamps.get(element) + this.expiration < now) { + if (this.event != null) this.event.onExpiration(element); + iterator.remove(); + super.remove(element); + } + } else { + iterator.remove(); + super.remove(element); + } + } + } + + public boolean add(T o) { + checkForExpirations(); + boolean success = super.add(o); + if (success) timestamps.put(o, EaglerAdapter.steadyTimeMillis()); + return success; + } + + public boolean remove(Object o) { + checkForExpirations(); + boolean success = super.remove(o); + if (success) timestamps.remove(o); + return success; + } + + public void clear() { + this.timestamps.clear(); + super.clear(); + } + + public boolean contains(Object o) { + checkForExpirations(); + return super.contains(o); + } +} \ No newline at end of file diff --git a/src/main/java/net/lax1dude/eaglercraft/GeneralDigest.java b/src/main/java/net/lax1dude/eaglercraft/GeneralDigest.java new file mode 100644 index 0000000..0ebbb07 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GeneralDigest.java @@ -0,0 +1,124 @@ +package net.lax1dude.eaglercraft; + +/** + * base implementation of MD4 family style digest as outlined in + * "Handbook of Applied Cryptography", pages 344 - 347. + */ +public abstract class GeneralDigest { + private byte[] xBuf; + private int xBufOff; + + private long byteCount; + + /** + * Standard constructor + */ + protected GeneralDigest() + { + xBuf = new byte[4]; + xBufOff = 0; + } + + /** + * Copy constructor. We are using copy constructors in place + * of the Object.clone() interface as this interface is not + * supported by J2ME. + */ + protected GeneralDigest(GeneralDigest t) + { + xBuf = new byte[t.xBuf.length]; + System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length); + + xBufOff = t.xBufOff; + byteCount = t.byteCount; + } + + public void update( + byte in) + { + xBuf[xBufOff++] = in; + + if (xBufOff == xBuf.length) + { + processWord(xBuf, 0); + xBufOff = 0; + } + + byteCount++; + } + + public void update( + byte[] in, + int inOff, + int len) + { + // + // fill the current word + // + while ((xBufOff != 0) && (len > 0)) + { + update(in[inOff]); + + inOff++; + len--; + } + + // + // process whole words. + // + while (len > xBuf.length) + { + processWord(in, inOff); + + inOff += xBuf.length; + len -= xBuf.length; + byteCount += xBuf.length; + } + + // + // load in the remainder. + // + while (len > 0) + { + update(in[inOff]); + + inOff++; + len--; + } + } + + public void finish() + { + long bitLength = (byteCount << 3); + + // + // add the pad bytes. + // + update((byte)128); + + while (xBufOff != 0) + { + update((byte)0); + } + + processLength(bitLength); + + processBlock(); + } + + public void reset() + { + byteCount = 0; + + xBufOff = 0; + for ( int i = 0; i < xBuf.length; i++ ) { + xBuf[i] = 0; + } + } + + protected abstract void processWord(byte[] in, int inOff); + + protected abstract void processLength(long bitLength); + + protected abstract void processBlock(); +} diff --git a/src/main/java/net/lax1dude/eaglercraft/GuiNetworkSettingsButton.java b/src/main/java/net/lax1dude/eaglercraft/GuiNetworkSettingsButton.java new file mode 100644 index 0000000..50fa9a0 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GuiNetworkSettingsButton.java @@ -0,0 +1,41 @@ +package net.lax1dude.eaglercraft; + +import net.minecraft.src.Minecraft; +import net.minecraft.src.EnumChatFormatting; +import net.minecraft.src.Gui; +import net.minecraft.src.GuiScreen; +import net.minecraft.src.StringTranslate; + +public class GuiNetworkSettingsButton extends Gui { + + private final GuiScreen screen; + private final String text; + private final Minecraft mc; + + public GuiNetworkSettingsButton(GuiScreen screen) { + this.screen = screen; + this.text = StringTranslate.getInstance().translateKey("directConnect.lanWorldRelay"); + this.mc = Minecraft.getMinecraft(); + } + + public void drawScreen(int xx, int yy) { + EaglerAdapter.glPushMatrix(); + EaglerAdapter.glScalef(0.75f, 0.75f, 0.75f); + + int w = mc.fontRenderer.getStringWidth(text); + boolean hover = xx > 1 && yy > 1 && xx < (w * 3 / 4) + 7 && yy < 12; + + drawString(mc.fontRenderer, EnumChatFormatting.UNDERLINE + text, 5, 5, hover ? 0xFFEEEE22 : 0xFFCCCCCC); + + EaglerAdapter.glPopMatrix(); + } + + public void mouseClicked(int xx, int yy, int btn) { + int w = mc.fontRenderer.getStringWidth(text); + if(xx > 2 && yy > 2 && xx < (w * 3 / 4) + 5 && yy < 12) { + mc.displayGuiScreen(new GuiScreenRelay(screen)); + mc.sndManager.playSoundFX("random.click", 1.0F, 1.0F); + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/GuiScreenAddRelay.java b/src/main/java/net/lax1dude/eaglercraft/GuiScreenAddRelay.java new file mode 100644 index 0000000..1bdc206 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GuiScreenAddRelay.java @@ -0,0 +1,128 @@ +package net.lax1dude.eaglercraft; + +import net.minecraft.src.GuiButton; +import net.minecraft.src.GuiScreen; +import net.minecraft.src.GuiTextField; +import net.minecraft.src.StringTranslate; + +public class GuiScreenAddRelay extends GuiScreen { + + /** This GUI's parent GUI. */ + private GuiScreenRelay parentGui; + private GuiTextField serverAddress; + private GuiTextField serverName; + + public GuiScreenAddRelay(GuiScreenRelay par1GuiScreen) { + this.parentGui = par1GuiScreen; + } + + /** + * Called from the main game loop to update the screen. + */ + public void updateScreen() { + this.serverName.updateCursorCounter(); + this.serverAddress.updateCursorCounter(); + } + + /** + * Adds the buttons (and other controls) to the screen in question. + */ + public void initGui() { + StringTranslate var1 = StringTranslate.getInstance(); + EaglerAdapter.enableRepeatEvents(true); + this.buttonList.clear(); + this.parentGui.addNewName = IntegratedServer.relayManager.makeNewRelayName(); + this.parentGui.addNewAddr = ""; + this.parentGui.addNewPrimary = IntegratedServer.relayManager.count() == 0; + int sslOff = EaglerAdapter.isSSLPage() ? 36 : 0; + this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 96 + 12 + sslOff, var1.translateKey("addRelay.add"))); + this.buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 + 120 + 12 + sslOff, var1.translateKey("gui.cancel"))); + this.buttonList.add(new GuiButton(2, this.width / 2 - 100, 142, var1.translateKey("addRelay.primary") + ": " + (this.parentGui.addNewPrimary ? var1.translateKey("gui.yes") : var1.translateKey("gui.no")))); + this.serverName = new GuiTextField(this.fontRenderer, this.width / 2 - 100, 106, 200, 20); + this.serverAddress = new GuiTextField(this.fontRenderer, this.width / 2 - 100, 66, 200, 20); + this.serverAddress.setMaxStringLength(128); + this.serverAddress.setFocused(true); + ((GuiButton) this.buttonList.get(0)).enabled = this.serverAddress.getText().length() > 0 && this.serverAddress.getText().split(":").length > 0 && this.serverName.getText().length() > 0; + this.serverName.setText(this.parentGui.addNewName); + } + + /** + * Called when the screen is unloaded. Used to disable keyboard repeat events + */ + public void onGuiClosed() { + EaglerAdapter.enableRepeatEvents(false); + } + + /** + * Fired when a control is clicked. This is the equivalent of + * ActionListener.actionPerformed(ActionEvent e). + */ + protected void actionPerformed(GuiButton par1GuiButton) { + if (par1GuiButton.enabled) { + if (par1GuiButton.id == 1) { + this.parentGui.confirmClicked(false, 0); + } else if (par1GuiButton.id == 0) { + this.parentGui.addNewName = this.serverName.getText(); + this.parentGui.addNewAddr = this.serverAddress.getText(); + this.parentGui.confirmClicked(true, 0); + } else if (par1GuiButton.id == 2) { + StringTranslate var2 = StringTranslate.getInstance(); + this.parentGui.addNewPrimary = !this.parentGui.addNewPrimary; + ((GuiButton) this.buttonList.get(2)).displayString = var2.translateKey("addRelay.primary") + ": " + (this.parentGui.addNewPrimary ? var2.translateKey("gui.yes") : var2.translateKey("gui.no")); + } + } + } + + /** + * Fired when a key is typed. This is the equivalent of + * KeyListener.keyTyped(KeyEvent e). + */ + protected void keyTyped(char par1, int par2) { + this.serverName.textboxKeyTyped(par1, par2); + this.serverAddress.textboxKeyTyped(par1, par2); + + if (par1 == 9) { + if (this.serverName.isFocused()) { + this.serverName.setFocused(false); + this.serverAddress.setFocused(true); + } else { + this.serverName.setFocused(true); + this.serverAddress.setFocused(false); + } + } + + if (par1 == 13) { + this.actionPerformed((GuiButton) this.buttonList.get(0)); + } + + ((GuiButton) this.buttonList.get(0)).enabled = this.serverAddress.getText().length() > 0 && this.serverAddress.getText().split(":").length > 0 && this.serverName.getText().length() > 0; + } + + /** + * Called when the mouse is clicked. + */ + protected void mouseClicked(int par1, int par2, int par3) { + super.mouseClicked(par1, par2, par3); + this.serverAddress.mouseClicked(par1, par2, par3); + this.serverName.mouseClicked(par1, par2, par3); + } + + /** + * Draws the screen and all the components in it. + */ + public void drawScreen(int par1, int par2, float par3) { + StringTranslate var4 = StringTranslate.getInstance(); + this.drawDefaultBackground(); + this.drawCenteredString(this.fontRenderer, var4.translateKey("addRelay.title"), this.width / 2, 17, 16777215); + this.drawString(this.fontRenderer, var4.translateKey("addRelay.address"), this.width / 2 - 100, 53, 10526880); + this.drawString(this.fontRenderer, var4.translateKey("addRelay.name"), this.width / 2 - 100, 94, 10526880); + if(EaglerAdapter.isSSLPage()) { + this.drawCenteredString(this.fontRenderer, var4.translateKey("addServer.SSLWarn1"), this.width / 2, 169, 0xccccff); + this.drawCenteredString(this.fontRenderer, var4.translateKey("addServer.SSLWarn2"), this.width / 2, 181, 0xccccff); + } + this.serverName.drawTextBox(); + this.serverAddress.drawTextBox(); + super.drawScreen(par1, par2, par3); + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/GuiScreenBackupWorld.java b/src/main/java/net/lax1dude/eaglercraft/GuiScreenBackupWorld.java new file mode 100644 index 0000000..667f616 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GuiScreenBackupWorld.java @@ -0,0 +1,109 @@ +package net.lax1dude.eaglercraft; + +import net.lax1dude.eaglercraft.sp.ipc.IPCPacket05RequestData; +import net.minecraft.src.GuiButton; +import net.minecraft.src.GuiCreateWorld; +import net.minecraft.src.GuiRenameWorld; +import net.minecraft.src.GuiScreen; +import net.minecraft.src.GuiYesNo; +import net.minecraft.src.NBTTagCompound; +import net.minecraft.src.StringTranslate; +import net.minecraft.src.WorldInfo; + +public class GuiScreenBackupWorld extends GuiScreen { + + private GuiScreen selectWorld; + + private GuiButton worldRecreate = null; + private GuiButton worldDuplicate = null; + private GuiButton worldExport = null; + private GuiButton worldConvert = null; + private GuiButton worldBackup = null; + private long worldSeed; + private NBTTagCompound levelDat; + + private String worldName; + + public GuiScreenBackupWorld(GuiScreen selectWorld, String worldName, NBTTagCompound levelDat) { + this.selectWorld = selectWorld; + this.worldName = worldName; + this.levelDat = levelDat; + this.worldSeed = levelDat.getCompoundTag("Data").getLong("RandomSeed"); + } + + public void initGui() { + StringTranslate var1 = StringTranslate.getInstance(); + this.buttonList.add(worldRecreate = new GuiButton(1, this.width / 2 - 100, this.height / 5 + 15, var1.translateKey("selectWorld.backup.recreate"))); + this.buttonList.add(worldDuplicate = new GuiButton(2, this.width / 2 - 100, this.height / 5 + 40, var1.translateKey("selectWorld.backup.duplicate"))); + this.buttonList.add(worldExport = new GuiButton(3, this.width / 2 - 100, this.height / 5 + 90, var1.translateKey("selectWorld.backup.export"))); + this.buttonList.add(worldConvert = new GuiButton(4, this.width / 2 - 100, this.height / 5 + 115, var1.translateKey("selectWorld.backup.vanilla"))); + this.buttonList.add(worldBackup = new GuiButton(5, this.width / 2 - 100, this.height / 5 + 146, var1.translateKey("selectWorld.backup.clearPlayerData"))); + this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 165, var1.translateKey("gui.cancel"))); + } + + public void drawScreen(int par1, int par2, float par3) { + StringTranslate var4 = StringTranslate.getInstance(); + this.drawDefaultBackground(); + + this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.backup.title") + " '" + worldName + "'", this.width / 2, this.height / 5 - 25, 16777215); + this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.backup.seed") + " " + worldSeed, this.width / 2, this.height / 5 + 72, 0xAAAAFF); + + int toolTipColor = 0xDDDDAA; + if(worldRecreate.func_82252_a()) { + this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.backup.recreate.tooltip"), this.width / 2, this.height / 5 - 2, toolTipColor); + }else if(worldDuplicate.func_82252_a()) { + this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.backup.duplicate.tooltip"), this.width / 2, this.height / 5 - 2, toolTipColor); + }else if(worldExport.func_82252_a()) { + this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.backup.export.tooltip"), this.width / 2, this.height / 5 - 2, toolTipColor); + }else if(worldConvert.func_82252_a()) { + this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.backup.vanilla.tooltip"), this.width / 2, this.height / 5 - 2, toolTipColor); + }else if(worldBackup.func_82252_a()) { + this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.backup.clearPlayerData.tooltip"), this.width / 2, this.height / 5 - 2, toolTipColor); + } + + super.drawScreen(par1, par2, par3); + } + + protected void actionPerformed(GuiButton par1GuiButton) { + if(par1GuiButton.id == 0) { + this.mc.displayGuiScreen(selectWorld); + }else if(par1GuiButton.id == 1) { + GuiCreateWorld cw = new GuiCreateWorld(selectWorld); + cw.func_82286_a(new WorldInfo(this.levelDat.getCompoundTag("Data"))); + this.mc.displayGuiScreen(cw); + }else if(par1GuiButton.id == 2) { + this.mc.displayGuiScreen(new GuiRenameWorld(this.selectWorld, this.worldName, true)); + }else if(par1GuiButton.id == 3) { + IntegratedServer.exportWorld(worldName, IPCPacket05RequestData.REQUEST_LEVEL_EAG); + this.mc.displayGuiScreen(new GuiScreenSingleplayerLoading(selectWorld, "selectWorld.progress.exporting.1", () -> { + byte[] b = IntegratedServer.getExportResponse(); + if(b != null) { + EaglerAdapter.downloadBytes(worldName + ".epk", b); + return true; + } + return false; + })); + }else if(par1GuiButton.id == 4) { + IntegratedServer.exportWorld(worldName, IPCPacket05RequestData.REQUEST_LEVEL_MCA); + this.mc.displayGuiScreen(new GuiScreenSingleplayerLoading(selectWorld, "selectWorld.progress.exporting.2", () -> { + byte[] b = IntegratedServer.getExportResponse(); + if(b != null) { + EaglerAdapter.downloadBytes(worldName + ".zip", b); + return true; + } + return false; + })); + }else if(par1GuiButton.id == 5) { + StringTranslate var4 = StringTranslate.getInstance(); + this.mc.displayGuiScreen(new GuiYesNo(this, var4.translateKey("selectWorld.backup.clearPlayerData.warning1"), + var4.translateKey("selectWorld.backup.clearPlayerData.warning2").replace("$world$", worldName).replace("$player$", EaglerProfile.username), 0)); + } + } + + public void confirmClicked(boolean par1, int par2) { + if(par1) { + IntegratedServer.clearPlayerData(worldName); + } + mc.displayGuiScreen(this); + } +} diff --git a/src/main/java/net/lax1dude/eaglercraft/GuiScreenChangeRelayTimeout.java b/src/main/java/net/lax1dude/eaglercraft/GuiScreenChangeRelayTimeout.java new file mode 100644 index 0000000..be3c100 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GuiScreenChangeRelayTimeout.java @@ -0,0 +1,71 @@ +package net.lax1dude.eaglercraft; + +import net.minecraft.src.Minecraft; +import net.minecraft.src.GuiButton; +import net.minecraft.src.GuiScreen; +import net.minecraft.src.GuiSlider2; +import net.minecraft.src.StringTranslate; + +public class GuiScreenChangeRelayTimeout extends GuiScreen { + + private GuiScreen parent; + private GuiSlider2 slider; + private String title; + + public GuiScreenChangeRelayTimeout(GuiScreen parent) { + this.parent = parent; + } + + public void initGui() { + StringTranslate ts = StringTranslate.getInstance(); + title = ts.translateKey("networkSettings.relayTimeoutTitle"); + buttonList.clear(); + buttonList.add(new GuiButton(0, width / 2 - 100, height / 3 + 55, ts.translateKey("gui.done"))); + buttonList.add(new GuiButton(1, width / 2 - 100, height / 3 + 85, ts.translateKey("gui.cancel"))); + slider = new GuiSlider2(0, width / 2 - 100, height / 3 + 10, 200, 20, (mc.gameSettings.relayTimeout - 1) / 14.0f, 1.0f) { + public boolean mousePressed(Minecraft par1Minecraft, int par2, int par3) { + if(super.mousePressed(par1Minecraft, par2, par3)) { + this.displayString = "" + (int)((sliderValue * 14.0f) + 1.0f) + "s"; + return true; + }else { + return false; + } + } + public void mouseDragged(Minecraft par1Minecraft, int par2, int par3) { + super.mouseDragged(par1Minecraft, par2, par3); + this.displayString = "" + (int)((sliderValue * 14.0f) + 1.0f) + "s"; + } + }; + slider.displayString = "" + mc.gameSettings.relayTimeout + "s"; + } + + public void actionPerformed(GuiButton btn) { + if(btn.id == 0) { + mc.gameSettings.relayTimeout = (int)((slider.sliderValue * 14.0f) + 1.0f); + mc.gameSettings.saveOptions(); + mc.displayGuiScreen(parent); + }else if(btn.id == 1) { + mc.displayGuiScreen(parent); + } + } + + public void drawScreen(int par1, int par2, float par3) { + drawDefaultBackground(); + drawCenteredString(fontRenderer, title, width / 2, height / 3 - 20, 0xFFFFFF); + slider.drawButton(mc, par1, par2); + super.drawScreen(par1, par2, par3); + } + + public void mouseClicked(int mx, int my, int button) { + slider.mousePressed(mc, mx, my); + super.mouseClicked(mx, my, button); + } + + public void mouseMovedOrUp(int par1, int par2, int par3) { + if(par3 == 0) { + slider.mouseReleased(par1, par2); + } + super.mouseMovedOrUp(par1, par2, par3); + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/GuiScreenConnectOption.java b/src/main/java/net/lax1dude/eaglercraft/GuiScreenConnectOption.java new file mode 100644 index 0000000..bd795a0 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GuiScreenConnectOption.java @@ -0,0 +1,61 @@ +package net.lax1dude.eaglercraft; + +import net.minecraft.src.GuiButton; +import net.minecraft.src.GuiMultiplayer; +import net.minecraft.src.GuiScreen; +import net.minecraft.src.GuiScreenDirectConnect; +import net.minecraft.src.StringTranslate; + +public class GuiScreenConnectOption extends GuiScreen { + + private final GuiMultiplayer guiScreen; + private String title; + private String prompt; + + private final GuiNetworkSettingsButton relaysButton; + + public GuiScreenConnectOption(GuiMultiplayer guiScreen) { + this.guiScreen = guiScreen; + this.relaysButton = new GuiNetworkSettingsButton(this); + } + + public void initGui() { + StringTranslate var1 = StringTranslate.getInstance(); + title = var1.translateKey("selectServer.direct"); + prompt = var1.translateKey("directConnect.prompt"); + buttonList.clear(); + buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 - 60 + 90, var1.translateKey("directConnect.serverJoin"))); + buttonList.add(new GuiButton(2, this.width / 2 - 100, this.height / 4 - 60 + 115, var1.translateKey("directConnect.lanWorld"))); + buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 - 60 + 155, var1.translateKey("gui.cancel"))); + } + + protected void actionPerformed(GuiButton par1GuiButton) { + if(par1GuiButton.id == 0) { + mc.displayGuiScreen(guiScreen); + }else if(par1GuiButton.id == 1) { + mc.displayGuiScreen(new GuiScreenDirectConnect(guiScreen, guiScreen.getTheServerData())); + }else if(par1GuiButton.id == 2) { + GuiScreen scn = new GuiScreenLANConnect(guiScreen); + if(IntegratedServer.relayManager.count() == 0) { + mc.displayGuiScreen(new GuiScreenNoRelays(guiScreen, "noRelay.title")); + }else { + mc.displayGuiScreen(scn); + } + } + } + + public void drawScreen(int par1, int par2, float par3) { + StringTranslate var4 = StringTranslate.getInstance(); + this.drawDefaultBackground(); + this.drawCenteredString(this.fontRenderer, title, this.width / 2, this.height / 4 - 60 + 20, 16777215); + this.drawCenteredString(this.fontRenderer, prompt, this.width / 2, this.height / 4 - 60 + 55, 0x999999); + super.drawScreen(par1, par2, par3); + relaysButton.drawScreen(par1, par2); + } + + protected void mouseClicked(int par1, int par2, int par3) { + relaysButton.mouseClicked(par1, par2, par3); + super.mouseClicked(par1, par2, par3); + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/GuiScreenCreateWorldSelection.java b/src/main/java/net/lax1dude/eaglercraft/GuiScreenCreateWorldSelection.java new file mode 100644 index 0000000..cc2dac5 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GuiScreenCreateWorldSelection.java @@ -0,0 +1,68 @@ +package net.lax1dude.eaglercraft; + +import net.minecraft.src.GuiButton; +import net.minecraft.src.GuiCreateWorld; +import net.minecraft.src.GuiScreen; +import net.minecraft.src.StringTranslate; + +public class GuiScreenCreateWorldSelection extends GuiScreen { + + private GuiScreen mainmenu; + private GuiButton worldCreate = null; + private GuiButton worldImport = null; + private GuiButton worldVanilla = null; + private boolean isImportingEPK = false; + private boolean isImportingMCA = false; + + public GuiScreenCreateWorldSelection(GuiScreen mainmenu) { + this.mainmenu = mainmenu; + } + + public void initGui() { + StringTranslate var1 = StringTranslate.getInstance(); + this.buttonList.add(worldCreate = new GuiButton(1, this.width / 2 - 100, this.height / 4 + 40, var1.translateKey("selectWorld.create.create"))); + this.buttonList.add(worldImport = new GuiButton(2, this.width / 2 - 100, this.height / 4 + 65, var1.translateKey("selectWorld.create.import"))); + this.buttonList.add(worldVanilla = new GuiButton(3, this.width / 2 - 100, this.height / 4 + 90, var1.translateKey("selectWorld.create.vanilla"))); + this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 130, var1.translateKey("gui.cancel"))); + } + + public void updateScreen() { + if(EaglerAdapter.getFileChooserResultAvailable() && (isImportingEPK || isImportingMCA)) { + this.mc.displayGuiScreen(new GuiScreenNameWorldImport(mainmenu, EaglerAdapter.getFileChooserResultName(), isImportingEPK ? 0 : (isImportingMCA ? 1 : -1))); + isImportingEPK = isImportingMCA = false; + } + } + + public void drawScreen(int par1, int par2, float par3) { + StringTranslate var4 = StringTranslate.getInstance(); + this.drawDefaultBackground(); + + this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.create.title"), this.width / 2, this.height / 4, 16777215); + + int toolTipColor = 0xDDDDAA; + if(worldCreate.func_82252_a()) { + this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.create.create.tooltip"), this.width / 2, this.height / 4 + 20, toolTipColor); + }else if(worldImport.func_82252_a()) { + this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.create.import.tooltip"), this.width / 2, this.height / 4 + 20, toolTipColor); + }else if(worldVanilla.func_82252_a()) { + this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.create.vanilla.tooltip"), this.width / 2, this.height / 4 + 20, toolTipColor); + } + + super.drawScreen(par1, par2, par3); + } + + protected void actionPerformed(GuiButton par1GuiButton) { + if(par1GuiButton.id == 0) { + this.mc.displayGuiScreen(mainmenu); + }else if(par1GuiButton.id == 1) { + this.mc.displayGuiScreen(new GuiCreateWorld(mainmenu)); + }else if(par1GuiButton.id == 2) { + isImportingEPK = true; + EaglerAdapter.openFileChooser("epk", null); + }else if(par1GuiButton.id == 3) { + isImportingMCA = true; + EaglerAdapter.openFileChooser("zip", null); + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/GuiScreenEditCape.java b/src/main/java/net/lax1dude/eaglercraft/GuiScreenEditCape.java new file mode 100644 index 0000000..1e75b02 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GuiScreenEditCape.java @@ -0,0 +1,308 @@ +package net.lax1dude.eaglercraft; + +import net.lax1dude.eaglercraft.EaglerProfile.EaglerProfileCape; +import net.minecraft.src.GuiButton; +import net.minecraft.src.GuiScreen; +import net.minecraft.src.StringTranslate; + +public class GuiScreenEditCape extends GuiScreen { + + private boolean dropDownOpen = false; + private String[] dropDownOptions; + private int slotsVisible = 0; + private int selectedSlot = 0; + private int scrollPos = -1; + private int skinsHeight = 0; + private boolean dragging = false; + private int mousex = 0; + private int mousey = 0; + + public static final String[] defaultVanillaCapeNames = new String[] { + "No Cape", + "Minecon 2011", + "Minecon 2012", + "Minecon 2013", + "Minecon 2015", + "Minecon 2016", + "Microsoft Account", + "Realms Mapmaker", + "Mojang Old", + "Mojang New", + "Jira Moderator", + "Mojang Very Old", + "Scrolls", + "Cobalt", + "Lang Translator", + "Millionth Player", + "Prismarine", + "Snowman", + "Spade", + "Birthday", + "dB" + }; + + protected String screenTitle = "Select Cape"; + + private GuiScreen parent; + private int skinToShow; + + public GuiScreenEditCape(GuiScreen parent, int skinToShow) { + this.parent = parent; + this.skinToShow = skinToShow; + reconcatDD(); + this.selectedSlot = EaglerProfile.presetCapeId < 0 ? EaglerProfile.customCapeId : (EaglerProfile.presetCapeId + EaglerProfile.capes.size()); + } + + public void initGui() { + super.initGui(); + EaglerAdapter.enableRepeatEvents(true); + StringTranslate var1 = StringTranslate.getInstance(); + screenTitle = var1.translateKey("profile.capeTitle"); + this.buttonList.add(new GuiButton(200, this.width / 2 - 100, this.height / 6 + 168, var1.translateKey("gui.done"))); + this.buttonList.add(new GuiButton(2, this.width / 2 - 21, this.height / 6 + 81, 71, 20, var1.translateKey("profile.addCape"))); + this.buttonList.add(new GuiButton(3, this.width / 2 - 21 + 71, this.height / 6 + 81, 72, 20, var1.translateKey("profile.clearSkin"))); + } + + public void onGuiClosed() { + EaglerAdapter.enableRepeatEvents(false); + } + + private void reconcatDD() { + String[] n = new String[EaglerProfile.capes.size()]; + for(int i = 0; i < n.length; ++i) { + n[i] = EaglerProfile.capes.get(i).name; + } + + this.dropDownOptions = EaglerProfile.concatArrays(n, defaultVanillaCapeNames); + } + + private static final TextureLocation gui = new TextureLocation("/gui/gui.png"); + + public void drawScreen(int mx, int my, float par3) { + StringTranslate var1 = StringTranslate.getInstance(); + this.drawDefaultBackground(); + + this.drawCenteredString(this.fontRenderer, this.screenTitle, this.width / 2, 15, 16777215); + + this.drawString(this.fontRenderer, "Player Cape", this.width / 2 - 20, this.height / 6 + 37, 10526880); + mousex = mx; + mousey = my; + + int skinX = this.width / 2 - 120; + int skinY = this.height / 6 + 8; + int skinWidth = 80; + int skinHeight = 130; + + drawRect(skinX, skinY, skinX + skinWidth, skinY + skinHeight, -6250336); + drawRect(skinX + 1, skinY + 1, skinX + skinWidth - 1, skinY + skinHeight - 1, 0xff000015); + + if(dropDownOpen) { + super.drawScreen(-1, -1, par3); + }else { + super.drawScreen(mx, my, par3); + } + + skinX = this.width / 2 - 20; + skinY = this.height / 6 + 53; + skinWidth = 140; + skinHeight = 22; + + drawRect(skinX, skinY, skinX + skinWidth, skinY + skinHeight, -6250336); + drawRect(skinX + 1, skinY + 1, skinX + skinWidth - 21, skinY + skinHeight - 1, -16777216); + drawRect(skinX + skinWidth - 20, skinY + 1, skinX + skinWidth - 1, skinY + skinHeight - 1, -16777216); + + EaglerAdapter.glColor4f(1f, 1f, 1f, 1f); + gui.bindTexture(); + drawTexturedModalRect(skinX + skinWidth - 18, skinY + 3, 0, 240, 16, 16); + + this.fontRenderer.drawStringWithShadow(dropDownOptions[selectedSlot], skinX + 5, skinY + 7, 14737632); + + EaglerProfile.customCapeId = (selectedSlot < EaglerProfile.capes.size()) ? selectedSlot : -1; + EaglerProfile.presetCapeId = EaglerProfile.customCapeId < 0 ? (selectedSlot - EaglerProfile.capes.size()) : -1; + + skinX = this.width / 2 - 20; + skinY = this.height / 6 + 74; + skinWidth = 140; + skinHeight = (this.height - skinY - 4); + slotsVisible = (skinHeight / 10); + if(slotsVisible > dropDownOptions.length) slotsVisible = dropDownOptions.length; + skinHeight = slotsVisible * 10 + 7; + skinsHeight = skinHeight; + if(scrollPos == -1) { + scrollPos = selectedSlot - 2; + } + if(scrollPos > (dropDownOptions.length - slotsVisible)) { + scrollPos = (dropDownOptions.length - slotsVisible); + } + if(scrollPos < 0) { + scrollPos = 0; + } + if(dropDownOpen) { + drawRect(skinX, skinY, skinX + skinWidth, skinY + skinHeight, -6250336); + drawRect(skinX + 1, skinY + 1, skinX + skinWidth - 1, skinY + skinHeight - 1, -16777216); + for(int i = 0; i < slotsVisible; i++) { + if(i + scrollPos < dropDownOptions.length) { + int idx = i + scrollPos - EaglerProfile.capes.size(); + if(selectedSlot == i + scrollPos) { + drawRect(skinX + 1, skinY + i*10 + 4, skinX + skinWidth - 1, skinY + i*10 + 14, 0x77ffffff); + }else if(mx >= skinX && mx < (skinX + skinWidth - 10) && my >= (skinY + i*10 + 5) && my < (skinY + i*10 + 15)) { + drawRect(skinX + 1, skinY + i*10 + 4, skinX + skinWidth - 1, skinY + i*10 + 14, 0x55ffffff); + } + this.fontRenderer.drawStringWithShadow(dropDownOptions[i + scrollPos], skinX + 5, skinY + 5 + i*10, 14737632); + } + } + int scrollerSize = skinHeight * slotsVisible / dropDownOptions.length; + int scrollerPos = skinHeight * scrollPos / dropDownOptions.length; + drawRect(skinX + skinWidth - 4, skinY + scrollerPos + 1, skinX + skinWidth - 1, skinY + scrollerPos + scrollerSize, 0xff888888); + } + + int xx = this.width / 2 - 80; + int yy = this.height / 6 + 130; + + DefaultSkinRenderer.renderPlayerPreview(xx, yy, mx, my, skinToShow | 0x10000); + + } + + protected void actionPerformed(GuiButton par1GuiButton) { + if(!dropDownOpen) { + if(par1GuiButton.id == 200) { + mc.displayGuiScreen(parent); + }else if(par1GuiButton.id == 2) { + EaglerAdapter.openFileChooser("png", "image/png"); + }else if(par1GuiButton.id == 3) { + for(EaglerProfileCape i : EaglerProfile.capes) { + this.mc.renderEngine.deleteTexture(i.glTex); + } + EaglerProfile.capes.clear(); + this.dropDownOptions = defaultVanillaCapeNames; + this.selectedSlot = 0; + } + } + } + + public void updateScreen() { + if(dropDownOpen) { + if(EaglerAdapter.mouseIsButtonDown(0)) { + int skinX = this.width / 2 - 20; + int skinY = this.height / 6 + 74; + int skinWidth = 140; + if(mousex >= (skinX + skinWidth - 10) && mousex < (skinX + skinWidth) && mousey >= skinY && mousey < (skinY + skinsHeight)) { + dragging = true; + } + if(dragging) { + int scrollerSize = skinsHeight * slotsVisible / dropDownOptions.length; + scrollPos = (mousey - skinY - (scrollerSize / 2)) * dropDownOptions.length / skinsHeight; + } + }else { + dragging = false; + } + }else { + dragging = false; + } + + byte[] b; + if((b = EaglerAdapter.getFileChooserResult()) != null && b.length > 0) { + EaglerImage img = EaglerImage.loadImage(b); + + if(!((img.w == 32 && img.h == 32) || (img.w == 64 && img.h == 32))) return; + + int[] loadSkin = img.data; + if(img.w == 64 && img.h == 32) { + loadSkin = grabPiece(loadSkin, 32, 32, 64); + } + + byte[] rawSkin = new byte[loadSkin.length * 4]; + for(int i = 0; i < loadSkin.length; i++) { + int i2 = i * 4; int i3 = loadSkin[i]; + rawSkin[i2] = (byte)(i3); + rawSkin[i2 + 1] = (byte)(i3 >> 8); + rawSkin[i2 + 2] = (byte)(i3 >> 16); + rawSkin[i2 + 3] = (byte)(i3 >> 24); + } + String name = EaglerAdapter.getFileChooserResultName(); + if(name.length() > 32) { + name = name.substring(0, 32); + } + int k; + if((k = EaglerProfile.addCape(name, rawSkin)) != -1) { + selectedSlot = k; + reconcatDD(); + } + } + } + + private int[] grabPiece(int[] input, int w, int h, int sw) { + int[] ret = new int[w * h]; + for(int i = 0; i < h; ++i) { + System.arraycopy(input, i * sw, ret, i * w, w); + } + return ret; + } + + public void handleMouseInput() { + super.handleMouseInput(); + if(dropDownOpen) { + int var1 = EaglerAdapter.mouseGetEventDWheel(); + if(var1 < 0) { + scrollPos += 3; + } + if(var1 > 0) { + scrollPos -= 3; + if(scrollPos < 0) { + scrollPos = 0; + } + } + } + } + + protected void keyTyped(char par1, int par2) { + if(par2 == 200 && selectedSlot > 0) { + --selectedSlot; + scrollPos = selectedSlot - 2; + } + if(par2 == 208 && selectedSlot < (dropDownOptions.length - 1)) { + ++selectedSlot; + scrollPos = selectedSlot - 2; + } + } + + protected void mouseClicked(int par1, int par2, int par3) { + super.mouseClicked(par1, par2, par3); + + if (par3 == 0) { + int skinX = this.width / 2 + 140 - 40; + int skinY = this.height / 6 + 53; + + if(par1 >= skinX && par1 < (skinX + 20) && par2 >= skinY && par2 < (skinY + 22)) { + dropDownOpen = !dropDownOpen; + } + + skinX = this.width / 2 - 20; + skinY = this.height / 6 + 53; + int skinWidth = 140; + int skinHeight = skinsHeight; + + if(!(par1 >= skinX && par1 < (skinX + skinWidth) && par2 >= skinY && par2 < (skinY + skinHeight + 22))) { + dropDownOpen = false; + dragging = false; + } + + skinY += 21; + + if(dropDownOpen && !dragging) { + for(int i = 0; i < slotsVisible; i++) { + if(i + scrollPos < dropDownOptions.length) { + if(selectedSlot != i + scrollPos) { + if(par1 >= skinX && par1 < (skinX + skinWidth - 10) && par2 >= (skinY + i*10 + 5) && par2 < (skinY + i*10 + 15) && selectedSlot != i + scrollPos) { + selectedSlot = i + scrollPos; + dropDownOpen = false; + dragging = false; + } + } + } + } + } + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/GuiScreenEditProfile.java b/src/main/java/net/lax1dude/eaglercraft/GuiScreenEditProfile.java new file mode 100644 index 0000000..e01f730 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GuiScreenEditProfile.java @@ -0,0 +1,547 @@ +package net.lax1dude.eaglercraft; + +import net.lax1dude.eaglercraft.EaglerProfile.EaglerProfileSkin; +import net.minecraft.src.EnumChatFormatting; +import net.minecraft.src.GuiButton; +import net.minecraft.src.GuiScreen; +import net.minecraft.src.GuiTextField; +import net.minecraft.src.NBTTagCompound; +import net.minecraft.src.StringTranslate; + +public class GuiScreenEditProfile extends GuiScreen { + + private GuiScreen parent; + private GuiTextField username; + + private boolean dropDownOpen = false; + private String[] dropDownOptions; + private int slotsVisible = 0; + private int selectedSlot = 0; + private int newSkinNotificationIndexCurrent = 0; + private int scrollPos = -1; + private int skinsHeight = 0; + private boolean dragging = false; + private int mousex = 0; + private int mousey = 0; + + private boolean newSkinWaitSteveOrAlex = false; + + private static final TextureLocation gui = new TextureLocation("/gui/gui.png"); + + public static final String[] defaultOptions = new String[] { + "Default Steve", + "Default Alex", + "Tennis Steve", + "Tennis Alex", + "Tuxedo Steve", + "Tuxedo Alex", + "Athlete Steve", + "Athlete Alex", + "Cyclist Steve", + "Cyclist Alex", + "Boxer Steve", + "Boxer Alex", + "Prisoner Steve", + "Prisoner Alex", + "Scottish Steve", + "Scottish Alex", + "Developer Steve", + "Developer Alex", + "Herobrine", + "Enderman", + "Skeleton", + "Blaze", + "Barney", + "Slime", + "Noob", + "Trump", + "Notch", + "Creeper", + "Zombie", + "Pig", + "Squid", + "Mooshroom", + "Villager", + "Long Arms", + "Weird Climber", + "Laxative Dude", + "Baby Charles", + "Baby Winston" + }; + + public static final int newDefaultNotice = defaultOptions.length - 5; + + protected String screenTitle = "Edit Profile"; + + public GuiScreenEditProfile(GuiScreen parent) { + this.parent = parent; + newSkinNotificationIndexCurrent = EaglerProfile.newSkinNotificationIndex; + reconcatDD(); + } + + private void reconcatDD() { + String[] n = new String[EaglerProfile.skins.size()]; + for(int i = 0; i < n.length; ++i) { + n[i] = EaglerProfile.skins.get(i).name; + } + + this.dropDownOptions = EaglerProfile.concatArrays(n, defaultOptions); + } + + private GuiButton button0, button1, button2, button10, button11, button12; + + public void initGui() { + super.initGui(); + EaglerAdapter.enableRepeatEvents(true); + StringTranslate var1 = StringTranslate.getInstance(); + this.screenTitle = var1.translateKey("profile.title"); + this.username = new GuiTextField(this.fontRenderer, this.width / 2 - 20 + 1, this.height / 6 + 24 + 1, 138, 20); + this.username.setFocused(true); + this.username.setText(EaglerProfile.username); + selectedSlot = EaglerProfile.presetSkinId == -1 ? EaglerProfile.customSkinId : (EaglerProfile.presetSkinId + EaglerProfile.skins.size()); + //this.buttonList.add(new GuiButton(0, this.width / 2 - 100, 140, "eeeee")); + this.buttonList.add(button0 = new GuiButton(200, this.width / 2 - 100, this.height / 6 + 168, var1.translateKey("gui.done"))); + this.buttonList.add(button1 = new GuiButton(2, this.width / 2 - 21, this.height / 6 + 110, 71, 20, var1.translateKey("profile.addSkin"))); + this.buttonList.add(button2 = new GuiButton(3, this.width / 2 - 21 + 71, this.height / 6 + 110, 72, 20, var1.translateKey("profile.clearSkin"))); + //this.buttonList.add(new GuiButton(200, this.width / 2, this.height / 6 + 72, 150, 20, var1.translateKey("gui.done"))); + } + + public void drawScreen(int mx, int my, float par3) { + StringTranslate var1 = StringTranslate.getInstance(); + this.drawDefaultBackground(); + this.drawCenteredString(this.fontRenderer, this.screenTitle, this.width / 2, 15, 16777215); + this.drawString(this.fontRenderer, var1.translateKey("profile.screenname"), this.width / 2 - 20, this.height / 6 + 8, 10526880); + + newSkinNotificationIndexCurrent = 23948923; + int cnt = defaultOptions.length - newSkinNotificationIndexCurrent; + if(cnt <= 0) { + this.drawString(this.fontRenderer, var1.translateKey("profile.playerSkin"), this.width / 2 - 20, this.height / 6 + 66, 10526880); + } + mousex = mx; + mousey = my; + + int skinX = this.width / 2 - 120; + int skinY = this.height / 6 + 8; + int skinWidth = 80; + int skinHeight = 130; + + drawRect(skinX, skinY, skinX + skinWidth, skinY + skinHeight, -6250336); + drawRect(skinX + 1, skinY + 1, skinX + skinWidth - 1, skinY + skinHeight - 1, 0xff000015); + + EaglerAdapter.glPushMatrix(); + EaglerAdapter.glTranslatef(skinX + 2, skinY - 9, 0.0f); + EaglerAdapter.glScalef(0.75f, 0.75f, 0.75f); + + int skid = selectedSlot - EaglerProfile.skins.size(); + if(skid < 0) { + skid = 0; + } + if(DefaultSkinRenderer.isStandardModel(skid) || DefaultSkinRenderer.isZombieModel(skid)) { + String capesText = var1.translateKey("profile.capes"); + int color = 10526880; + if(mx > skinX - 10 && my > skinY - 16 && mx < skinX + (fontRenderer.getStringWidth(capesText) / 0.75f) + 10 && my < skinY + 7) { + color = 0xFFCCCC44; + } + this.drawString(this.fontRenderer, EnumChatFormatting.UNDERLINE + capesText, 0, 0, color); + } + + EaglerAdapter.glPopMatrix(); + + this.username.drawTextBox(); + if(dropDownOpen || newSkinWaitSteveOrAlex) { + super.drawScreen(0, 0, par3); + }else { + super.drawScreen(mx, my, par3); + } + + skinX = this.width / 2 - 20; + skinY = this.height / 6 + 82; + skinWidth = 140; + skinHeight = 22; + + drawRect(skinX, skinY, skinX + skinWidth, skinY + skinHeight, -6250336); + drawRect(skinX + 1, skinY + 1, skinX + skinWidth - 21, skinY + skinHeight - 1, -16777216); + drawRect(skinX + skinWidth - 20, skinY + 1, skinX + skinWidth - 1, skinY + skinHeight - 1, -16777216); + + EaglerAdapter.glColor4f(1f, 1f, 1f, 1f); + gui.bindTexture(); + drawTexturedModalRect(skinX + skinWidth - 18, skinY + 3, 0, 240, 16, 16); + + this.fontRenderer.drawStringWithShadow(dropDownOptions[selectedSlot], skinX + 5, skinY + 7, 14737632); + + if(cnt > 0) { + EaglerAdapter.glPushMatrix(); + EaglerAdapter.glTranslatef(skinX, skinY - 11, 0.0f); + EaglerAdapter.glScalef(0.9f, 0.9f, 0.9f); + drawString(fontRenderer, "" + cnt + " new skin" + (cnt != 1 ? "" : "s") + " have been added:", 0, 0, 0xFFDDDDAA); + EaglerAdapter.glPopMatrix(); + } + + skinX = this.width / 2 - 20; + skinY = this.height / 6 + 103; + skinWidth = 140; + skinHeight = (this.height - skinY - 10); + slotsVisible = (skinHeight / 10); + if(slotsVisible > dropDownOptions.length) slotsVisible = dropDownOptions.length; + skinHeight = slotsVisible * 10 + 7; + skinsHeight = skinHeight; + if(scrollPos == -1) { + scrollPos = selectedSlot - 2; + } + if(scrollPos > (dropDownOptions.length - slotsVisible)) { + scrollPos = (dropDownOptions.length - slotsVisible); + } + if(scrollPos < 0) { + scrollPos = 0; + } + if(dropDownOpen) { + drawRect(skinX, skinY, skinX + skinWidth, skinY + skinHeight, -6250336); + drawRect(skinX + 1, skinY + 1, skinX + skinWidth - 1, skinY + skinHeight - 1, -16777216); + for(int i = 0; i < slotsVisible; i++) { + if(i + scrollPos < dropDownOptions.length) { + int idx = i + scrollPos - EaglerProfile.skins.size(); + if(idx >= newSkinNotificationIndexCurrent) { + drawRect(skinX + 1, skinY + i*10 + 4, skinX + skinWidth - 1, skinY + i*10 + 14, 0x77ffdd88); + } + if(selectedSlot == i + scrollPos) { + drawRect(skinX + 1, skinY + i*10 + 4, skinX + skinWidth - 1, skinY + i*10 + 14, 0x77ffffff); + }else if(mx >= skinX && mx < (skinX + skinWidth - 10) && my >= (skinY + i*10 + 5) && my < (skinY + i*10 + 15)) { + drawRect(skinX + 1, skinY + i*10 + 4, skinX + skinWidth - 1, skinY + i*10 + 14, 0x55ffffff); + } + this.fontRenderer.drawStringWithShadow(dropDownOptions[i + scrollPos], skinX + 5, skinY + 5 + i*10, 14737632); + if(EaglerProfile.newSkinNotificationIndex <= idx) { + EaglerProfile.newSkinNotificationIndex = idx + 1; + } + } + } + int scrollerSize = skinHeight * slotsVisible / dropDownOptions.length; + int scrollerPos = skinHeight * scrollPos / dropDownOptions.length; + drawRect(skinX + skinWidth - 4, skinY + scrollerPos + 1, skinX + skinWidth - 1, skinY + scrollerPos + scrollerSize, 0xff888888); + } + + int xx = this.width / 2 - 80; + int yy = this.height / 6 + 130; + + if(newSkinWaitSteveOrAlex && selectedSlot < EaglerProfile.skins.size()) { + skinWidth = 70; + skinHeight = 120; + + EaglerProfile.EaglerProfileSkin eee = EaglerProfile.skins.get(selectedSlot); + + EaglerAdapter.glClear(EaglerAdapter.GL_DEPTH_BUFFER_BIT); + + skinX = this.width / 2 - 90; + skinY = this.height / 4; + xx = skinX + 35; + yy = skinY + 117; + + boolean mouseOver = mx >= skinX && my >= skinY && mx < skinX + skinWidth && my < skinY + skinHeight; + int cc = mouseOver ? 0xFFDDDD99 : 0xFF555555; + + EaglerAdapter.glEnable(EaglerAdapter.GL_BLEND); + EaglerAdapter.glBlendFunc(EaglerAdapter.GL_SRC_ALPHA, EaglerAdapter.GL_ONE_MINUS_SRC_ALPHA); + drawRect(0, 0, width, height, 0xbb000000); + drawRect(skinX, skinY, skinX + skinWidth, skinY + skinHeight, 0xbb000000); + EaglerAdapter.glDisable(EaglerAdapter.GL_BLEND); + + drawRect(skinX, skinY, skinX + 1, skinY + skinHeight, cc); + drawRect(skinX, skinY, skinX + skinWidth, skinY + 1, cc); + drawRect(skinX + skinWidth - 1, skinY, skinX + skinWidth, skinY + skinHeight, cc); + drawRect(skinX, skinY + skinHeight - 1, skinX + skinWidth, skinY + skinHeight, cc); + + if(mouseOver) { + drawCenteredString(fontRenderer, "Steve", skinX + skinWidth / 2, skinY + skinHeight + 6, cc); + } + + this.mc.renderEngine.bindTexture(eee.glTex); + DefaultSkinRenderer.renderAlexOrSteve(xx, yy, mx, my, false); + + skinX = this.width / 2 + 20; + skinY = this.height / 4; + xx = skinX + 35; + yy = skinY + 117; + + mouseOver = mx >= skinX && my >= skinY && mx < skinX + skinWidth && my < skinY + skinHeight; + cc = mouseOver ? 0xFFDDDD99 : 0xFF555555; + + EaglerAdapter.glEnable(EaglerAdapter.GL_BLEND); + drawRect(skinX, skinY, skinX + skinWidth, skinY + skinHeight, 0xbb000000); + EaglerAdapter.glDisable(EaglerAdapter.GL_BLEND); + + drawRect(skinX, skinY, skinX + 1, skinY + skinHeight, cc); + drawRect(skinX, skinY, skinX + skinWidth, skinY + 1, cc); + drawRect(skinX + skinWidth - 1, skinY, skinX + skinWidth, skinY + skinHeight, cc); + drawRect(skinX, skinY + skinHeight - 1, skinX + skinWidth, skinY + skinHeight, cc); + + if(mouseOver) { + drawCenteredString(fontRenderer, "Alex", skinX + skinWidth / 2, skinY + skinHeight + 8, cc); + } + + this.mc.renderEngine.bindTexture(eee.glTex); + DefaultSkinRenderer.renderAlexOrSteve(xx, yy, mx, my, true); + }else { + skinX = this.width / 2 - 120; + skinY = this.height / 6 + 8; + skinWidth = 80; + skinHeight = 130; + if(DefaultSkinRenderer.isPlayerPreviewNew(selectedSlot)) { + int w = fontRenderer.getStringWidth("1.8") + 4; + EaglerAdapter.glPushMatrix(); + EaglerAdapter.glScalef(0.75f, 0.75f, 0.75f); + drawString(fontRenderer, "1.8", (int)((skinX + skinWidth) / 0.75f) - w, (int)((skinY + skinHeight) / 0.75f) - 12, 0xFFBBBB66); + EaglerAdapter.glPopMatrix(); + } + DefaultSkinRenderer.renderPlayerPreview(xx, yy, newSkinWaitSteveOrAlex ? width / 2 : mx, newSkinWaitSteveOrAlex ? height / 2 : my, selectedSlot); + } + + } + + public void handleMouseInput() { + super.handleMouseInput(); + if(dropDownOpen) { + int var1 = EaglerAdapter.mouseGetEventDWheel(); + if(var1 < 0) { + scrollPos += 3; + } + if(var1 > 0) { + scrollPos -= 3; + if(scrollPos < 0) { + scrollPos = 0; + } + } + } + } + + private void save() { + EaglerProfile.username = this.username.getText().length() == 0 ? "null" : this.username.getText(); + EaglerProfile.presetSkinId = selectedSlot - EaglerProfile.skins.size(); + if(EaglerProfile.presetSkinId < 0) { + EaglerProfile.presetSkinId = -1; + EaglerProfile.customSkinId = selectedSlot; + }else { + EaglerProfile.customSkinId = -1; + } + + LocalStorageManager.profileSettingsStorage.setInteger("ps", EaglerProfile.presetSkinId); + LocalStorageManager.profileSettingsStorage.setInteger("cs", EaglerProfile.customSkinId); + LocalStorageManager.profileSettingsStorage.setInteger("pc", EaglerProfile.presetCapeId); + LocalStorageManager.profileSettingsStorage.setInteger("cc", EaglerProfile.customCapeId); + LocalStorageManager.profileSettingsStorage.setInteger("nsi", EaglerProfile.newSkinNotificationIndex); + LocalStorageManager.profileSettingsStorage.setString("name", EaglerProfile.username); + + NBTTagCompound skins = new NBTTagCompound(); + for(int i = 0, l = EaglerProfile.skins.size(); i < l; i++) { + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setByteArray("data", EaglerProfile.skins.get(i).data); + nbt.setBoolean("slim", EaglerProfile.skins.get(i).slim); + skins.setTag(EaglerProfile.skins.get(i).name, nbt); + } + LocalStorageManager.profileSettingsStorage.setCompoundTag("skins", skins); + + NBTTagCompound capes = new NBTTagCompound(); + for(int i = 0, l = EaglerProfile.capes.size(); i < l; i++) { + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setByteArray("data", EaglerProfile.capes.get(i).data); + capes.setTag(EaglerProfile.capes.get(i).name, nbt); + } + LocalStorageManager.profileSettingsStorage.setCompoundTag("capes", capes); + + LocalStorageManager.saveStorageP(); + } + + protected void actionPerformed(GuiButton par1GuiButton) { + if(!dropDownOpen) { + if(par1GuiButton.id == 200) { + save(); + this.mc.displayGuiScreen((GuiScreen) parent); + }else if(par1GuiButton.id == 2) { + EaglerAdapter.openFileChooser("png", "image/png"); + }else if(par1GuiButton.id == 3) { + for(EaglerProfileSkin i : EaglerProfile.skins) { + this.mc.renderEngine.deleteTexture(i.glTex); + } + EaglerProfile.skins.clear(); + this.dropDownOptions = defaultOptions; + this.selectedSlot = 0; + save(); + } + } + } + + public void updateScreen() { + this.username.updateCursorCounter(); + + if(dropDownOpen) { + if(EaglerAdapter.mouseIsButtonDown(0)) { + int skinX = this.width / 2 - 20; + int skinY = this.height / 6 + 103; + int skinWidth = 140; + if(mousex >= (skinX + skinWidth - 10) && mousex < (skinX + skinWidth) && mousey >= skinY && mousey < (skinY + skinsHeight)) { + dragging = true; + } + if(dragging) { + int scrollerSize = skinsHeight * slotsVisible / dropDownOptions.length; + scrollPos = (mousey - skinY - (scrollerSize / 2)) * dropDownOptions.length / skinsHeight; + } + }else { + dragging = false; + } + }else { + dragging = false; + } + + byte[] b; + if((b = EaglerAdapter.getFileChooserResult()) != null && b.length > 0) { + EaglerImage img = EaglerImage.loadImage(b); + if(!((img.w == 64 && img.h == 32) || (img.w == 64 && img.h == 64))) return; + byte[] rawSkin = new byte[img.data.length * 4]; + for(int i = 0; i < img.data.length; i++) { + int i2 = i * 4; int i3 = img.data[i]; + rawSkin[i2] = (byte)(i3); + rawSkin[i2 + 1] = (byte)(i3 >> 8); + rawSkin[i2 + 2] = (byte)(i3 >> 16); + rawSkin[i2 + 3] = (byte)(i3 >> 24); + } + String name = EaglerAdapter.getFileChooserResultName(); + if(name.length() > 32) { + name = name.substring(0, 32); + } + if(img.w == 64 && img.h == 64) { + newSkinWaitSteveOrAlex = true; + } + int k; + if((k = EaglerProfile.addSkin(name, rawSkin, false)) != -1) { + selectedSlot = k; + reconcatDD(); + save(); + } + } + } + + public void onGuiClosed() { + EaglerAdapter.enableRepeatEvents(false); + } + + + protected void keyTyped(char par1, int par2) { + this.username.textboxKeyTyped(par1, par2); + + String text = username.getText(); + if(text.length() > 16) text = text.substring(0, 16); + text = text.replaceAll("[^A-Za-z0-9\\-_]", "_"); + this.username.setText(text); + + if(par2 == 200 && selectedSlot > 0) { + --selectedSlot; + scrollPos = selectedSlot - 2; + } + if(par2 == 208 && selectedSlot < (dropDownOptions.length - 1)) { + ++selectedSlot; + scrollPos = selectedSlot - 2; + } + } + + protected void mouseClicked(int par1, int par2, int par3) { + if(newSkinWaitSteveOrAlex) { + int skinX = this.width / 2 - 90; + int skinY = this.height / 4; + int skinWidth = 70; + int skinHeight = 120; + if(par1 >= skinX && par2 >= skinY && par1 < skinX + skinWidth && par2 < skinY + skinHeight) { + if(selectedSlot < EaglerProfile.skins.size()) { + newSkinWaitSteveOrAlex = false; + EaglerProfile.skins.get(selectedSlot).slim = false; + save(); + } + return; + } + skinX = this.width / 2 + 20; + skinY = this.height / 4; + if(par1 >= skinX && par2 >= skinY && par1 < skinX + skinWidth && par2 < skinY + skinHeight) { + if(selectedSlot < EaglerProfile.skins.size()) { + EaglerProfile.skins.get(selectedSlot).slim = true; + newSkinWaitSteveOrAlex = false; + save(); + } + } + return; + }else if(selectedSlot < EaglerProfile.skins.size()) { + int skinX = this.width / 2 - 120; + int skinY = this.height / 6 + 18; + int skinWidth = 80; + int skinHeight = 120; + if(par1 >= skinX && par2 >= skinY && par1 < skinX + skinWidth && par2 < skinY + skinHeight) { + if(selectedSlot < EaglerProfile.skins.size()) { + int type = EaglerProfile.getSkinSize(EaglerProfile.skins.get(selectedSlot).data.length); + if(type == 1 || type == 3) { + newSkinWaitSteveOrAlex = true; + return; + } + } + } + } + super.mouseClicked(par1, par2, par3); + this.username.mouseClicked(par1, par2, par3); + if (par3 == 0) { + int skinX = this.width / 2 + 140 - 40; + int skinY = this.height / 6 + 82; + + if(par1 >= skinX && par1 < (skinX + 20) && par2 >= skinY && par2 < (skinY + 22)) { + dropDownOpen = !dropDownOpen; + if(!dropDownOpen) { + //newSkinNotificationIndexCurrent = EaglerProfile.newSkinNotificationIndex; + } + } + + skinX = this.width / 2 - 20; + skinY = this.height / 6 + 82; + int skinWidth = 140; + int skinHeight = skinsHeight; + + if(!(par1 >= skinX && par1 < (skinX + skinWidth) && par2 >= skinY && par2 < (skinY + skinHeight + 22))) { + dropDownOpen = false; + dragging = false; + if(!dropDownOpen) { + //newSkinNotificationIndexCurrent = EaglerProfile.newSkinNotificationIndex; + } + } + + skinY += 21; + + if(dropDownOpen && !dragging) { + for(int i = 0; i < slotsVisible; i++) { + if(i + scrollPos < dropDownOptions.length) { + if(selectedSlot != i + scrollPos) { + if(par1 >= skinX && par1 < (skinX + skinWidth - 10) && par2 >= (skinY + i*10 + 5) && par2 < (skinY + i*10 + 15) && selectedSlot != i + scrollPos) { + selectedSlot = i + scrollPos; + dropDownOpen = false; + dragging = false; + if(!dropDownOpen) { + //newSkinNotificationIndexCurrent = EaglerProfile.newSkinNotificationIndex; + } + } + } + } + } + } + + int skid = selectedSlot - EaglerProfile.skins.size(); + if(skid < 0) { + skid = 0; + } + if(DefaultSkinRenderer.isStandardModel(skid) || DefaultSkinRenderer.isZombieModel(skid)) { + skinX = this.width / 2 - 120; + skinY = this.height / 6 + 8; + String capesText = StringTranslate.getInstance().translateKey("profile.capes"); + if(par1 > skinX - 10 && par2 > skinY - 16 && par1 < skinX + (fontRenderer.getStringWidth(capesText) / 0.75f) + 10 && par2 < skinY + 7) { + save(); + this.mc.sndManager.playSoundFX("random.click", 1.0F, 1.0F); + this.mc.displayGuiScreen(new GuiScreenEditCape(this, selectedSlot)); + } + } + } + } + + + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/GuiScreenLANConnect.java b/src/main/java/net/lax1dude/eaglercraft/GuiScreenLANConnect.java new file mode 100644 index 0000000..b2d2309 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GuiScreenLANConnect.java @@ -0,0 +1,77 @@ +package net.lax1dude.eaglercraft; + +import net.minecraft.src.GuiButton; +import net.minecraft.src.GuiScreen; +import net.minecraft.src.GuiTextField; +import net.minecraft.src.StringTranslate; + +public class GuiScreenLANConnect extends GuiScreen { + + private final GuiScreen parent; + private GuiTextField codeTextField; + private final GuiNetworkSettingsButton relaysButton; + + private static String lastCode = ""; + + public GuiScreenLANConnect(GuiScreen parent) { + this.parent = parent; + this.relaysButton = new GuiNetworkSettingsButton(this); + } + + public void initGui() { + StringTranslate var1 = StringTranslate.getInstance(); + EaglerAdapter.enableRepeatEvents(true); + this.buttonList.clear(); + this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 96 + 12, var1.translateKey("directConnect.lanWorldJoin"))); + this.buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 + 120 + 12, var1.translateKey("gui.cancel"))); + this.codeTextField = new GuiTextField(this.fontRenderer, this.width / 2 - 100, this.height / 4 + 27, 200, 20); + this.codeTextField.setMaxStringLength(48); + this.codeTextField.setFocused(true); + this.codeTextField.setText(lastCode); + ((GuiButton) this.buttonList.get(0)).enabled = this.codeTextField.getText().trim().length() > 0; + } + + public void onGuiClosed() { + EaglerAdapter.enableRepeatEvents(false); + lastCode = this.codeTextField.getText().trim(); + } + + protected void keyTyped(char par1, int par2) { + if (this.codeTextField.textboxKeyTyped(par1, par2)) { + ((GuiButton) this.buttonList.get(0)).enabled = this.codeTextField.getText().trim().length() > 0; + } else if (par2 == 28) { + this.actionPerformed((GuiButton) this.buttonList.get(0)); + } + } + + public void updateScreen() { + this.codeTextField.updateCursorCounter(); + } + + protected void mouseClicked(int par1, int par2, int par3) { + super.mouseClicked(par1, par2, par3); + this.codeTextField.mouseClicked(par1, par2, par3); + this.relaysButton.mouseClicked(par1, par2, par3); + } + + public void drawScreen(int xx, int yy, float pt) { + StringTranslate var4 = StringTranslate.getInstance(); + this.drawDefaultBackground(); + this.drawCenteredString(this.fontRenderer, var4.translateKey("selectServer.direct"), this.width / 2, this.height / 4 - 60 + 20, 16777215); + this.drawString(this.fontRenderer, var4.translateKey("directConnect.lanWorldCode"), this.width / 2 - 100, this.height / 4 + 12, 10526880); + this.drawCenteredString(this.fontRenderer, var4.translateKey("directConnect.networkSettingsNote"), this.width / 2, this.height / 4 + 63, 10526880); + this.drawCenteredString(this.fontRenderer, var4.translateKey("directConnect.ipGrabNote"), this.width / 2, this.height / 4 + 77, 10526880); + this.codeTextField.drawTextBox(); + super.drawScreen(xx, yy, pt); + this.relaysButton.drawScreen(xx, yy); + } + + protected void actionPerformed(GuiButton par1GuiButton) { + if(par1GuiButton.id == 1) { + mc.displayGuiScreen(parent); + }else if(par1GuiButton.id == 0) { + mc.displayGuiScreen(new GuiScreenLANConnecting(parent, this.codeTextField.getText().trim())); + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/GuiScreenLANConnecting.java b/src/main/java/net/lax1dude/eaglercraft/GuiScreenLANConnecting.java new file mode 100644 index 0000000..eebfe56 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GuiScreenLANConnecting.java @@ -0,0 +1,96 @@ +package net.lax1dude.eaglercraft; + +import java.io.IOException; + +import net.minecraft.src.GuiDisconnected; +import net.minecraft.src.GuiScreen; +import net.minecraft.src.LoadingScreenRenderer; +import net.minecraft.src.NetClientHandler; +import net.minecraft.src.Packet250CustomPayload; +import net.minecraft.src.Packet2ClientProtocol; +import net.minecraft.src.StringTranslate; + +public class GuiScreenLANConnecting extends GuiScreen { + + private final GuiScreen parent; + private final String code; + private final RelayServer relay; + + private boolean completed = false; + + private NetClientHandler netHandler = null; + + private int renderCount = 0; + + public GuiScreenLANConnecting(GuiScreen parent, String code) { + this.parent = parent; + this.code = code; + this.relay = null; + } + + public GuiScreenLANConnecting(GuiScreen parent, String code, RelayServer relay) { + this.parent = parent; + this.code = code; + this.relay = relay; + } + + public boolean doesGuiPauseGame() { + return false; + } + + public void updateScreen() { + if(netHandler != null) { + netHandler.processReadPackets(); + } + } + + public void drawScreen(int par1, int par2, float par3) { + this.drawDefaultBackground(); + StringTranslate st = StringTranslate.getInstance(); + if(completed) { + String message = st.translateKey("connect.authorizing"); + this.drawString(fontRenderer, message, (this.width - this.fontRenderer.getStringWidth(message)) / 2, this.height / 3 + 10, 0xFFFFFF); + }else { + LoadingScreenRenderer ls = mc.loadingScreen; + + String message = st.translateKey("lanServer.pleaseWait"); + this.drawString(fontRenderer, message, (this.width - this.fontRenderer.getStringWidth(message)) / 2, this.height / 3 + 10, 0xFFFFFF); + + if(++renderCount > 1) { + RelayServerSocket sock; + if(relay == null) { + sock = IntegratedServer.relayManager.getWorkingRelay((str) -> ls.resetProgresAndWorkingMessage("Connecting: " + str), 0x02, code); + }else { + sock = IntegratedServer.relayManager.connectHandshake(relay, 0x02, code); + } + if(sock == null) { + this.mc.displayGuiScreen(new GuiScreenNoRelays(parent, st.translateKey("noRelay.worldNotFound1").replace("$code$", code), + st.translateKey("noRelay.worldNotFound2").replace("$code$", code), st.translateKey("noRelay.worldNotFound3"))); + return; + } + + LANClientNetworkManager netMgr = LANClientNetworkManager.connectToWorld(sock, code, sock.getURI()); + if(netMgr == null) { + this.mc.displayGuiScreen(new GuiDisconnected(parent, "connect.failed", "disconnect.genericReason", st.translateKey("noRelay.worldFail").replace("$code$", code), "")); + return; + } + + completed = true; + + try { + netHandler = new NetClientHandler(mc, netMgr); + this.mc.setNetManager(netMgr); + netMgr.setNetHandler(netHandler); + netHandler.addToSendQueue(new Packet2ClientProtocol(61, EaglerProfile.username, "127.0.0.1", mc.gameSettings.renderDistance)); + netHandler.addToSendQueue(new Packet250CustomPayload("EAG|MySkin", EaglerProfile.getSkinPacket())); + netHandler.addToSendQueue(new Packet250CustomPayload("EAG|MyCape", EaglerProfile.getCapePacket())); + } catch (IOException e) { + this.mc.displayGuiScreen(new GuiDisconnected(parent, "connect.failed", "disconnect.genericReason", "could not create nethandler", "")); + e.printStackTrace(); + return; + } + } + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/GuiScreenNameWorldImport.java b/src/main/java/net/lax1dude/eaglercraft/GuiScreenNameWorldImport.java new file mode 100644 index 0000000..7aded44 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GuiScreenNameWorldImport.java @@ -0,0 +1,123 @@ +package net.lax1dude.eaglercraft; + +import net.minecraft.src.GuiButton; +import net.minecraft.src.GuiCreateWorld; +import net.minecraft.src.GuiScreen; +import net.minecraft.src.GuiTextField; +import net.minecraft.src.StringTranslate; + +public class GuiScreenNameWorldImport extends GuiScreen { + private GuiScreen parentGuiScreen; + private GuiTextField theGuiTextField; + private int importFormat; + private String name; + private String oldName; + private boolean timeToImport = false; + private boolean definetlyTimeToImport = false; + private boolean isImporting = false; + + public GuiScreenNameWorldImport(GuiScreen menu, String name, int format) { + this.parentGuiScreen = menu; + this.importFormat = format; + this.oldName = name; + if(name.length() > 4 && (name.endsWith(".epk") || name.endsWith(".zip"))) { + name = name.substring(0, name.length() - 4); + } + this.name = name; + } + + /** + * Called from the main game loop to update the screen. + */ + public void updateScreen() { + if(!timeToImport) { + this.theGuiTextField.updateCursorCounter(); + } + if(definetlyTimeToImport && !isImporting) { + isImporting = true; + IntegratedServer.importWorld(GuiCreateWorld.makeUsableName(this.theGuiTextField.getText().trim()), EaglerAdapter.getFileChooserResult(), importFormat); + mc.displayGuiScreen(new GuiScreenSingleplayerLoading(parentGuiScreen, "selectWorld.progress.importing." + importFormat, () -> IntegratedServer.isReady())); + } + } + + /** + * Adds the buttons (and other controls) to the screen in question. + */ + public void initGui() { + if(!timeToImport) { + StringTranslate var1 = StringTranslate.getInstance(); + EaglerAdapter.enableRepeatEvents(true); + this.buttonList.clear(); + this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 96 + 12, var1.translateKey("selectWorld.progress.continue"))); + this.buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 + 120 + 12, var1.translateKey("gui.cancel"))); + this.theGuiTextField = new GuiTextField(this.fontRenderer, this.width / 2 - 100, this.height / 4 + 3, 200, 20); + this.theGuiTextField.setFocused(true); + this.theGuiTextField.setText(name); + } + } + + /** + * Called when the screen is unloaded. Used to disable keyboard repeat events + */ + public void onGuiClosed() { + EaglerAdapter.enableRepeatEvents(false); + } + + /** + * Fired when a control is clicked. This is the equivalent of + * ActionListener.actionPerformed(ActionEvent e). + */ + protected void actionPerformed(GuiButton par1GuiButton) { + if (par1GuiButton.enabled) { + if (par1GuiButton.id == 1) { + EaglerAdapter.clearFileChooserResult(); + this.mc.displayGuiScreen(this.parentGuiScreen); + } else if (par1GuiButton.id == 0) { + this.buttonList.clear(); + timeToImport = true; + } + } + } + + /** + * Fired when a key is typed. This is the equivalent of + * KeyListener.keyTyped(KeyEvent e). + */ + protected void keyTyped(char par1, int par2) { + this.theGuiTextField.textboxKeyTyped(par1, par2); + ((GuiButton) this.buttonList.get(0)).enabled = this.theGuiTextField.getText().trim().length() > 0; + + if (par1 == 13) { + this.actionPerformed((GuiButton) this.buttonList.get(0)); + } + } + + /** + * Called when the mouse is clicked. + */ + protected void mouseClicked(int par1, int par2, int par3) { + super.mouseClicked(par1, par2, par3); + if(!timeToImport) { + this.theGuiTextField.mouseClicked(par1, par2, par3); + } + } + + /** + * Draws the screen and all the components in it. + */ + public void drawScreen(int par1, int par2, float par3) { + this.drawDefaultBackground(); + if(!timeToImport) { + StringTranslate var4 = StringTranslate.getInstance(); + this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.importName"), this.width / 2, this.height / 4 - 60 + 20, 16777215); + this.drawString(this.fontRenderer, var4.translateKey("selectWorld.enterName"), this.width / 2 - 100, this.height / 4 - 60 + 50, 10526880); + this.theGuiTextField.drawTextBox(); + }else { + definetlyTimeToImport = true; + long dots = (EaglerAdapter.steadyTimeMillis() / 500l) % 4l; + String str = "Reading: '" + oldName + "'"; + this.drawString(fontRenderer, str + (dots > 0 ? "." : "") + (dots > 1 ? "." : "") + (dots > 2 ? "." : ""), (this.width - this.fontRenderer.getStringWidth(str)) / 2, this.height / 3 + 10, 0xFFFFFF); + } + super.drawScreen(par1, par2, par3); + } +} diff --git a/src/main/java/net/lax1dude/eaglercraft/GuiScreenNoRelays.java b/src/main/java/net/lax1dude/eaglercraft/GuiScreenNoRelays.java new file mode 100644 index 0000000..7702d97 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GuiScreenNoRelays.java @@ -0,0 +1,56 @@ +package net.lax1dude.eaglercraft; + +import net.minecraft.src.GuiButton; +import net.minecraft.src.GuiScreen; +import net.minecraft.src.StringTranslate; + +public class GuiScreenNoRelays extends GuiScreen { + + private GuiScreen parent; + private String title1; + private String title2; + private String title3; + + public GuiScreenNoRelays(GuiScreen parent, String title) { + this.parent = parent; + this.title1 = title; + this.title2 = null; + this.title3 = null; + } + + public GuiScreenNoRelays(GuiScreen parent, String title1, String title2, String title3) { + this.parent = parent; + this.title1 = title1; + this.title2 = title2; + this.title3 = title3; + } + + public void initGui() { + StringTranslate var1 = StringTranslate.getInstance(); + buttonList.clear(); + buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 - 60 + 145, var1.translateKey("gui.cancel"))); + buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 - 60 + 115, var1.translateKey("directConnect.lanWorldRelay"))); + } + + public void drawScreen(int par1, int par2, float par3) { + StringTranslate var4 = StringTranslate.getInstance(); + this.drawDefaultBackground(); + this.drawCenteredString(this.fontRenderer, var4.translateKey(title1), this.width / 2, this.height / 4 - 60 + 70, 16777215); + if(title2 != null) { + this.drawCenteredString(this.fontRenderer, var4.translateKey(title2), this.width / 2, this.height / 4 - 60 + 80, 0xCCCCCC); + } + if(title3 != null) { + this.drawCenteredString(this.fontRenderer, var4.translateKey(title3), this.width / 2, this.height / 4 - 60 + 90, 0xCCCCCC); + } + super.drawScreen(par1, par2, par3); + } + + protected void actionPerformed(GuiButton par1GuiButton) { + if(par1GuiButton.id == 0) { + mc.displayGuiScreen(parent); + }else if(par1GuiButton.id == 1) { + mc.displayGuiScreen(new GuiScreenRelay(parent)); + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/GuiScreenRelay.java b/src/main/java/net/lax1dude/eaglercraft/GuiScreenRelay.java new file mode 100644 index 0000000..6d57285 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GuiScreenRelay.java @@ -0,0 +1,195 @@ +package net.lax1dude.eaglercraft; + +import net.minecraft.src.Minecraft; +import net.minecraft.src.EnumChatFormatting; +import net.minecraft.src.Gui; +import net.minecraft.src.GuiButton; +import net.minecraft.src.GuiScreen; +import net.minecraft.src.GuiScreenConfirmation; +import net.minecraft.src.StringTranslate; + +public class GuiScreenRelay extends GuiScreen { + + private final GuiScreen screen; + private GuiSlotRelay slots; + private boolean hasPinged; + private boolean addingNew = false; + private boolean deleting = false; + int selected; + + private GuiButton deleteRelay; + private GuiButton setPrimary; + + private String tooltipString = null; + + private long lastRefresh = 0l; + + public GuiScreenRelay(GuiScreen screen) { + this.screen = screen; + } + + public void initGui() { + selected = -1; + StringTranslate var1 = StringTranslate.getInstance(); + buttonList.clear(); + buttonList.add(new GuiButton(0, this.width / 2 + 54, this.height - 28, 100, 20, var1.translateKey("gui.done"))); + buttonList.add(new GuiButton(1, this.width / 2 - 154, this.height - 52, 100, 20, var1.translateKey("networkSettings.add"))); + buttonList.add(deleteRelay = new GuiButton(2, this.width / 2 - 50, this.height - 52, 100, 20, var1.translateKey("networkSettings.delete"))); + buttonList.add(setPrimary = new GuiButton(3, this.width / 2 + 54, this.height - 52, 100, 20, var1.translateKey("networkSettings.default"))); + buttonList.add(new GuiButton(4, this.width / 2 - 50, this.height - 28, 100, 20, var1.translateKey("networkSettings.refresh"))); + buttonList.add(new GuiButton(5, this.width / 2 - 154, this.height - 28, 100, 20, var1.translateKey("networkSettings.loadDefaults"))); + buttonList.add(new GuiButton(6, this.width - 100, 0, 100, 20, var1.translateKey("networkSettings.downloadRelay"))); + updateButtons(); + this.slots = new GuiSlotRelay(this); + if(!hasPinged) { + hasPinged = true; + slots.relayManager.ping(); + } + } + + void updateButtons() { + if(selected < 0) { + deleteRelay.enabled = false; + setPrimary.enabled = false; + }else { + deleteRelay.enabled = true; + setPrimary.enabled = true; + } + } + + public void actionPerformed(GuiButton btn) { + if(btn.id == 0) { + IntegratedServer.relayManager.save(); + mc.displayGuiScreen(screen); + } else if(btn.id == 1) { + addingNew = true; + mc.displayGuiScreen(new GuiScreenAddRelay(this)); + } else if(btn.id == 2) { + StringTranslate var1 = StringTranslate.getInstance(); + if(selected >= 0) { + RelayServer srv = IntegratedServer.relayManager.get(selected); + mc.displayGuiScreen(new GuiScreenConfirmation(this, var1.translateKey("networkSettings.delete"), var1.translateKey("addRelay.removeText1"), + EnumChatFormatting.GRAY + "'" + srv.comment + "' (" + srv.address + ")", selected)); + deleting = true; + } + } else if(btn.id == 3) { + if(selected >= 0) { + slots.relayManager.setPrimary(selected); + selected = 0; + } + } else if(btn.id == 4) { + long millis = EaglerAdapter.steadyTimeMillis(); + if(millis - lastRefresh > 700l) { + lastRefresh = millis; + slots.relayManager.ping(); + } + lastRefresh += 60l; + } else if(btn.id == 5) { + slots.relayManager.loadDefaults(); + long millis = EaglerAdapter.steadyTimeMillis(); + if(millis - lastRefresh > 700l) { + lastRefresh = millis; + slots.relayManager.ping(); + } + lastRefresh += 60l; + } else if(btn.id == 6) { + EaglerAdapter.downloadBytes("EaglerSPRelay.zip", EaglerAdapter.loadResourceBytes("relay_download.zip")); + } + } + + public void updateScreen() { + slots.relayManager.update(); + } + + private int mx = 0; + private int my = 0; + + int getFrameMouseX() { + return mx; + } + + int getFrameMouseY() { + return my; + } + + public void drawScreen(int par1, int par2, float par3) { + drawDefaultBackground(); + StringTranslate var4 = StringTranslate.getInstance(); + + mx = par1; + my = par2; + slots.drawScreen(par1, par2, par3); + + if(tooltipString != null) { + int ww = mc.fontRenderer.getStringWidth(tooltipString); + Gui.drawRect(par1 + 1, par2 - 14, par1 + ww + 7, par2 - 2, 0xC0000000); + screen.drawString(mc.fontRenderer, tooltipString, par1 + 4, par2 - 12, 0xFF999999); + tooltipString = null; + } + + this.drawCenteredString(fontRenderer, var4.translateKey("networkSettings.title"), this.width / 2, 16, 16777215); + + String str = var4.translateKey("networkSettings.relayTimeout") + " " + mc.gameSettings.relayTimeout; + int w = fontRenderer.getStringWidth(str); + this.drawString(fontRenderer, str, 3, 3, 0xDDDDDD); + + EaglerAdapter.glPushMatrix(); + EaglerAdapter.glTranslatef(w + 7, 4, 0.0f); + EaglerAdapter.glScalef(0.75f, 0.75f, 0.75f); + str = EnumChatFormatting.UNDERLINE + var4.translateKey("networkSettings.relayTimeoutChange"); + int w2 = fontRenderer.getStringWidth(str); + boolean b = par1 > w + 5 && par1 < w + 7 + w2 * 3 / 4 && par2 > 3 && par2 < 11; + this.drawString(fontRenderer, EnumChatFormatting.UNDERLINE + var4.translateKey("networkSettings.relayTimeoutChange"), 0, 0, b ? 0xCCCCCC : 0x999999); + EaglerAdapter.glPopMatrix(); + + super.drawScreen(par1, par2, par3); + } + + protected void mouseClicked(int par1, int par2, int par3) { + super.mouseClicked(par1, par2, par3); + if(par3 == 0) { + StringTranslate var4 = StringTranslate.getInstance(); + String str = var4.translateKey("networkSettings.relayTimeout") + " " + mc.gameSettings.relayTimeout; + int w = fontRenderer.getStringWidth(str); + str = var4.translateKey("networkSettings.relayTimeoutChange"); + int w2 = fontRenderer.getStringWidth(str); + if(par1 > w + 5 && par1 < w + 7 + w2 * 3 / 4 && par2 > 3 && par2 < 11) { + this.mc.displayGuiScreen(new GuiScreenChangeRelayTimeout(this)); + this.mc.sndManager.playSoundFX("random.click", 1.0F, 1.0F); + } + } + } + + void setToolTip(String str) { + tooltipString = str; + } + + String addNewName; + String addNewAddr; + boolean addNewPrimary; + + public void confirmClicked(boolean par1, int par2) { + if(par1) { + if(addingNew) { + IntegratedServer.relayManager.addNew(addNewAddr, addNewName, addNewPrimary); + addNewAddr = null; + addNewName = null; + addNewPrimary = false; + selected = -1; + updateButtons(); + }else if(deleting) { + IntegratedServer.relayManager.remove(par2); + selected = -1; + updateButtons(); + } + } + addingNew = false; + deleting = false; + this.mc.displayGuiScreen(this); + } + + static Minecraft getMinecraft(GuiScreenRelay screen) { + return screen.mc; + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/GuiScreenSingleplayerConnecting.java b/src/main/java/net/lax1dude/eaglercraft/GuiScreenSingleplayerConnecting.java new file mode 100644 index 0000000..4e7de72 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GuiScreenSingleplayerConnecting.java @@ -0,0 +1,89 @@ +package net.lax1dude.eaglercraft; + +import java.io.IOException; + +import net.minecraft.src.Minecraft; +import net.minecraft.src.GuiButton; +import net.minecraft.src.GuiDisconnected; +import net.minecraft.src.GuiScreen; +import net.minecraft.src.NetClientHandler; +import net.minecraft.src.Packet250CustomPayload; +import net.minecraft.src.Packet2ClientProtocol; +import net.minecraft.src.WorldClient; + +public class GuiScreenSingleplayerConnecting extends GuiScreen { + + private GuiScreen menu; + private String message; + private GuiButton killTask; + private NetClientHandler netHandler = null; + + private long startStartTime; + + public GuiScreenSingleplayerConnecting(GuiScreen menu, String message) { + this.menu = menu; + this.message = message; + } + + public void initGui() { + if(startStartTime == 0) this.startStartTime = EaglerAdapter.steadyTimeMillis(); + this.buttonList.add(killTask = new GuiButton(0, this.width / 2 - 100, this.height / 3 + 50, "Kill Task")); + killTask.enabled = false; + } + + public void drawScreen(int par1, int par2, float par3) { + this.drawDefaultBackground(); + float f = 2.0f; + int top = this.height / 3; + + long millis = EaglerAdapter.steadyTimeMillis(); + + long dots = (millis / 500l) % 4l; + this.drawString(fontRenderer, message + (dots > 0 ? "." : "") + (dots > 1 ? "." : "") + (dots > 2 ? "." : ""), (this.width - this.fontRenderer.getStringWidth(message)) / 2, top + 10, 0xFFFFFF); + + long elapsed = (millis - startStartTime) / 1000l; + if(elapsed > 3) { + this.drawCenteredString(fontRenderer, "(" + elapsed + "s)", this.width / 2, top + 25, 0xFFFFFF); + } + + super.drawScreen(par1, par2, par3); + } + + public boolean doesGuiPauseGame() { + return false; + } + + public void updateScreen() { + if(netHandler == null) { + try { + netHandler = new NetClientHandler(mc, EaglerProfile.username); + this.mc.setNetManager(netHandler.getNetManager()); + netHandler.addToSendQueue(new Packet2ClientProtocol(61, EaglerProfile.username, "127.0.0.1", mc.gameSettings.renderDistance)); + netHandler.addToSendQueue(new Packet250CustomPayload("EAG|MySkin", EaglerProfile.getSkinPacket())); + netHandler.addToSendQueue(new Packet250CustomPayload("EAG|MyCape", EaglerProfile.getCapePacket())); + } catch (IOException e) { + this.mc.displayGuiScreen(new GuiDisconnected(this.menu, "connect.failed", "disconnect.genericReason", "could not create nethandler", "")); + e.printStackTrace(); + return; + } + } + + long millis = EaglerAdapter.steadyTimeMillis(); + if(millis - startStartTime > 6000l) { + killTask.enabled = true; + } + } + + protected void actionPerformed(GuiButton par1GuiButton) { + if(par1GuiButton.id == 0) { + IntegratedServer.killWorker(); + this.mc.loadWorld((WorldClient)null); + this.mc.displayGuiScreen(menu); + if(netHandler != null) { + netHandler.getNetManager().closeConnections(); + Minecraft.getMinecraft().setNetManager(null); + } + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/GuiScreenSingleplayerException.java b/src/main/java/net/lax1dude/eaglercraft/GuiScreenSingleplayerException.java new file mode 100644 index 0000000..7844575 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GuiScreenSingleplayerException.java @@ -0,0 +1,69 @@ +package net.lax1dude.eaglercraft; + +import net.lax1dude.eaglercraft.sp.ipc.IPCPacket15ThrowException; +import net.minecraft.src.GuiButton; +import net.minecraft.src.GuiScreen; +import net.minecraft.src.StringTranslate; + +public class GuiScreenSingleplayerException extends GuiScreen { + + private GuiScreen mainmenu; + private IPCPacket15ThrowException exception; + private GuiButton returnToMenu; + private String action; + + public GuiScreenSingleplayerException(GuiScreen mainmenu, String action, IPCPacket15ThrowException exception) { + this.mainmenu = mainmenu; + this.action = action; + this.exception = exception; + } + + public void initGui() { + this.buttonList.add(returnToMenu = new GuiButton(0, this.width / 2 - 100, this.height / 3 + 36, StringTranslate.getInstance().translateKey("selectWorld.progress.continue"))); + } + + public void drawScreen(int par1, int par2, float par3) { + this.drawDefaultBackground(); + + int width_ = this.fontRenderer.getStringWidth(exception.errorMessage); + + int numTrace = exception.stackTrace.size(); + if(numTrace > 7) { + numTrace = 7; + } + int height_ = numTrace * 10 + 90 + (numTrace >= 7 ? 10 : 0); + + for(String s : exception.stackTrace) { + int w = this.fontRenderer.getStringWidth(" " + s); + if(width_ < w) { + width_ = w; + } + } + + int top = (this.height - height_) / 2; + if(top < 5) top = 5; + int left = (this.width - width_) / 2; + if(left < 5) left = 5; + + this.drawCenteredString(fontRenderer, "An error occured while '" + StringTranslate.getInstance().translateKey(action) + "'", this.width / 2, top, 0xFFAAAA); + + this.drawString(fontRenderer, exception.errorMessage, left, top + 20, 0xFFAAAA); + for(int i = 0; i < numTrace; ++i) { + this.drawString(fontRenderer, " " + exception.stackTrace.get(i), left, top + 30 + i * 10, 0xFFAAAA); + } + if(numTrace >= 7) { + this.drawCenteredString(fontRenderer, "... " + (exception.size() - numTrace) + " remaining ...", this.width / 2, top + 30 + numTrace * 10, 0xFFAAAA); + } + + returnToMenu.yPosition = top + 46 + numTrace * 10 + (numTrace >= 7 ? 10 : 0); + + super.drawScreen(par1, par2, par3); + } + + protected void actionPerformed(GuiButton par1GuiButton) { + if(par1GuiButton.id == 0) { + this.mc.displayGuiScreen(mainmenu); + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/GuiScreenSingleplayerLoading.java b/src/main/java/net/lax1dude/eaglercraft/GuiScreenSingleplayerLoading.java new file mode 100644 index 0000000..ab0a4dd --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GuiScreenSingleplayerLoading.java @@ -0,0 +1,146 @@ +package net.lax1dude.eaglercraft; + +import java.util.function.BiConsumer; +import java.util.function.BooleanSupplier; + +import net.lax1dude.eaglercraft.sp.ipc.IPCPacket15ThrowException; +import net.minecraft.src.Minecraft; +import net.minecraft.src.GuiButton; +import net.minecraft.src.GuiMainMenu; +import net.minecraft.src.GuiScreen; +import net.minecraft.src.StringTranslate; + +public class GuiScreenSingleplayerLoading extends GuiScreen { + + public final GuiScreen menu; + private GuiButton killTask; + public final String message; + private BooleanSupplier checkTaskComplete; + private Runnable taskKill; + private String lastStatus; + private String currentStatus; + private BiConsumer onException; + private int areYouSure; + + private long startStartTime; + + private static final Runnable defaultTerminateAction = () -> { + IntegratedServer.killWorker(); + Minecraft.getMinecraft().displayGuiScreen(new GuiMainMenu()); + }; + + public static GuiScreen createException(GuiScreen ok, String msg, IPCPacket15ThrowException[] exceptions) { + for(int i = exceptions.length - 1; i >= 0; --i) { + ok = new GuiScreenSingleplayerException(ok, msg, exceptions[i]); + } + return ok; + } + + private static final BiConsumer defaultExceptionAction = (t, u) -> { + GuiScreenSingleplayerLoading tt = (GuiScreenSingleplayerLoading) t; + Minecraft.getMinecraft().displayGuiScreen(createException(tt.menu, tt.message, u)); + }; + + public GuiScreenSingleplayerLoading(GuiScreen menu, String message, BooleanSupplier checkTaskComplete) { + this(menu, message, checkTaskComplete, defaultExceptionAction, defaultTerminateAction); + } + + public GuiScreenSingleplayerLoading(GuiScreen menu, String message, BooleanSupplier checkTaskComplete, BiConsumer exceptionAction) { + this(menu, message, checkTaskComplete, exceptionAction, defaultTerminateAction); + } + + public GuiScreenSingleplayerLoading(GuiScreen menu, String message, BooleanSupplier checkTaskComplete, Runnable onTerminate) { + this(menu, message, checkTaskComplete, defaultExceptionAction, onTerminate); + } + + public GuiScreenSingleplayerLoading(GuiScreen menu, String message, BooleanSupplier checkTaskComplete, BiConsumer onException, Runnable onTerminate) { + this.menu = menu; + this.message = message; + this.checkTaskComplete = checkTaskComplete; + this.onException = onException; + this.taskKill = onTerminate; + this.lastStatus = IntegratedServer.worldStatusString(); + this.currentStatus = message; + } + + public void initGui() { + if(startStartTime == 0) this.startStartTime = EaglerAdapter.steadyTimeMillis(); + areYouSure = 0; + this.buttonList.add(killTask = new GuiButton(0, this.width / 2 - 100, this.height / 3 + 50, StringTranslate.getInstance().translateKey("gui.killTask"))); + killTask.enabled = false; + } + + public boolean doesGuiPauseGame() { + return false; + } + + public void drawScreen(int par1, int par2, float par3) { + this.drawDefaultBackground(); + float f = 2.0f; + int top = this.height / 3; + + long millis = EaglerAdapter.steadyTimeMillis(); + + String str = StringTranslate.getInstance().translateKey(currentStatus); + + long dots = (millis / 500l) % 4l; + this.drawString(fontRenderer, str + (dots > 0 ? "." : "") + (dots > 1 ? "." : "") + (dots > 2 ? "." : ""), (this.width - this.fontRenderer.getStringWidth(str)) / 2, top + 10, 0xFFFFFF); + + if(areYouSure > 0) { + this.drawCenteredString(fontRenderer, StringTranslate.getInstance().translateKey("selectWorld.progress.cancelWarning"), this.width / 2, top + 25, 0xFF8888); + }else { + float prog = IntegratedServer.worldStatusProgress(); + if(this.currentStatus.equals(this.lastStatus) && prog > 0.01f) { + this.drawCenteredString(fontRenderer, (prog > 1.0f ? ("(" + (prog > 1000000.0f ? "" + (int)(prog / 1000000.0f) + "MB" : + (prog > 1000.0f ? "" + (int)(prog / 1000.0f) + "kB" : "" + (int)prog + "B")) + ")") : "" + (int)(prog * 100.0f) + "%"), this.width / 2, top + 25, 0xFFFFFF); + }else { + long elapsed = (millis - startStartTime) / 1000l; + if(elapsed > 3) { + this.drawCenteredString(fontRenderer, "(" + elapsed + "s)", this.width / 2, top + 25, 0xFFFFFF); + } + } + } + + super.drawScreen(par1, par2, par3); + } + + public void updateScreen() { + long millis = EaglerAdapter.steadyTimeMillis(); + if(millis - startStartTime > 6000l) { + killTask.enabled = true; + } + if(IntegratedServer.didLastCallFail()) { + IPCPacket15ThrowException[] pk = IntegratedServer.worldStatusErrors(); + if(pk != null) { + onException.accept(this, pk); + }else { + onException.accept(this, new IPCPacket15ThrowException[] { new IPCPacket15ThrowException("Server Crash: State '" + + IntegratedState.getStateName(IntegratedServer.statusState()) + "'", new String[0]) }); + } + return; + } + if(checkTaskComplete.getAsBoolean()) { + this.mc.displayGuiScreen(menu); + } + String str = IntegratedServer.worldStatusString(); + if(!lastStatus.equals(str)) { + lastStatus = str; + currentStatus = str; + } + killTask.displayString = StringTranslate.getInstance().translateKey(areYouSure > 0 ? "selectWorld.progress.confirmCancel" : "gui.killTask"); + if(areYouSure > 0) { + --areYouSure; + } + } + + protected void actionPerformed(GuiButton par1GuiButton) { + if(par1GuiButton.id == 0) { + if(areYouSure <= 0) { + areYouSure = 80; + }else if(areYouSure <= 65) { + taskKill.run(); + } + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/GuiScreenSingleplayerNotImplemented.java b/src/main/java/net/lax1dude/eaglercraft/GuiScreenSingleplayerNotImplemented.java new file mode 100644 index 0000000..7c10dfa --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GuiScreenSingleplayerNotImplemented.java @@ -0,0 +1,35 @@ +package net.lax1dude.eaglercraft; + +import net.minecraft.src.GuiButton; +import net.minecraft.src.GuiScreen; + +public class GuiScreenSingleplayerNotImplemented extends GuiScreen { + + private GuiScreen mainmenu; + private String featureName; + + public GuiScreenSingleplayerNotImplemented(GuiScreen mainmenu, String featureName) { + this.mainmenu = mainmenu; + this.featureName = featureName; + } + + public void initGui() { + this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 3 + 50, "I Understand")); + } + + public void drawScreen(int par1, int par2, float par3) { + this.drawDefaultBackground(); + + this.drawCenteredString(fontRenderer, "the feature '" + featureName + "' is incomplete", this.width / 2, this.height / 3, 0xFFFFFF); + this.drawCenteredString(fontRenderer, "it will be added to Eaglercraft in the next update", this.width / 2, this.height / 3 + 20, 0xFFFFFF); + + super.drawScreen(par1, par2, par3); + } + + protected void actionPerformed(GuiButton par1GuiButton) { + if(par1GuiButton.id == 0) { + this.mc.displayGuiScreen(mainmenu); + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/GuiScreenSkinCapeSettings.java b/src/main/java/net/lax1dude/eaglercraft/GuiScreenSkinCapeSettings.java new file mode 100644 index 0000000..617815b --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GuiScreenSkinCapeSettings.java @@ -0,0 +1,127 @@ +package net.lax1dude.eaglercraft; + +import net.minecraft.src.GuiButton; +import net.minecraft.src.GuiScreen; +import net.minecraft.src.MathHelper; +import net.minecraft.src.StringTranslate; + +public class GuiScreenSkinCapeSettings extends GuiScreen { + + private final GuiScreen parent; + + private String skinCustomizationTitle = "yee"; + private String skinCustomizationOtherPlayers = "yee"; + + private GuiButton toggleCape; + private GuiButton toggleJacket; + private GuiButton toggleHat; + private GuiButton toggleLeftArm; + private GuiButton toggleRightArm; + private GuiButton toggleLeftLeg; + private GuiButton toggleRightLeg; + private GuiButton toggleShowErasers; + private GuiButton toggleShowOtherCapes; + + public GuiScreenSkinCapeSettings(GuiScreen parent) { + this.parent = parent; + } + + public void initGui() { + StringTranslate var1 = StringTranslate.getInstance(); + skinCustomizationTitle = var1.translateKey("menu.skinCapeSettings.skinCustomization"); + skinCustomizationOtherPlayers = var1.translateKey("menu.skinCapeSettings.skinCustomization.otherPlayers"); + + int offset = MathHelper.clamp_int((height - 300) / 3, -100, 0); + + buttonList.add(new GuiButton(0, ((width - 230) / 2), 225 + offset, 230, 20, var1.translateKey("menu.skinCapeSettings.skinCustomization.apply"))); + + buttonList.add(toggleJacket = new GuiButton(1, width / 2 - 152, 60 + offset, 150, 20, var1.translateKey("menu.skinCapeSettings.skinCustomization.jacket") + ": " + + (mc.gameSettings.showSkinJacket ? var1.translateKey("options.on") : var1.translateKey("options.off")))); + buttonList.add(toggleHat = new GuiButton(2, width / 2 + 2, 60 + offset, 150, 20, var1.translateKey("menu.skinCapeSettings.skinCustomization.hat") + ": " + + (mc.gameSettings.showSkinHat ? var1.translateKey("options.on") : var1.translateKey("options.off")))); + buttonList.add(toggleLeftArm = new GuiButton(3, width / 2 - 152, 82 + offset, 150, 20, var1.translateKey("menu.skinCapeSettings.skinCustomization.leftArm") + ": " + + (mc.gameSettings.showSkinLeftArm ? var1.translateKey("options.on") : var1.translateKey("options.off")))); + buttonList.add(toggleRightArm = new GuiButton(4, width / 2 + 2, 82 + offset, 150, 20, var1.translateKey("menu.skinCapeSettings.skinCustomization.rightArm") + ": " + + (mc.gameSettings.showSkinRightArm ? var1.translateKey("options.on") : var1.translateKey("options.off")))); + buttonList.add(toggleLeftLeg = new GuiButton(5, width / 2 - 152, 104 + offset, 150, 20, var1.translateKey("menu.skinCapeSettings.skinCustomization.leftPants") + ": " + + (mc.gameSettings.showSkinLeftLeg ? var1.translateKey("options.on") : var1.translateKey("options.off")))); + buttonList.add(toggleRightLeg = new GuiButton(6, width / 2 + 2, 104 + offset, 150, 20, var1.translateKey("menu.skinCapeSettings.skinCustomization.rightPants") + ": " + + (mc.gameSettings.showSkinRightLeg ? var1.translateKey("options.on") : var1.translateKey("options.off")))); + buttonList.add(toggleCape = new GuiButton(7, width / 2 - 85, 130 + offset, 165, 20, var1.translateKey("menu.skinCapeSettings.skinCustomization.cape") + ": " + + (mc.gameSettings.showCape ? var1.translateKey("options.on") : var1.translateKey("options.off")))); + buttonList.add(toggleShowErasers = new GuiButton(8, width / 2 - 152, 190 + offset, 150, 20, (mc.gameSettings.allowFNAWSkins ? + var1.translateKey("menu.skinCapeSettings.skinCustomization.showErasersOn") : var1.translateKey("menu.skinCapeSettings.skinCustomization.showErasersOff")))); + buttonList.add(toggleShowOtherCapes = new GuiButton(9, width / 2 + 2, 190 + offset, 150, 20, var1.translateKey("menu.skinCapeSettings.skinCustomization.showOtherCapes") + ": " + + (mc.gameSettings.showOtherCapes ? var1.translateKey("options.on") : var1.translateKey("options.off")))); + } + + protected void actionPerformed(GuiButton par1GuiButton) { + StringTranslate var1 = StringTranslate.getInstance(); + switch(par1GuiButton.id) { + case 0: + mc.displayGuiScreen(parent); + mc.gameSettings.saveOptions(); + break; + case 1: + mc.gameSettings.showSkinJacket = !mc.gameSettings.showSkinJacket; + toggleJacket.displayString = var1.translateKey("menu.skinCapeSettings.skinCustomization.jacket") + ": " + + (mc.gameSettings.showSkinJacket ? var1.translateKey("options.on") : var1.translateKey("options.off")); + break; + case 2: + mc.gameSettings.showSkinHat = !mc.gameSettings.showSkinHat; + toggleHat.displayString = var1.translateKey("menu.skinCapeSettings.skinCustomization.hat") + ": " + + (mc.gameSettings.showSkinHat ? var1.translateKey("options.on") : var1.translateKey("options.off")); + break; + case 3: + mc.gameSettings.showSkinLeftArm = !mc.gameSettings.showSkinLeftArm; + toggleLeftArm.displayString = var1.translateKey("menu.skinCapeSettings.skinCustomization.leftArm") + ": " + + (mc.gameSettings.showSkinLeftArm ? var1.translateKey("options.on") : var1.translateKey("options.off")); + break; + case 4: + mc.gameSettings.showSkinRightArm = !mc.gameSettings.showSkinRightArm; + toggleRightArm.displayString = var1.translateKey("menu.skinCapeSettings.skinCustomization.rightArm") + ": " + + (mc.gameSettings.showSkinRightArm ? var1.translateKey("options.on") : var1.translateKey("options.off")); + break; + case 5: + mc.gameSettings.showSkinLeftLeg = !mc.gameSettings.showSkinLeftLeg; + toggleLeftLeg.displayString = var1.translateKey("menu.skinCapeSettings.skinCustomization.leftPants") + ": " + + (mc.gameSettings.showSkinLeftLeg ? var1.translateKey("options.on") : var1.translateKey("options.off")); + break; + case 6: + mc.gameSettings.showSkinRightLeg = !mc.gameSettings.showSkinRightLeg; + toggleRightLeg.displayString = var1.translateKey("menu.skinCapeSettings.skinCustomization.rightPants") + ": " + + (mc.gameSettings.showSkinRightLeg ? var1.translateKey("options.on") : var1.translateKey("options.off")); + break; + case 7: + mc.gameSettings.showCape = !mc.gameSettings.showCape; + toggleCape.displayString = var1.translateKey("menu.skinCapeSettings.skinCustomization.cape") + ": " + + (mc.gameSettings.showCape ? var1.translateKey("options.on") : var1.translateKey("options.off")); + break; + case 8: + mc.gameSettings.allowFNAWSkins = !mc.gameSettings.allowFNAWSkins; + toggleShowErasers.displayString = mc.gameSettings.allowFNAWSkins ? var1.translateKey("menu.skinCapeSettings.skinCustomization.showErasersOn") : + var1.translateKey("menu.skinCapeSettings.skinCustomization.showErasersOff"); + break; + case 9: + mc.gameSettings.showOtherCapes = !mc.gameSettings.showOtherCapes; + toggleShowOtherCapes.displayString = var1.translateKey("menu.skinCapeSettings.skinCustomization.showOtherCapes") + ": " + + (mc.gameSettings.showOtherCapes ? var1.translateKey("options.on") : var1.translateKey("options.off")); + break; + default: + break; + } + } + + public void drawScreen(int mx, int my, float partialTicks) { + drawDefaultBackground(); + + int offset = MathHelper.clamp_int((height - 300) / 3, -100, 0); + + this.drawCenteredString(this.fontRenderer, skinCustomizationTitle, this.width / 2, 40 + offset, 16777215); + this.drawCenteredString(this.fontRenderer, skinCustomizationOtherPlayers, this.width / 2, 170 + offset, 16777215); + + super.drawScreen(mx, my, partialTicks); + + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/GuiScreenVSyncWarning.java b/src/main/java/net/lax1dude/eaglercraft/GuiScreenVSyncWarning.java new file mode 100644 index 0000000..2526e1b --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GuiScreenVSyncWarning.java @@ -0,0 +1,78 @@ +package net.lax1dude.eaglercraft; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.src.EnumChatFormatting; +import net.minecraft.src.GuiButton; +import net.minecraft.src.GuiScreen; +import net.minecraft.src.StatCollector; + +public class GuiScreenVSyncWarning extends GuiScreen { + + private final GuiScreen cont; + private final List messages = new ArrayList<>(); + private int top = 0; + + public GuiScreenVSyncWarning(GuiScreen cont) { + this.cont = cont; + } + + public void initGui() { + messages.clear(); + messages.add(EnumChatFormatting.RED + StatCollector.translateToLocal("options.vsyncWarning.title")); + messages.add(null); + messages.add(EnumChatFormatting.GRAY + StatCollector.translateToLocal("options.vsyncWarning.0")); + messages.add(EnumChatFormatting.GRAY + StatCollector.translateToLocal("options.vsyncWarning.1")); + messages.add(null); + messages.add(StatCollector.translateToLocal("options.vsyncWarning.2")); + messages.add(StatCollector.translateToLocal("options.vsyncWarning.3")); + messages.add(StatCollector.translateToLocal("options.vsyncWarning.4")); + messages.add(StatCollector.translateToLocal("options.vsyncWarning.5")); + messages.add(StatCollector.translateToLocal("options.vsyncWarning.6")); + int j = 0; + for(int i = 0, l = messages.size(); i < l; ++i) { + if(messages.get(i) != null) { + j += 9; + }else { + j += 5; + } + } + top = this.height / 6 + j / -12; + j += top; + buttonList.clear(); + buttonList.add(new GuiButton(0, this.width / 2 - 100, j + 16, StatCollector.translateToLocal("options.vsyncWarning.fixSettings"))); + buttonList.add(new GuiButton(1, this.width / 2 - 100, j + 40, StatCollector.translateToLocal("options.vsyncWarning.continueAnyway"))); + buttonList.add(new GuiButton(2, this.width / 2 - 100, j + 64, StatCollector.translateToLocal("options.vsyncWarning.doNotShowAgain"))); + } + + public void drawScreen(int par1, int par2, float par3) { + this.drawDefaultBackground(); + int j = 0; + for(int i = 0, l = messages.size(); i < l; ++i) { + String str = messages.get(i); + if(str != null) { + this.drawCenteredString(fontRenderer, str, this.width / 2, top + j, 16777215); + j += 9; + }else { + j += 5; + } + } + super.drawScreen(par1, par2, par3); + } + + protected void actionPerformed(GuiButton par1GuiButton) { + if(par1GuiButton.id == 0) { + mc.gameSettings.enableVsync = true; + mc.gameSettings.saveOptions(); + mc.displayGuiScreen(cont); + }else if(par1GuiButton.id == 1) { + mc.displayGuiScreen(cont); + }else if(par1GuiButton.id == 2) { + mc.gameSettings.hideVsyncWarning = true; + mc.gameSettings.saveOptions(); + mc.displayGuiScreen(cont); + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/GuiSlotRelay.java b/src/main/java/net/lax1dude/eaglercraft/GuiSlotRelay.java new file mode 100644 index 0000000..5e3ebdb --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GuiSlotRelay.java @@ -0,0 +1,130 @@ +package net.lax1dude.eaglercraft; + +import net.lax1dude.eaglercraft.RelayQuery.VersionMismatch; +import net.lax1dude.eaglercraft.adapter.Tessellator; +import net.minecraft.src.Minecraft; +import net.minecraft.src.GuiSlot; + +class GuiSlotRelay extends GuiSlot { + + final GuiScreenRelay screen; + final RelayManager relayManager; + + public GuiSlotRelay(GuiScreenRelay screen) { + super(GuiScreenRelay.getMinecraft(screen), screen.width, screen.height, 32, screen.height - 64, 26); + this.screen = screen; + this.relayManager = IntegratedServer.relayManager; + } + + @Override + protected int getSize() { + return relayManager.count(); + } + + @Override + protected void elementClicked(int var1, boolean var2) { + screen.selected = var1; + screen.updateButtons(); + } + + @Override + protected boolean isSelected(int var1) { + return screen.selected == var1; + } + + @Override + protected void drawBackground() { + screen.drawDefaultBackground(); + } + + private static final TextureLocation icons = new TextureLocation("/gui/icons.png"); + + @Override + protected void drawSlot(int id, int xx, int yy, int height, Tessellator var5) { + if(id < relayManager.count()) { + icons.bindTexture(); + RelayServer srv = relayManager.get(id); + String comment = srv.comment; + int var15 = 0; + int var16 = 0; + String str = null; + int h = 12; + long ping = srv.getPing(); + if(ping == 0l) { + var16 = 5; + str = "No Connection"; + }else if(ping < 0l) { + var15 = 1; + var16 = (int) (Minecraft.getSystemTime() / 100L + (long) (id * 2) & 7L); + if (var16 > 4) { + var16 = 8 - var16; + } + str = "Polling..."; + }else { + VersionMismatch vm = srv.getPingCompatible(); + if(!vm.isCompatible()) { + var16 = 5; + switch(vm) { + case CLIENT_OUTDATED: + str = "Outdated Client!"; + break; + case RELAY_OUTDATED: + str = "Outdated Relay!"; + break; + default: + case UNKNOWN: + str = "Incompatible Relay!"; + break; + } + EaglerAdapter.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + EaglerAdapter.glPushMatrix(); + EaglerAdapter.glTranslatef(xx + 205, yy + 11, 0.0f); + EaglerAdapter.glScalef(0.6f, 0.6f, 0.6f); + screen.drawTexturedModalRect(0, 0, 0, 144, 16, 16); + EaglerAdapter.glPopMatrix(); + h += 10; + }else { + String pingComment = srv.getPingComment().trim(); + if(pingComment.length() > 0) { + comment = pingComment; + } + str = "" + ping + "ms"; + if (ping < 150L) { + var16 = 0; + } else if (ping < 300L) { + var16 = 1; + } else if (ping < 600L) { + var16 = 2; + } else if (ping < 1000L) { + var16 = 3; + } else { + var16 = 4; + } + } + } + + EaglerAdapter.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + screen.drawTexturedModalRect(xx + 205, yy, 0 + var15 * 10, 176 + var16 * 8, 10, 8); + if(srv.isPrimary()) { + EaglerAdapter.glPushMatrix(); + EaglerAdapter.glTranslatef(xx + 4, yy + 5, 0.0f); + EaglerAdapter.glScalef(0.8f, 0.8f, 0.8f); + screen.drawTexturedModalRect(0, 0, 0, 160, 16, 16); + EaglerAdapter.glPopMatrix(); + } + + screen.drawString(mc.fontRenderer, comment, xx + 22, yy + 2, 0xFFFFFFFF); + screen.drawString(mc.fontRenderer, srv.address, xx + 22, yy + 12, 0xFF999999); + + if(str != null) { + int mx = screen.getFrameMouseX(); + int my = screen.getFrameMouseY(); + int rx = xx + 202; + if(mx > rx && mx < rx + 13 && my > yy - 1 && my < yy + h) { + screen.setToolTip(str); + } + } + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/HighPolySkin.java b/src/main/java/net/lax1dude/eaglercraft/HighPolySkin.java new file mode 100644 index 0000000..89da9de --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/HighPolySkin.java @@ -0,0 +1,96 @@ +package net.lax1dude.eaglercraft; + +public enum HighPolySkin { + + LONG_ARMS( + new TextureLocation("/mesh/longarms.png"), + new ModelLocation("/mesh/longarms0.mdl"), + null, + new ModelLocation("/mesh/longarms2.mdl"), + new ModelLocation[] { + new ModelLocation("/mesh/longarms1.mdl") + }, + new float[] { + 1.325f + }, + 0.0f, + new TextureLocation("/mesh/longarms.fallback.png") + ), + + WEIRD_CLIMBER_DUDE( + new TextureLocation("/mesh/weirdclimber.png"), + new ModelLocation("/mesh/weirdclimber0.mdl"), + null, + new ModelLocation("/mesh/weirdclimber2.mdl"), + new ModelLocation[] { + new ModelLocation("/mesh/weirdclimber1.mdl") + }, + new float[] { + 2.62f + }, + -90.0f, + new TextureLocation("/mesh/weirdclimber.fallback.png") + ), + + LAXATIVE_DUDE( + new TextureLocation("/mesh/laxativedude.png"), + new ModelLocation("/mesh/laxativedude0.mdl"), + null, + new ModelLocation("/mesh/laxativedude3.mdl"), + new ModelLocation[] { + new ModelLocation("/mesh/laxativedude1.mdl"), + new ModelLocation("/mesh/laxativedude2.mdl") + }, + new float[] { + 2.04f + }, + 0.0f, + new TextureLocation("/mesh/laxativedude.fallback.png") + ), + + BABY_CHARLES( + new TextureLocation("/mesh/charles.png"), + new ModelLocation("/mesh/charles0.mdl"), + new ModelLocation("/mesh/charles1.mdl"), + new ModelLocation("/mesh/charles2.mdl"), + new ModelLocation[] {}, + new float[] {}, + 0.0f, + new TextureLocation("/mesh/charles.fallback.png") + ), + + BABY_WINSTON( + new TextureLocation("/mesh/winston.png"), + new ModelLocation("/mesh/winston0.mdl"), + null, + new ModelLocation("/mesh/winston1.mdl"), + new ModelLocation[] {}, + new float[] {}, + 0.0f, + new TextureLocation("/mesh/winston.fallback.png") + ); + + public static float highPolyScale = 0.5f; + + public final TextureLocation texture; + public final ModelLocation bodyModel; + public final ModelLocation headModel; + public final ModelLocation eyesModel; + public final ModelLocation[] limbsModel; + public final float[] limbsOffset; + public final float limbsInitialRotation; + public final TextureLocation fallbackTexture; + + HighPolySkin(TextureLocation texture, ModelLocation bodyModel, ModelLocation headModel, ModelLocation eyesModel, + ModelLocation[] limbsModel, float[] limbsOffset, float limbsInitialRotation, TextureLocation fallbackTexture) { + this.texture = texture; + this.bodyModel = bodyModel; + this.headModel = headModel; + this.eyesModel = eyesModel; + this.limbsModel = limbsModel; + this.limbsOffset = limbsOffset; + this.limbsInitialRotation = limbsInitialRotation; + this.fallbackTexture = fallbackTexture; + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/IntegratedServer.java b/src/main/java/net/lax1dude/eaglercraft/IntegratedServer.java new file mode 100644 index 0000000..332b968 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/IntegratedServer.java @@ -0,0 +1,452 @@ +package net.lax1dude.eaglercraft; + +import java.io.IOException; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +import net.lax1dude.eaglercraft.sp.ipc.*; +import net.minecraft.src.EnumGameType; +import net.minecraft.src.NBTTagCompound; +import net.minecraft.src.NetHandler; +import net.minecraft.src.WorldSettings; + +public class IntegratedServer { + + public static boolean isWorkerAlive() { + return !(statusState < 0 || !EaglerAdapter.isIntegratedServerAlive()); + } + + public static void killWorker() { + openConnections.clear(); + exceptions.clear(); + statusState = IntegratedState.WORLD_WORKER_NOT_RUNNING; + EaglerAdapter.terminateIntegratedServer(); + } + + private static String[] loadLocale = null; + private static String[] loadStats = null; + private static boolean isPaused = false; + private static List integratedServerTPS = new LinkedList<>(); + + public static final int preferredRelayVersion = 1; + + public static final RelayManager relayManager = new RelayManager(); + + public static List getTPS() { + return integratedServerTPS; + } + + public static void clearTPS() { + integratedServerTPS.clear(); + } + + public static void begin() { + if(!isWorkerAlive()) { + begin(EaglerAdapter.fileContentsLines("lang/en_US.lang"), EaglerAdapter.fileContentsLines("achievement/map.txt")); + } + } + + public static void begin(String[] locale, String[] stats) { + logException = true; + if(!isWorkerAlive()) { + openConnections.clear(); + exceptions.clear(); + statusState = IntegratedState.WORLD_WORKER_BOOTING; + isPaused = false; + loadLocale = locale; + loadStats = stats; + clearTPS(); + EaglerAdapter.beginLoadingIntegratedServer(); + } + } + + public static boolean isReady() { + return statusState == IntegratedState.WORLD_NONE; + } + + public static boolean isWorldNotLoaded() { + return statusState == IntegratedState.WORLD_NONE || statusState == IntegratedState.WORLD_WORKER_NOT_RUNNING || + statusState == IntegratedState.WORLD_WORKER_BOOTING; + } + + public static boolean isWorldRunning() { + return statusState == IntegratedState.WORLD_LOADED || statusState == IntegratedState.WORLD_PAUSED || + statusState == IntegratedState.WORLD_LOADING || statusState == IntegratedState.WORLD_SAVING; + } + + public static boolean isWorldReady() { + return statusState == IntegratedState.WORLD_LOADED || statusState == IntegratedState.WORLD_LOADING; + } + + private static void ensureReady() { + if(!isReady()) { + String msg = "Server is in state " + statusState + " '" + IntegratedState.getStateName(statusState) + "' which is not the 'WORLD_NONE' state for the requested IPC operation"; + throw new IllegalStateException(msg); + } + } + + private static void ensureWorldReady() { + if(!isWorldReady()) { + String msg = "Server is in state " + statusState + " '" + IntegratedState.getStateName(statusState) + "' which is not the 'WORLD_LOADED' state for the requested IPC operation"; + throw new IllegalStateException(msg); + } + } + + public static boolean isAlive() { + return isWorkerAlive(); + } + + public static void loadWorld(String name, int difficulty) { + loadWorld(name, difficulty, null); + } + + public static void loadWorld(String name, int difficulty, WorldSettings gen) { + ensureReady(); + clearTPS(); + statusState = IntegratedState.WORLD_LOADING; + isPaused = false; + + if(gen != null) { + sendIPCPacket(new IPCPacket02InitWorld(name, gen.getIPCGamemode(), gen.getTerrainType().getWorldTypeID(), + gen.func_82749_j(), gen.getSeed(), gen.areCommandsAllowed(), gen.isMapFeaturesEnabled(), gen.isBonusChestEnabled())); + } + + sendIPCPacket(new IPCPacket00StartServer(name, EaglerProfile.username, difficulty)); + } + + public static void unloadWorld() { + if(isWorldRunning()) { + statusState = IntegratedState.WORLD_UNLOADING; + sendIPCPacket(new IPCPacket01StopServer()); + } + IntegratedServerLAN.closeLAN(); + } + + public static void autoSave() { + if(!isPaused) { + statusState = IntegratedState.WORLD_SAVING; + sendIPCPacket(new IPCPacket0BPause(false)); + } + } + + public static void setPaused(boolean pause) { + if(statusState != IntegratedState.WORLD_LOADED && statusState != IntegratedState.WORLD_PAUSED) { + return; + } + if(isPaused != pause) { + if(pause) { + statusState = IntegratedState.WORLD_PAUSED; + }else { + statusState = IntegratedState.WORLD_LOADED; + } + sendIPCPacket(new IPCPacket0BPause(pause)); + isPaused = pause; + } + + } + + public static void requestWorldList() { + ensureReady(); + statusState = IntegratedState.WORLD_LISTING; + worlds.clear(); + sendIPCPacket(new IPCPacket0EListWorlds()); + } + + public static List getWorldList() { + return statusState == IntegratedState.WORLD_LISTING ? null : worlds; + } + + public static NBTTagCompound getWorld(String folderName) { + for(NBTTagCompound nbt : worlds) { + if(folderName.equals(nbt.getString("folderName"))) { + return nbt; + } + } + return null; + } + + public static void deleteWorld(String name) { + ensureReady(); + statusState = IntegratedState.WORLD_DELETING; + sendIPCPacket(new IPCPacket03DeleteWorld(name)); + } + + public static void setWorldName(String name, String displayName) { + ensureReady(); + sendIPCPacket(new IPCPacket06RenameWorldNBT(name, displayName)); + } + + public static void copyMoveWorld(String oldName, String newName, String newDisplayName, boolean copyFilesNotRename) { + ensureReady(); + statusState = copyFilesNotRename ? IntegratedState.WORLD_DUPLICATING : IntegratedState.WORLD_RENAMING; + sendIPCPacket(new IPCPacket04RenameWorld(oldName, newName, newDisplayName, copyFilesNotRename)); + } + + private static int statusState = IntegratedState.WORLD_WORKER_NOT_RUNNING; + private static String worldStatusString = ""; + private static float worldStatusProgress = 0.0f; + + private static final LinkedList exceptions = new LinkedList<>(); + + public static final LinkedList worlds = new LinkedList<>(); + + public static int statusState() { + return statusState; + } + + public static String worldStatusString() { + return worldStatusString; + } + + public static float worldStatusProgress() { + return worldStatusProgress; + } + + public static IPCPacket15ThrowException worldStatusError() { + return exceptions.size() > 0 ? exceptions.remove(0) : null; + } + + public static IPCPacket15ThrowException[] worldStatusErrors() { + if(exceptions.size() <= 0) { + return null; + } + IPCPacket15ThrowException[] t = new IPCPacket15ThrowException[exceptions.size()]; + for(int i = 0; i < t.length; ++i) { + t[i] = exceptions.get(i); + } + exceptions.clear(); + return t; + } + + private static boolean logException = false; + + public static void enableExceptionLog(boolean f) { + logException = f; + } + + private static boolean callFailed = false; + + public static boolean didLastCallFail() { + boolean c = callFailed; + callFailed = false; + return c; + } + + public static void importWorld(String name, byte[] data, int format) { + ensureReady(); + statusState = IntegratedState.WORLD_IMPORTING; + sendIPCPacket(new IPCPacket07ImportWorld(name, data, (byte)format)); + } + + public static void exportWorld(String name, int format) { + ensureReady(); + statusState = IntegratedState.WORLD_EXPORTING; + if(format == IPCPacket05RequestData.REQUEST_LEVEL_EAG) { + name = name + (new String(new char[] { (char)253, (char)233, (char)233 })) + EaglerProfile.username; + } + sendIPCPacket(new IPCPacket05RequestData(name, (byte)format)); + } + + private static byte[] exportResponse = null; + + public static byte[] getExportResponse() { + byte[] dat = exportResponse; + exportResponse = null; + return dat; + } + + public static void processICP() { + + if(!EaglerAdapter.isIntegratedServerAlive()) { + if(IntegratedServerLAN.isLANOpen()) { + IntegratedServerLAN.closeLAN(); + } + return; + } + + PKT pktBytes; + while((pktBytes = EaglerAdapter.recieveFromIntegratedServer("IPC")) != null) { + + IPCPacketBase packet; + try { + packet = IPCPacketManager.IPCDeserialize(pktBytes.data); + }catch(IOException e) { + System.err.print("Failed to deserialize IPC packet: "); + e.printStackTrace(); + continue; + } + + int id = packet.id(); + + try { + switch(id) { + case IPCPacketFFProcessKeepAlive.ID: { + IPCPacketFFProcessKeepAlive pkt = (IPCPacketFFProcessKeepAlive)packet; + IntegratedState.isACKValidInState(pkt.ack, statusState); + switch(pkt.ack) { + case 0xFF: + System.out.println("Integrated server signaled a successful boot"); + sendIPCPacket(new IPCPacket14StringList(IPCPacket14StringList.LOCALE, loadLocale)); + sendIPCPacket(new IPCPacket14StringList(IPCPacket14StringList.STAT_GUID, loadStats)); + loadLocale = loadStats = null; + statusState = IntegratedState.WORLD_NONE; + break; + case IPCPacket00StartServer.ID: + statusState = IntegratedState.WORLD_LOADED; + isPaused = false; + break; + case IPCPacket0BPause.ID: + statusState = isPaused ? IntegratedState.WORLD_PAUSED : IntegratedState.WORLD_LOADED; + break; + case IPCPacketFFProcessKeepAlive.FAILURE: + System.err.println("Server signaled 'FAILURE' response in state '" + IntegratedState.getStateName(statusState) + "'"); + statusState = IntegratedState.WORLD_NONE; + callFailed = true; + break; + case IPCPacket01StopServer.ID: + statusState = IntegratedState.WORLD_NONE; + break; + case IPCPacket03DeleteWorld.ID: + case IPCPacket04RenameWorld.ID: + case IPCPacket07ImportWorld.ID: + case IPCPacket12FileWrite.ID: + case IPCPacket13FileCopyMove.ID: + case IPCPacket18ClearPlayers.ID: + statusState = IntegratedState.WORLD_NONE; + break; + default: + System.err.println("IPC acknowledge packet type 0x" + Integer.toHexString(id) + " class '" + packet.getClass().getSimpleName() + "' was not handled"); + break; + } + break; + } + case IPCPacket09RequestResponse.ID: { + IPCPacket09RequestResponse pkt = (IPCPacket09RequestResponse)packet; + if(statusState == IntegratedState.WORLD_EXPORTING) { + statusState = IntegratedState.WORLD_NONE; + exportResponse = pkt.response; + }else { + System.err.println("IPCPacket09RequestResponse was recieved but statusState was '" + IntegratedState.getStateName(statusState) + "' instead of 'WORLD_EXPORTING'"); + } + break; + } + case IPCPacket0DProgressUpdate.ID: { + IPCPacket0DProgressUpdate pkt = (IPCPacket0DProgressUpdate)packet; + worldStatusString = pkt.updateMessage; + worldStatusProgress = pkt.updateProgress; + if(logException) { + System.out.println("IntegratedServer: task \"" + pkt.updateMessage + "\"" + (pkt.updateProgress > 0.0f ? " is " + ((int)(pkt.updateProgress * 100.0f)) + "% complete" : "")); + } + break; + } + case IPCPacket14StringList.ID: { + IPCPacket14StringList pkt = (IPCPacket14StringList)packet; + + if(pkt.opCode == IPCPacket14StringList.SERVER_TPS) { + integratedServerTPS.clear(); + integratedServerTPS.addAll(pkt.stringList); + } + + // file path list for file browser + + break; + } + case IPCPacket15ThrowException.ID: { + exceptions.add((IPCPacket15ThrowException)packet); + if(logException) { + ((IPCPacket15ThrowException)packet).log(); + } + if(exceptions.size() > 64) { + exceptions.remove(0); + } + break; + } + case IPCPacket16NBTList.ID: { + IPCPacket16NBTList pkt = (IPCPacket16NBTList)packet; + if(pkt.opCode == IPCPacket16NBTList.WORLD_LIST && statusState == IntegratedState.WORLD_LISTING) { + statusState = IntegratedState.WORLD_NONE; + worlds.clear(); + worlds.addAll(pkt.nbtTagList); + }else { + System.err.println("IPC packet type 0x" + Integer.toHexString(id) + " class '" + packet.getClass().getSimpleName() + "' contained invalid opCode " + pkt.opCode + " in state " + statusState + " '" + IntegratedState.getStateName(statusState) + "'"); + } + break; + } + case IPCPacket0CPlayerChannel.ID: { + IPCPacket0CPlayerChannel pkt = (IPCPacket0CPlayerChannel)packet; + WorkerNetworkManager newConnection = openConnections.get(pkt.channel); + if(newConnection == null) { + return; + } + System.out.println("[Client][INIT][CLOSE][" + pkt.channel + "]"); + newConnection.closeConnections(); + openConnections.remove(pkt.channel); + EaglerAdapter.disableChannel("NET|" + pkt.channel); + break; + } + default: + System.err.println("IPC packet type 0x" + Integer.toHexString(id) + " class '" + packet.getClass().getSimpleName() + "' was not handled"); + break; + } + }catch(Throwable t) { + System.err.println("Failed to process IPC packet type 0x" + Integer.toHexString(id) + " class '" + packet.getClass().getSimpleName() + "'"); + t.printStackTrace(); + } + } + + IntegratedServerLAN.updateLANServer(); + } + + public static void sendIPCPacket(IPCPacketBase pkt) { + try { + byte[] serialized = IPCPacketManager.IPCSerialize(pkt); + EaglerAdapter.sendToIntegratedServer("IPC", serialized); + } catch (IOException e) { + System.err.println("Could not serialize IPC packet 0x" + Integer.toHexString(pkt.id()) + " class '" + pkt.getClass().getSimpleName() + "'"); + e.printStackTrace(); + } + } + + private static final HashMap openConnections = new HashMap<>(); + + public static final boolean doesChannelExist(String channel) { + return openConnections.containsKey(channel); + } + + public static final WorkerNetworkManager openConnection(String channel, NetHandler netHandler) { + WorkerNetworkManager newConnection = openConnections.get(channel); + if(newConnection != null) { + return newConnection; + } + System.out.println("[Client][INIT][OPEN][" + channel + "]"); + EaglerAdapter.enableChannel("NET|" + channel); + sendIPCPacket(new IPCPacket0CPlayerChannel(channel, true)); + newConnection = new WorkerNetworkManager(channel, netHandler); + openConnections.put(channel, newConnection); + return newConnection; + } + + public static final void closeChannel(String channel) { + WorkerNetworkManager newConnection = openConnections.get(channel); + if(newConnection == null) { + return; + } + System.out.println("[Client][INIT][CLOSE][" + channel + "]"); + newConnection.closeConnections(); + openConnections.remove(channel); + EaglerAdapter.disableChannel("NET|" + channel); + sendIPCPacket(new IPCPacket0CPlayerChannel(channel, false)); + } + + public static void configureLAN(EnumGameType enumGameType, boolean allowCommands) { + sendIPCPacket(new IPCPacket17ConfigureLAN(enumGameType.getID(), allowCommands, IntegratedServerLAN.currentICEServers)); + } + + public static void clearPlayerData(String worldName) { + ensureReady(); + statusState = IntegratedState.WORLD_CLEAR_PLAYERS; + sendIPCPacket(new IPCPacket18ClearPlayers(worldName)); + } + +} \ No newline at end of file diff --git a/src/main/java/net/lax1dude/eaglercraft/IntegratedServerLAN.java b/src/main/java/net/lax1dude/eaglercraft/IntegratedServerLAN.java new file mode 100644 index 0000000..6b59124 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/IntegratedServerLAN.java @@ -0,0 +1,369 @@ +package net.lax1dude.eaglercraft; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import net.lax1dude.eaglercraft.sp.ipc.IPCPacket0CPlayerChannel; +import net.lax1dude.eaglercraft.sp.relay.pkt.*; + +public class IntegratedServerLAN { + + public static final List currentICEServers = new ArrayList<>(); + + private static RelayServerSocket lanRelaySocket = null; + + private static String currentCode = null; + + public static String shareToLAN(Consumer progressCallback, String worldName, boolean worldHidden) { + currentCode = null; + RelayServerSocket sock = IntegratedServer.relayManager.getWorkingRelay((str) -> progressCallback.accept("Connecting: " + str), + IntegratedServer.preferredRelayVersion, worldName + (worldHidden ? ";1" : ";0")); + if(sock == null) { + lanRelaySocket = null; + return null; + }else { + progressCallback.accept("Opening: " + sock.getURI()); + IPacket00Handshake hs = (IPacket00Handshake)sock.readPacket(); + lanRelaySocket = sock; + String code = hs.connectionCode; + System.out.println("Relay [" + sock.getURI() + "] connected as 'server', code: " + code); + progressCallback.accept("Opened '" + code + "' on " + sock.getURI()); + long millis = EaglerAdapter.steadyTimeMillis(); + do { + if(sock.isClosed()) { + System.out.println("Relay [" + sock.getURI() + "] connection lost"); + lanRelaySocket = null; + return null; + } + IPacket pkt = sock.readPacket(); + if(pkt != null) { + if(pkt instanceof IPacket01ICEServers) { + IPacket01ICEServers ipkt = (IPacket01ICEServers)pkt; + System.out.println("Relay [" + sock.getURI() + "] provided ICE servers:"); + currentICEServers.clear(); + for(net.lax1dude.eaglercraft.sp.relay.pkt.ICEServerSet.RelayServer srv : ipkt.servers) { + System.out.println("Relay [" + sock.getURI() + "] " + srv.type.name() + + ": " + srv.address); + currentICEServers.add(srv.getICEString()); + } + EaglerAdapter.serverLANInitializeServer(currentICEServers.toArray(new String[currentICEServers.size()])); + return currentCode = code; + }else { + System.err.println("Relay [" + sock.getURI() + "] unexpected packet: " + pkt.getClass().getSimpleName()); + closeLAN(); + return null; + } + } + EaglerAdapter.sleep(50); + }while(EaglerAdapter.steadyTimeMillis() - millis < 2500l); + System.out.println("Relay [" + sock.getURI() + "] relay provide ICE servers timeout"); + closeLAN(); + return null; + } + } + + public static String getCurrentURI() { + return lanRelaySocket == null ? "" : lanRelaySocket.getURI(); + } + + public static String getCurrentCode() { + return currentCode == null ? "" : currentCode; + } + + public static void closeLAN() { + closeLANNoKick(); + EaglerAdapter.serverLANCloseServer(); + cleanupLAN(); + } + + public static void closeLANNoKick() { + if(lanRelaySocket != null) { + lanRelaySocket.close(); + lanRelaySocket = null; + currentCode = null; + } + } + + public static void cleanupLAN() { + Iterator itr = clients.values().iterator(); + while(itr.hasNext()) { + itr.next().disconnect(); + } + clients.clear(); + } + + public static boolean isHostingLAN() { + return lanRelaySocket != null || EaglerAdapter.countPeers() > 0; + } + + public static boolean isLANOpen() { + return lanRelaySocket != null; + } + + private static final Map clients = new HashMap<>(); + + public static void updateLANServer() { + if(lanRelaySocket != null) { + IPacket pkt; + while((pkt = lanRelaySocket.readPacket()) != null) { + if(pkt instanceof IPacket02NewClient) { + IPacket02NewClient ipkt = (IPacket02NewClient) pkt; + if(clients.containsKey(ipkt.clientId)) { + System.err.println("Relay [" + lanRelaySocket.getURI() + "] relay provided duplicate client '" + ipkt.clientId + "'"); + }else { + clients.put(ipkt.clientId, new LANClient(ipkt.clientId)); + } + }else if(pkt instanceof IPacket03ICECandidate) { + IPacket03ICECandidate ipkt = (IPacket03ICECandidate) pkt; + LANClient c = clients.get(ipkt.peerId); + if(c != null) { + c.handleICECandidates(ipkt.candidate); + }else { + System.err.println("Relay [" + lanRelaySocket.getURI() + "] relay sent IPacket03ICECandidate for unknown client '" + ipkt.peerId + "'"); + } + }else if(pkt instanceof IPacket04Description) { + IPacket04Description ipkt = (IPacket04Description) pkt; + LANClient c = clients.get(ipkt.peerId); + if(c != null) { + c.handleDescription(ipkt.description); + }else { + System.err.println("Relay [" + lanRelaySocket.getURI() + "] relay sent IPacket04Description for unknown client '" + ipkt.peerId + "'"); + } + }else if(pkt instanceof IPacket05ClientSuccess) { + IPacket05ClientSuccess ipkt = (IPacket05ClientSuccess) pkt; + LANClient c = clients.get(ipkt.clientId); + if(c != null) { + c.handleSuccess(); + }else { + System.err.println("Relay [" + lanRelaySocket.getURI() + "] relay sent IPacket05ClientSuccess for unknown client '" + ipkt.clientId + "'"); + } + }else if(pkt instanceof IPacket06ClientFailure) { + IPacket06ClientFailure ipkt = (IPacket06ClientFailure) pkt; + LANClient c = clients.get(ipkt.clientId); + if(c != null) { + c.handleFailure(); + }else { + System.err.println("Relay [" + lanRelaySocket.getURI() + "] relay sent IPacket06ClientFailure for unknown client '" + ipkt.clientId + "'"); + } + }else if(pkt instanceof IPacketFFErrorCode) { + IPacketFFErrorCode ipkt = (IPacketFFErrorCode) pkt; + System.err.println("Relay [" + lanRelaySocket.getURI() + "] error code thrown: " + + IPacketFFErrorCode.code2string(ipkt.code) + "(" + ipkt.code + "): " + ipkt.desc); + Throwable t; + while((t = lanRelaySocket.getException()) != null) { + t.printStackTrace(); + } + }else { + System.err.println("Relay [" + lanRelaySocket.getURI() + "] unexpected packet: " + pkt.getClass().getSimpleName()); + } + } + if(lanRelaySocket.isClosed()) { + lanRelaySocket = null; + } + } + Iterator itr = clients.values().iterator(); + while(itr.hasNext()) { + LANClient cl = itr.next(); + cl.update(); + if(cl.dead) { + itr.remove(); + } + } + } + + private static final class LANClient { + + private static final int PRE = 0, RECEIVED_ICE_CANDIDATE = 1, SENT_ICE_CANDIDATE = 2, RECEIVED_DESCRIPTION = 3, + SENT_DESCRIPTION = 4, RECEIVED_SUCCESS = 5, CONNECTED = 6, CLOSED = 7; + + protected final String clientId; + protected final String channelId; + + protected int state = PRE; + protected boolean dead = false; + protected String localICECandidate = null; + protected boolean localChannel = false; + protected List packetPreBuffer = null; + protected final long startTime; + + protected LANClient(String clientId) { + this.clientId = clientId; + this.channelId = "NET|" + clientId; + this.startTime = EaglerAdapter.steadyTimeMillis(); + EaglerAdapter.serverLANCreatePeer(clientId); + } + + protected void handleICECandidates(String candidates) { + if(state == SENT_DESCRIPTION) { + EaglerAdapter.serverLANPeerICECandidates(clientId, candidates); + if(localICECandidate != null) { + lanRelaySocket.writePacket(new IPacket03ICECandidate(clientId, localICECandidate)); + localICECandidate = null; + state = SENT_ICE_CANDIDATE; + }else { + state = RECEIVED_ICE_CANDIDATE; + } + }else { + System.err.println("Relay [" + lanRelaySocket.getURI() + "] unexpected IPacket03ICECandidate for '" + clientId + "'"); + } + } + + protected void handleDescription(String description) { + if(state == PRE) { + EaglerAdapter.serverLANPeerDescription(clientId, description); + state = RECEIVED_DESCRIPTION; + }else { + System.err.println("Relay [" + lanRelaySocket.getURI() + "] unexpected IPacket04Description for '" + clientId + "'"); + } + } + + protected void handleSuccess() { + if(state == SENT_ICE_CANDIDATE) { + if(localChannel) { + EaglerAdapter.enableChannel(channelId); + IntegratedServer.sendIPCPacket(new IPCPacket0CPlayerChannel(clientId, true)); + localChannel = false; + if(packetPreBuffer != null) { + for(byte[] b : packetPreBuffer) { + EaglerAdapter.sendToIntegratedServer(channelId, b); + } + packetPreBuffer = null; + } + state = CONNECTED; + }else { + state = RECEIVED_SUCCESS; + } + }else { + System.err.println("Relay [" + lanRelaySocket.getURI() + "] unexpected IPacket05ClientSuccess for '" + clientId + "'"); + } + } + + protected void handleFailure() { + if(state == SENT_ICE_CANDIDATE) { + System.err.println("Client '" + clientId + "' failed to connect"); + disconnect(); + }else { + System.err.println("Relay [" + lanRelaySocket.getURI() + "] unexpected IPacket06ClientFailure for '" + clientId + "'"); + } + } + + protected void update() { + if(state != CLOSED) { + if(state != CONNECTED && EaglerAdapter.steadyTimeMillis() - startTime > 13000l) { + System.out.println("LAN client '" + clientId + "' handshake timed out"); + disconnect(); + return; + } + PKT pk; + while(state == CONNECTED && (pk = EaglerAdapter.recieveFromIntegratedServer("NET|" + clientId)) != null) { + EaglerAdapter.serverLANWritePacket(clientId, pk.data); + } + List l = EaglerAdapter.serverLANGetAllEvent(clientId); + if(l == null) { + return; + } + read_loop: for(int i = 0, s = l.size(); i < s; ++i) { + LANPeerEvent evt = l.get(i); + if(evt instanceof LANPeerEvent.LANPeerDisconnectEvent) { + System.out.println("LAN client '" + clientId + "' disconnected"); + disconnect(); + }else { + switch(state) { + case SENT_DESCRIPTION:{ + if(evt instanceof LANPeerEvent.LANPeerICECandidateEvent) { + localICECandidate = ((LANPeerEvent.LANPeerICECandidateEvent)evt).candidates; + continue read_loop; + } + break; + } + case RECEIVED_DESCRIPTION: { + if(evt instanceof LANPeerEvent.LANPeerDescriptionEvent) { + lanRelaySocket.writePacket(new IPacket04Description(clientId, ((LANPeerEvent.LANPeerDescriptionEvent)evt).description)); + state = SENT_DESCRIPTION; + continue read_loop; + } + break; + } + case RECEIVED_ICE_CANDIDATE: { + if(evt instanceof LANPeerEvent.LANPeerICECandidateEvent) { + lanRelaySocket.writePacket(new IPacket03ICECandidate(clientId, ((LANPeerEvent.LANPeerICECandidateEvent)evt).candidates)); + state = SENT_ICE_CANDIDATE; + continue read_loop; + }else if(evt instanceof LANPeerEvent.LANPeerDataChannelEvent) { + localChannel = true; + continue read_loop; + }else if(evt instanceof LANPeerEvent.LANPeerPacketEvent) { + if(packetPreBuffer == null) packetPreBuffer = new LinkedList<>(); + packetPreBuffer.add(((LANPeerEvent.LANPeerPacketEvent)evt).payload); + continue read_loop; + } + break; + } + case SENT_ICE_CANDIDATE: { + if(evt instanceof LANPeerEvent.LANPeerDataChannelEvent) { + localChannel = true; + continue read_loop; + }else if(evt instanceof LANPeerEvent.LANPeerPacketEvent) { + if(packetPreBuffer == null) packetPreBuffer = new LinkedList<>(); + packetPreBuffer.add(((LANPeerEvent.LANPeerPacketEvent)evt).payload); + continue read_loop; + } + break; + } + case RECEIVED_SUCCESS: { + if(evt instanceof LANPeerEvent.LANPeerDataChannelEvent) { + EaglerAdapter.enableChannel(channelId); + IntegratedServer.sendIPCPacket(new IPCPacket0CPlayerChannel(clientId, true)); + if(packetPreBuffer != null) { + for(byte[] b : packetPreBuffer) { + EaglerAdapter.sendToIntegratedServer(channelId, b); + } + packetPreBuffer = null; + } + state = CONNECTED; + continue read_loop; + } + break; + } + case CONNECTED: { + if(evt instanceof LANPeerEvent.LANPeerPacketEvent) { + EaglerAdapter.sendToIntegratedServer(channelId, ((LANPeerEvent.LANPeerPacketEvent)evt).payload); + continue read_loop; + } + break; + } + default: { + break; + } + } + if(state != CLOSED) { + System.err.println("LAN client '" + clientId + "' had an accident: " + evt.getClass().getSimpleName() + " (state " + state + ")"); + } + disconnect(); + return; + } + } + }else { + disconnect(); + } + } + + protected void disconnect() { + if(!dead) { + if(state == CONNECTED) { + IntegratedServer.sendIPCPacket(new IPCPacket0CPlayerChannel(clientId, false)); + EaglerAdapter.disableChannel(channelId); + } + state = CLOSED; + EaglerAdapter.serverLANDisconnectPeer(clientId); + dead = true; + } + } + + } +} diff --git a/src/main/java/net/lax1dude/eaglercraft/IntegratedState.java b/src/main/java/net/lax1dude/eaglercraft/IntegratedState.java new file mode 100644 index 0000000..36e4b68 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/IntegratedState.java @@ -0,0 +1,80 @@ +package net.lax1dude.eaglercraft; + +import net.lax1dude.eaglercraft.sp.ipc.*; + +public class IntegratedState { + + public static final int WORLD_WORKER_NOT_RUNNING = -2; + public static final int WORLD_WORKER_BOOTING = -1; + public static final int WORLD_NONE = 0; + public static final int WORLD_LOADING = 2; + public static final int WORLD_LOADED = 3; + public static final int WORLD_UNLOADING = 4; + public static final int WORLD_DELETING = 5; + public static final int WORLD_RENAMING = 6; + public static final int WORLD_DUPLICATING = 7; + public static final int WORLD_PAUSED = 9; + public static final int WORLD_LISTING = 10; + public static final int WORLD_SAVING = 11; + public static final int WORLD_IMPORTING = 12; + public static final int WORLD_EXPORTING = 13; + public static final int WORLD_GET_NBT = 14; + + public static final int WORLD_LIST_FILE = 15; + public static final int WORLD_FILE_READ = 16; + public static final int WORLD_FILE_WRITE = 17; + public static final int WORLD_FILE_MOVE = 18; + public static final int WORLD_FILE_COPY = 19; + public static final int WORLD_CLEAR_PLAYERS = 20; + + public static String getStateName(int i) { + switch(i) { + case WORLD_WORKER_NOT_RUNNING: return "WORLD_WORKER_NOT_RUNNING"; + case WORLD_WORKER_BOOTING: return "WORLD_WORKER_BOOTING"; + case WORLD_NONE: return "WORLD_NONE"; + case WORLD_LOADING: return "WORLD_LOADING"; + case WORLD_LOADED: return "WORLD_LOADED"; + case WORLD_UNLOADING: return "WORLD_UNLOADING"; + case WORLD_DELETING: return "WORLD_DELETING"; + case WORLD_RENAMING: return "WORLD_RENAMING"; + case WORLD_DUPLICATING: return "WORLD_DUPLICATING"; + case WORLD_PAUSED: return "WORLD_PAUSED"; + case WORLD_LISTING: return "WORLD_LISTING"; + case WORLD_SAVING: return "WORLD_SAVING"; + case WORLD_IMPORTING: return "WORLD_IMPORTING"; + case WORLD_EXPORTING: return "WORLD_EXPORTING"; + case WORLD_GET_NBT: return "WORLD_GET_NBT"; + case WORLD_LIST_FILE: return "WORLD_LIST_FILE"; + case WORLD_FILE_READ: return "WORLD_FILE_READ"; + case WORLD_FILE_WRITE: return "WORLD_FILE_WRITE"; + case WORLD_FILE_MOVE: return "WORLD_FILE_MOVE"; + case WORLD_FILE_COPY: return "WORLD_FILE_COPY"; + case WORLD_CLEAR_PLAYERS: return "WORLD_CLEAR_PLAYERS"; + default: return "INVALID"; + } + } + + public static boolean isACKValidInState(int ack, int state) { + switch(ack) { + case 0xFF: return state == WORLD_WORKER_BOOTING; + case IPCPacket00StartServer.ID: return state == WORLD_LOADING; + case IPCPacket01StopServer.ID: return state == WORLD_UNLOADING; + case IPCPacket03DeleteWorld.ID: return state == WORLD_DELETING; + case IPCPacket04RenameWorld.ID: return (state == WORLD_DUPLICATING || state == WORLD_RENAMING); + case IPCPacket07ImportWorld.ID: return state == WORLD_IMPORTING; + case IPCPacket0BPause.ID: return (state == WORLD_SAVING || state == WORLD_PAUSED); + case IPCPacket12FileWrite.ID: return state == WORLD_FILE_WRITE; + case IPCPacket13FileCopyMove.ID: return (state == WORLD_FILE_MOVE || state == WORLD_FILE_COPY); + case IPCPacket18ClearPlayers.ID: return state == WORLD_CLEAR_PLAYERS; + default: return false; + } + } + + public void assertState(int ack, int state) { + if(!isACKValidInState(ack, state)) { + String msg = "Recieved ACK " + ack + " '" + getStateName(ack) + "' while the client state was " + state + " '" + getStateName(state) + "'"; + System.err.println(msg); + throw new IllegalStateException(msg); + } + } +} diff --git a/src/main/java/net/lax1dude/eaglercraft/LANClientNetworkManager.java b/src/main/java/net/lax1dude/eaglercraft/LANClientNetworkManager.java new file mode 100644 index 0000000..76a0f52 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/LANClientNetworkManager.java @@ -0,0 +1,329 @@ +package net.lax1dude.eaglercraft; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket; +import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket00Handshake; +import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket01ICEServers; +import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket03ICECandidate; +import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket04Description; +import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket05ClientSuccess; +import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket06ClientFailure; +import net.lax1dude.eaglercraft.sp.relay.pkt.IPacketFFErrorCode; +import net.minecraft.src.INetworkManager; +import net.minecraft.src.NetHandler; +import net.minecraft.src.Packet; + +public class LANClientNetworkManager implements INetworkManager { + + private static final int PRE = 0, INIT = 1, SENT_ICE_CANDIDATE = 2, SENT_DESCRIPTION = 3; + + private static final String[] initStateNames = new String[] { "PRE", "INIT", "SENT_ICE_CANDIDATE", "SENT_DESCRIPTION" }; + + public final String displayCode; + public final String displayRelay; + + private NetHandler theNetHandler; + + private LANClientNetworkManager(String displayCode, String displayRelay) { + this.displayCode = displayCode; + this.displayRelay = displayRelay; + this.theNetHandler = null; + } + + public static LANClientNetworkManager connectToWorld(RelayServerSocket sock, String displayCode, String displayRelay) { + EaglerAdapter.clearLANClientState(); + int connectState = PRE; + IPacket pkt; + mainLoop: while(!sock.isClosed()) { + if((pkt = sock.readPacket()) != null) { + if(pkt instanceof IPacket00Handshake) { + if(connectState == PRE) { + + // %%%%%% Process IPacket00Handshake %%%%%% + + System.out.println("Relay [" + displayRelay + "|" + displayCode + "] recieved handshake, " + + "client id: " + ((IPacket00Handshake)pkt).connectionCode); + connectState = INIT; + + }else { + sock.close(); + System.err.println("Relay [" + displayRelay + "|" + displayCode + "] unexpected packet: " + + "IPacket00Handshake in state " + initStateNames[connectState]); + return null; + } + }else if(pkt instanceof IPacket01ICEServers) { + if(connectState == INIT) { + + // %%%%%% Process IPacket01ICEServers %%%%%% + + IPacket01ICEServers ipkt = (IPacket01ICEServers) pkt; + + // print servers + System.out.println("Relay [" + displayRelay + "|" + displayCode + "] provided ICE servers:"); + List servers = new ArrayList<>(); + for(net.lax1dude.eaglercraft.sp.relay.pkt.ICEServerSet.RelayServer srv : ipkt.servers) { + System.out.println("Relay [" + displayRelay + "|" + displayCode + "] " + srv.type.name() + + ": " + srv.address); + servers.add(srv.getICEString()); + } + + // process + EaglerAdapter.clientLANSetICEServersAndConnect(servers.toArray(new String[servers.size()])); + + // await result + long lm = EaglerAdapter.steadyTimeMillis(); + do { + String c = EaglerAdapter.clientLANAwaitDescription(); + if(c != null) { + System.out.println("Relay [" + displayRelay + "|" + displayCode + "] client sent description"); + + // 'this.descriptionHandler' was called, send result: + sock.writePacket(new IPacket04Description("", c)); + + connectState = SENT_DESCRIPTION; + continue mainLoop; + } + EaglerAdapter.sleep(20); + }while(EaglerAdapter.steadyTimeMillis() - lm < 5000l); + + // no description was sent + sock.close(); + System.err.println("Relay [" + displayRelay + "|" + displayCode + "] client provide description timeout"); + return null; + + }else { + sock.close(); + System.err.println("Relay [" + displayRelay + "|" + displayCode + "] unexpected packet: " + + "IPacket01ICEServers in state " + initStateNames[connectState]); + return null; + } + }else if(pkt instanceof IPacket03ICECandidate) { + if(connectState == SENT_ICE_CANDIDATE) { + + // %%%%%% Process IPacket03ICECandidate %%%%%% + + IPacket03ICECandidate ipkt = (IPacket03ICECandidate) pkt; + + // process + System.out.println("Relay [" + displayRelay + "|" + displayCode + "] recieved server ICE candidate"); + EaglerAdapter.clientLANSetICECandidate(ipkt.candidate); + + // await result + long lm = EaglerAdapter.steadyTimeMillis(); + do { + if(EaglerAdapter.clientLANAwaitChannel()) { + System.out.println("Relay [" + displayRelay + "|" + displayCode + "] client opened data channel"); + + // 'this.remoteDataChannelHandler' was called, success + sock.writePacket(new IPacket05ClientSuccess(ipkt.peerId)); + sock.close(); + return new LANClientNetworkManager(displayCode, displayRelay); + + } + EaglerAdapter.sleep(20); + }while(EaglerAdapter.steadyTimeMillis() - lm < 10000l); + + // no channel was opened + sock.writePacket(new IPacket06ClientFailure(ipkt.peerId)); + sock.close(); + System.err.println("Relay [" + displayRelay + "|" + displayCode + "] client open data channel timeout"); + return null; + + }else { + sock.close(); + System.err.println("Relay [" + displayRelay + "|" + displayCode + "] unexpected packet: " + + "IPacket03ICECandidate in state " + initStateNames[connectState]); + return null; + } + }else if(pkt instanceof IPacket04Description) { + if(connectState == SENT_DESCRIPTION) { + + // %%%%%% Process IPacket04Description %%%%%% + + IPacket04Description ipkt = (IPacket04Description) pkt; + + // process + System.out.println("Relay [" + displayRelay + "|" + displayCode + "] recieved server description"); + EaglerAdapter.clientLANSetDescription(ipkt.description); + + // await result + long lm = EaglerAdapter.steadyTimeMillis(); + do { + String c = EaglerAdapter.clientLANAwaitICECandidate(); + if(c != null) { + System.out.println("Relay [" + displayRelay + "|" + displayCode + "] client sent ICE candidate"); + + // 'this.iceCandidateHandler' was called, send result: + sock.writePacket(new IPacket03ICECandidate("", c)); + + connectState = SENT_ICE_CANDIDATE; + continue mainLoop; + } + EaglerAdapter.sleep(20); + }while(EaglerAdapter.steadyTimeMillis() - lm < 10000l); + + // no ice candidates were sent + sock.close(); + System.err.println("Relay [" + displayRelay + "|" + displayCode + "] client provide ICE candidate timeout"); + return null; + + }else { + sock.close(); + System.err.println("Relay [" + displayRelay + "|" + displayCode + "] unexpected packet: " + + "IPacket04Description in state " + initStateNames[connectState]); + return null; + } + }else if(pkt instanceof IPacketFFErrorCode) { + + // %%%%%% Process IPacketFFErrorCode %%%%%% + + IPacketFFErrorCode ipkt = (IPacketFFErrorCode) pkt; + System.err.println("Relay [" + displayRelay + "|" + displayCode + "] connection failed: " + + IPacketFFErrorCode.code2string(ipkt.code) + "(" + ipkt.code + "): " + ipkt.desc); + Throwable t; + while((t = sock.getException()) != null) { + t.printStackTrace(); + } + sock.close(); + return null; + + }else { + + // %%%%%% Unexpected Packet %%%%%% + + System.err.println("Relay [" + displayRelay + "] unexpected packet: " + pkt.getClass().getSimpleName()); + sock.close(); + return null; + } + } + EaglerAdapter.sleep(20); + } + return null; + } + + @Override + public void setNetHandler(NetHandler var1) { + theNetHandler = var1; + } + + private ByteArrayOutputStream sendBuffer = new ByteArrayOutputStream(); + + @Override + public void addToSendQueue(Packet var1) { + try { + sendBuffer.reset(); + Packet.writePacket(var1, new DataOutputStream(sendBuffer)); + EaglerAdapter.clientLANSendPacket(sendBuffer.toByteArray()); + }catch(IOException e) { + System.err.println("Failed to serialize minecraft packet '" + var1.getClass().getSimpleName() + "' to remote LAN world"); + e.printStackTrace(); + } + } + + @Override + public void wakeThreads() { + // no + } + + private byte[] fragmentedPacket = new byte[0]; + + @Override + public void processReadPackets() { + + /* + * Alright some really weird shit is up with TeaVM here, if you put the try/catch + * around the full inner body of the while loop, the compiler fails with no error + * message, just a vague stack trace. But making a multi-catch around just + * readPacketData and processPacket has no issues + * + * You're welcome for the two hours of my time and single line changes I made + * in a fuck ton of irrelevant files leading up to this bullshit revelation + */ + + if(this.theNetHandler != null) { + byte[] data; + while((data = EaglerAdapter.clientLANReadPacket()) != null) { + byte[] fullData; + + if (data[0] == 0) { + fullData = new byte[fragmentedPacket.length + data.length - 1]; + System.arraycopy(fragmentedPacket, 0, fullData, 0, fragmentedPacket.length); + System.arraycopy(data, 1, fullData, fragmentedPacket.length, data.length - 1); + fragmentedPacket = new byte[0]; + } else if (data[0] == 1) { + fullData = new byte[fragmentedPacket.length + data.length - 1]; + System.arraycopy(fragmentedPacket, 0, fullData, 0, fragmentedPacket.length); + System.arraycopy(data, 1, fullData, fragmentedPacket.length, data.length - 1); + fragmentedPacket = fullData; + continue; + } else { + continue; + } + + EaglerInputStream bai = new EaglerInputStream(fullData); + + int pktId = bai.read(); + + if(pktId == -1) { + System.err.println("Recieved invalid '-1' packet"); + continue; + } + + Packet pkt = Packet.getNewPacket(pktId); + + if(pkt == null) { + System.err.println("Recieved invalid '" + pktId + "' packet"); + continue; + } + + try { + pkt.readPacketData(new DataInputStream(bai)); + pkt.processPacket(theNetHandler); + }catch(IOException ex) { + System.err.println("Could not deserialize a " + data.length + " byte long minecraft packet of type '" + (data.length <= 0 ? -1 : (int)(data[0] & 0xFF)) + "' from remote LAN world"); + }catch(Throwable t) { + System.err.println("Could not process minecraft packet 0x" + Integer.toHexString(pkt.getPacketId()) + " class '" + pkt.getClass().getSimpleName() + "' from remote LAN world"); + t.printStackTrace(); + } + } + } + } + + @Override + public void serverShutdown() { + if(!EaglerAdapter.clientLANClosed()) { + EaglerAdapter.clientLANCloseConnection(); + } + } + + @Override + public int packetSize() { + return 0; + } + + @Override + public void networkShutdown(String var1, Object... var2) { + if(!EaglerAdapter.clientLANClosed()) { + EaglerAdapter.clientLANCloseConnection(); + } + } + + @Override + public void closeConnections() { + if(!EaglerAdapter.clientLANClosed()) { + EaglerAdapter.clientLANCloseConnection(); + } + } + + @Override + public String getServerURI() { + return "[lan:" + displayRelay + ":" + displayCode + "]"; + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/LANPeerEvent.java b/src/main/java/net/lax1dude/eaglercraft/LANPeerEvent.java new file mode 100644 index 0000000..6d2e974 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/LANPeerEvent.java @@ -0,0 +1,88 @@ +package net.lax1dude.eaglercraft; + +public interface LANPeerEvent { + + String getPeerId(); + + public static class LANPeerICECandidateEvent implements LANPeerEvent { + + public final String clientId; + public final String candidates; + + public LANPeerICECandidateEvent(String clientId, String candidates) { + this.clientId = clientId; + this.candidates = candidates; + } + + @Override + public String getPeerId() { + return clientId; + } + + } + + public static class LANPeerDescriptionEvent implements LANPeerEvent { + + public final String clientId; + public final String description; + + public LANPeerDescriptionEvent(String clientId, String description) { + this.clientId = clientId; + this.description = description; + } + + @Override + public String getPeerId() { + return clientId; + } + + } + + public static class LANPeerDataChannelEvent implements LANPeerEvent { + + public final String clientId; + + public LANPeerDataChannelEvent(String clientId) { + this.clientId = clientId; + } + + @Override + public String getPeerId() { + return clientId; + } + + } + + public static class LANPeerPacketEvent implements LANPeerEvent { + + public final String clientId; + public final byte[] payload; + + public LANPeerPacketEvent(String clientId, byte[] payload) { + this.clientId = clientId; + this.payload = payload; + } + + @Override + public String getPeerId() { + return clientId; + } + + } + + public static class LANPeerDisconnectEvent implements LANPeerEvent { + + public final String clientId; + + public LANPeerDisconnectEvent(String clientId) { + this.clientId = clientId; + } + + @Override + public String getPeerId() { + return clientId; + } + + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/LANServerList.java b/src/main/java/net/lax1dude/eaglercraft/LANServerList.java new file mode 100644 index 0000000..458d5e9 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/LANServerList.java @@ -0,0 +1,139 @@ +package net.lax1dude.eaglercraft; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket07LocalWorlds.LocalWorld; + +public class LANServerList { + + private final List lanServersList = new LinkedList<>(); + private final Map lanServersQueryList = new LinkedHashMap<>(); + private final Set deadURIs = new HashSet<>(); + + private long lastRefresh = 0l; + private int refreshCounter = 0; + + public void update() { + long millis = EaglerAdapter.steadyTimeMillis(); + if(millis - lastRefresh > 10000l) { + if(++refreshCounter < 10) { + refresh(); + }else { + lastRefresh = millis; + } + }else { + Iterator> itr = lanServersQueryList.entrySet().iterator(); + while(itr.hasNext()) { + Entry etr = itr.next(); + String uri = etr.getKey(); + RelayWorldsQuery q = etr.getValue(); + if(!q.isQueryOpen()) { + itr.remove(); + if(q.isQueryFailed()) { + deadURIs.add(uri); + Iterator itr2 = lanServersList.iterator(); + while(itr2.hasNext()) { + if(itr2.next().lanServerRelay.address.equals(uri)) { + itr2.remove(); + } + } + }else { + RelayServer rl = IntegratedServer.relayManager.getByURI(uri); + Iterator itr2 = lanServersList.iterator(); + while(itr2.hasNext()) { + LanServer l = itr2.next(); + if(l.lanServerRelay.address.equals(uri)) { + l.flagged = false; + } + } + if(rl != null) { + Iterator itr3 = q.getWorlds().iterator(); + yee: while(itr3.hasNext()) { + LocalWorld l = itr3.next(); + itr2 = lanServersList.iterator(); + while(itr2.hasNext()) { + LanServer l2 = itr2.next(); + if(l2.lanServerRelay.address.equals(uri) && l2.lanServerCode.equals(l.worldCode)) { + l2.lanServerMotd = l.worldName; + l2.flagged = true; + continue yee; + } + } + lanServersList.add(new LanServer(l.worldName, rl, l.worldCode)); + } + } + itr2 = lanServersList.iterator(); + while(itr2.hasNext()) { + LanServer l = itr2.next(); + if(l.lanServerRelay.address.equals(uri)) { + if(!l.flagged) { + itr2.remove(); + } + } + } + } + } + } + } + } + + public void forceRefresh() { + deadURIs.clear(); + refreshCounter = 0; + refresh(); + } + + private void refresh() { + lastRefresh = EaglerAdapter.steadyTimeMillis(); + for(int i = 0, l = IntegratedServer.relayManager.count(); i < l; ++i) { + RelayServer srv = IntegratedServer.relayManager.get(i); + if(!lanServersQueryList.containsKey(srv.address) && !deadURIs.contains(srv.address)) { + lanServersQueryList.put(srv.address, EaglerAdapter.openRelayWorldsQuery(srv.address)); + } + } + } + + public LanServer getServer(int idx) { + return lanServersList.get(idx); + } + + public int countServers() { + return lanServersList.size(); + } + + public class LanServer { + + private String lanServerMotd; + private RelayServer lanServerRelay; + private String lanServerCode; + + protected boolean flagged = true; + + protected LanServer(String lanServerMotd, RelayServer lanServerRelay, String lanServerCode) { + this.lanServerMotd = lanServerMotd; + this.lanServerRelay = lanServerRelay; + this.lanServerCode = lanServerCode; + } + + public String getLanServerMotd() { + return lanServerMotd; + } + + public RelayServer getLanServerRelay() { + return lanServerRelay; + } + + public String getLanServerCode() { + return lanServerCode; + } + + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/LocalStorageManager.java b/src/main/java/net/lax1dude/eaglercraft/LocalStorageManager.java new file mode 100644 index 0000000..043ba4a --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/LocalStorageManager.java @@ -0,0 +1,96 @@ +package net.lax1dude.eaglercraft; + +import java.io.IOException; + +import net.minecraft.src.Achievement; +import net.minecraft.src.CompressedStreamTools; +import net.minecraft.src.NBTTagCompound; + +public class LocalStorageManager { + + public static NBTTagCompound achievementStorage = null; + public static NBTTagCompound gameSettingsStorage = null; + public static NBTTagCompound profileSettingsStorage = null; + + public static void loadStorage() { + byte[] a = EaglerAdapter.loadLocalStorage("a"); + byte[] g = EaglerAdapter.loadLocalStorage("g"); + byte[] p = EaglerAdapter.loadLocalStorage("p"); + + if(a != null) { + try { + achievementStorage = CompressedStreamTools.readUncompressed(a); + }catch(IOException e) { + ; + } + } + + if(g != null) { + try { + gameSettingsStorage = CompressedStreamTools.readUncompressed(g); + }catch(IOException e) { + ; + } + } + + if(p != null) { + try { + profileSettingsStorage = CompressedStreamTools.readUncompressed(p); + }catch(IOException e) { + ; + } + } + + if(achievementStorage == null) achievementStorage = new NBTTagCompound(); + if(gameSettingsStorage == null) gameSettingsStorage = new NBTTagCompound(); + if(profileSettingsStorage == null) profileSettingsStorage = new NBTTagCompound(); + + } + + public static void saveStorageA() { + try { + EaglerAdapter.saveLocalStorage("a", CompressedStreamTools.writeUncompressed(achievementStorage)); + } catch (IOException e) { + ; + } + } + + public static void saveStorageG() { + try { + EaglerAdapter.saveLocalStorage("g", CompressedStreamTools.writeUncompressed(gameSettingsStorage)); + } catch (IOException e) { + ; + } + } + + public static void saveStorageP() { + try { + EaglerAdapter.saveLocalStorage("p", CompressedStreamTools.writeUncompressed(profileSettingsStorage)); + } catch (IOException e) { + ; + } + } + + public static String dumpConfiguration() { + try { + return Base64.encodeBase64String(CompressedStreamTools.writeUncompressed(gameSettingsStorage)); + } catch(Throwable e) { + return ""; + } + } + + public static boolean hasMadeAchievement(Achievement stat) { + if(stat.parentAchievement != null && (!achievementStorage.getBoolean(stat.parentAchievement.statGuid))) { + return false; + }else { + if(!achievementStorage.getBoolean(stat.statGuid)) { + achievementStorage.setBoolean(stat.statGuid, true); + saveStorageA(); + return true; + }else { + return false; + } + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/ModelBipedNewSkins.java b/src/main/java/net/lax1dude/eaglercraft/ModelBipedNewSkins.java new file mode 100644 index 0000000..3387f53 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/ModelBipedNewSkins.java @@ -0,0 +1,160 @@ +package net.lax1dude.eaglercraft; + +import net.minecraft.src.Entity; +import net.minecraft.src.ModelBiped; +import net.minecraft.src.ModelRenderer; + +public class ModelBipedNewSkins extends ModelBiped { + /** + * left arm + */ + public ModelRenderer field_178734_a; + /** + * right arm + */ + public ModelRenderer field_178732_b; + /** + * left leg + */ + public ModelRenderer field_178733_c; + /** + * right leg + */ + public ModelRenderer field_178731_d; + /** + * jacket + */ + public ModelRenderer field_178730_v; + private ModelRenderer field_178729_w; + private ModelRenderer field_178736_x; + private boolean isAlex; + + public ModelBipedNewSkins(float p_i46304_1_, boolean p_i46304_2_) + { + super(p_i46304_1_, 0.0F, 64, 64); + this.isAlex = p_i46304_2_; + this.field_178736_x = new ModelRenderer(this, 24, 0); + this.field_178736_x.addBox(-3.0F, -6.0F, -1.0F, 6, 6, 1, p_i46304_1_); + this.field_178729_w = new ModelRenderer(this, 0, 0); + this.field_178729_w.setTextureSize(64, 32); + this.field_178729_w.addBox(-5.0F, 0.0F, -1.0F, 10, 16, 1, p_i46304_1_); + + if (p_i46304_2_) + { + this.bipedLeftArm = new ModelRenderer(this, 32, 48); + this.bipedLeftArm.addBox(-1.0F, -2.0F, -2.0F, 3, 12, 4, p_i46304_1_); + this.bipedLeftArm.setRotationPoint(5.0F, 2.5F, 0.0F); + this.bipedRightArm = new ModelRenderer(this, 40, 16); + this.bipedRightArm.addBox(-2.0F, -2.0F, -2.0F, 3, 12, 4, p_i46304_1_); + this.bipedRightArm.setRotationPoint(-5.0F, 2.5F, 0.0F); + this.field_178734_a = new ModelRenderer(this, 48, 48); + this.field_178734_a.addBox(-1.0F, -2.0F, -2.0F, 3, 12, 4, p_i46304_1_ + 0.25F); + this.field_178734_a.setRotationPoint(5.0F, 2.5F, 0.0F); + this.field_178732_b = new ModelRenderer(this, 40, 32); + this.field_178732_b.addBox(-2.0F, -2.0F, -2.0F, 3, 12, 4, p_i46304_1_ + 0.25F); + this.field_178732_b.setRotationPoint(-5.0F, 2.5F, 10.0F); + } + else + { + this.bipedLeftArm = new ModelRenderer(this, 32, 48); + this.bipedLeftArm.addBox(-1.0F, -2.0F, -2.0F, 4, 12, 4, p_i46304_1_); + this.bipedLeftArm.setRotationPoint(5.0F, 2.0F, 0.0F); + this.field_178734_a = new ModelRenderer(this, 48, 48); + this.field_178734_a.addBox(-1.0F, -2.0F, -2.0F, 4, 12, 4, p_i46304_1_ + 0.25F); + this.field_178734_a.setRotationPoint(5.0F, 2.0F, 0.0F); + this.field_178732_b = new ModelRenderer(this, 40, 32); + this.field_178732_b.addBox(-3.0F, -2.0F, -2.0F, 4, 12, 4, p_i46304_1_ + 0.25F); + this.field_178732_b.setRotationPoint(-5.0F, 2.0F, 10.0F); + } + + this.bipedLeftLeg = new ModelRenderer(this, 16, 48); + this.bipedLeftLeg.addBox(-2.0F, 0.0F, -2.0F, 4, 12, 4, p_i46304_1_); + this.bipedLeftLeg.setRotationPoint(1.9F, 12.0F, 0.0F); + this.field_178733_c = new ModelRenderer(this, 0, 48); + this.field_178733_c.addBox(-2.0F, 0.0F, -2.0F, 4, 12, 4, p_i46304_1_ + 0.25F); + this.field_178733_c.setRotationPoint(1.9F, 12.0F, 0.0F); + this.field_178731_d = new ModelRenderer(this, 0, 32); + this.field_178731_d.addBox(-2.0F, 0.0F, -2.0F, 4, 12, 4, p_i46304_1_ + 0.25F); + this.field_178731_d.setRotationPoint(-1.9F, 12.0F, 0.0F); + this.field_178730_v = new ModelRenderer(this, 16, 32); + this.field_178730_v.addBox(-4.0F, 0.0F, -2.0F, 8, 12, 4, p_i46304_1_ + 0.25F); + this.field_178730_v.setRotationPoint(0.0F, 0.0F, 0.0F); + } + + /** + * Sets the models various rotation angles then renders the model. + */ + public void render(Entity p_78088_1_, float p_78088_2_, float p_78088_3_, float p_78088_4_, float p_78088_5_, float p_78088_6_, float p_78088_7_) { + super.render(p_78088_1_, p_78088_2_, p_78088_3_, p_78088_4_, p_78088_5_, p_78088_6_, p_78088_7_); + //EaglerAdapter.glPushMatrix(); + + //if (p_78088_1_ != null && p_78088_1_.isSneaking()) { + // EaglerAdapter.glTranslatef(0.0F, 0.2F, 0.0F); + //} + + this.field_178733_c.render(p_78088_7_); + this.field_178731_d.render(p_78088_7_); + this.field_178734_a.render(p_78088_7_); + this.field_178732_b.render(p_78088_7_); + this.field_178730_v.render(p_78088_7_); + + //EaglerAdapter.glPopMatrix(); + } + + public void func_178727_b(float p_178727_1_) { + func_178685_a(this.bipedHead, this.field_178736_x); + this.field_178736_x.rotationPointX = 0.0F; + this.field_178736_x.rotationPointY = 0.0F; + this.field_178736_x.render(p_178727_1_); + } + + public void func_178728_c(float p_178728_1_) { + this.field_178729_w.render(p_178728_1_); + } + + /** + * Sets the model's various rotation angles. For bipeds, par1 and par2 are used + * for animating the movement of arms and legs, where par1 represents the + * time(so that arms and legs swing back and forth) and par2 represents how + * "far" arms and legs can swing at most. + */ + public void setRotationAngles(float p_78087_1_, float p_78087_2_, float p_78087_3_, float p_78087_4_, float p_78087_5_, float p_78087_6_, Entity p_78087_7_) { + super.setRotationAngles(p_78087_1_, p_78087_2_, p_78087_3_, p_78087_4_, p_78087_5_, p_78087_6_, p_78087_7_); + func_178685_a(this.bipedLeftLeg, this.field_178733_c); + func_178685_a(this.bipedRightLeg, this.field_178731_d); + func_178685_a(this.bipedLeftArm, this.field_178734_a); + func_178685_a(this.bipedRightArm, this.field_178732_b); + func_178685_a(this.bipedBody, this.field_178730_v); + } + + public void func_178725_a() { + this.bipedRightArm.render(0.0625F); + this.field_178732_b.render(0.0625F); + } + + public void func_178726_b() { + this.bipedLeftArm.render(0.0625F); + this.field_178734_a.render(0.0625F); + } + + public void postRenderHiddenArm(float p_178718_1_) { + if (this.isAlex) { + ++this.bipedRightArm.rotationPointX; + this.bipedRightArm.postRender(p_178718_1_); + --this.bipedRightArm.rotationPointX; + } else { + this.bipedRightArm.postRender(p_178718_1_); + } + } + + public static void func_178685_a(ModelRenderer p_178685_0_, ModelRenderer p_178685_1_) + { + p_178685_1_.rotateAngleX = p_178685_0_.rotateAngleX; + p_178685_1_.rotateAngleY = p_178685_0_.rotateAngleY; + p_178685_1_.rotateAngleZ = p_178685_0_.rotateAngleZ; + p_178685_1_.rotationPointX = p_178685_0_.rotationPointX; + p_178685_1_.rotationPointY = p_178685_0_.rotationPointY; + p_178685_1_.rotationPointZ = p_178685_0_.rotationPointZ; + } + +} \ No newline at end of file diff --git a/src/main/java/net/lax1dude/eaglercraft/ModelLocation.java b/src/main/java/net/lax1dude/eaglercraft/ModelLocation.java new file mode 100644 index 0000000..029ce03 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/ModelLocation.java @@ -0,0 +1,23 @@ +package net.lax1dude.eaglercraft; + +import net.lax1dude.eaglercraft.glemu.HighPolyMesh; + +public class ModelLocation { + + public final String path; + private boolean loadAttempted = false; + private HighPolyMesh mesh; + + public ModelLocation(String path) { + this.path = path; + } + + public HighPolyMesh getModel() { + if(!loadAttempted) { + mesh = EaglerAdapter.loadMesh(path); + loadAttempted = true; + } + return mesh; + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/NoCatchParse.java b/src/main/java/net/lax1dude/eaglercraft/NoCatchParse.java new file mode 100644 index 0000000..dc19376 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/NoCatchParse.java @@ -0,0 +1,412 @@ +package net.lax1dude.eaglercraft; + +public class NoCatchParse { + + public static final int INT_EXCEPTION = Integer.MIN_VALUE; + public static final float FLOAT_EXCEPTION = Float.NaN; + public static final double DOUBLE_EXCEPTION = Double.NaN; + + public static int parseInt(String s) { + return parseInt(s, 10, false, INT_EXCEPTION); + } + + public static int parseInt(String s, int radix) { + return parseInt(s, radix, false, INT_EXCEPTION); + } + + public static int parseInt(String s, int radix, boolean log) { + return parseInt(s, radix, log, INT_EXCEPTION); + } + + public static int parseInt(String s, int radix, boolean log, int exceptionResult) { + if (s == null) { + if (log) { + System.err.println("parseInt: string was null"); + } + return exceptionResult; + } + + if (s.isEmpty()) { + if (log) { + System.err.println("parseInt: string was empty"); + } + return exceptionResult; + } + + if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) { + if (log) { + System.err.println("parseInt: invalid radix '" + radix + "'"); + } + return exceptionResult; + } + + tryFail: { + int result = 0; + boolean negative = false; + int i = 0, len = s.length(); + int limit = -Integer.MAX_VALUE; + int multmin; + int digit; + + if (len > 0) { + char firstChar = s.charAt(0); + if (firstChar < '0') { // Possible leading "+" or "-" + if (firstChar == '-') { + negative = true; + limit = Integer.MIN_VALUE; + } else if (firstChar != '+') + break tryFail; + + if (len == 1) + break tryFail; + i++; + } + multmin = limit / radix; + while (i < len) { + // Accumulating negatively avoids surprises near MAX_VALUE + digit = Character.digit(s.charAt(i++), radix); + if (digit < 0 || result < multmin) { + + break tryFail; + } + result *= radix; + if (result < limit + digit) { + break tryFail; + } + result -= digit; + } + } else { + break tryFail; + } + int ret = negative ? result : -result; + if (ret == exceptionResult) { + System.err.println( + "parseInt: number '" + s + "' was parsed successfully but it is equal to exceptionResult"); + } + return ret; + } + if (log) { + System.err.println("parseInt: cannot parse '" + s + "'"); + } + return exceptionResult; + } + + public static double parseDouble(String s) { + return parseDouble(s, false, DOUBLE_EXCEPTION); + } + + public static double parseDouble(String s, boolean log) { + return parseDouble(s, log, DOUBLE_EXCEPTION); + } + + public static double parseDouble(String s, boolean log, double exceptionResult) { + if (s == null) { + if (log) { + System.err.println("parseDouble: string was null"); + } + return exceptionResult; + } + + if (s.isEmpty()) { + if (log) { + System.err.println("parseDouble: string was empty"); + } + return exceptionResult; + } + + tryFail: { + int start = 0; + int end = s.length(); + while (s.charAt(start) <= ' ') { + if (++start == end) { + break tryFail; + } + } + while (s.charAt(end - 1) <= ' ') { + --end; + } + + boolean negative = false; + int index = start; + if (s.charAt(index) == '-') { + ++index; + negative = true; + } else if (s.charAt(index) == '+') { + ++index; + } + if (index == end) { + break tryFail; + } + char c = s.charAt(index); + + long mantissa = 0; + int exp = 0; + boolean hasOneDigit = false; + if (c != '.') { + hasOneDigit = true; + if (c < '0' || c > '9') { + break tryFail; + } + while (index < end && s.charAt(index) == '0') { + ++index; + } + while (index < end) { + c = s.charAt(index); + if (c < '0' || c > '9') { + break; + } + if (mantissa < Long.MAX_VALUE / 10 - 9) { + mantissa = mantissa * 10 + (c - '0'); + } else { + ++exp; + } + ++index; + } + } + if (index < end && s.charAt(index) == '.') { + ++index; + while (index < end) { + c = s.charAt(index); + if (c < '0' || c > '9') { + break; + } + if (mantissa < Long.MAX_VALUE / 10 - 9) { + mantissa = mantissa * 10 + (c - '0'); + --exp; + } + ++index; + hasOneDigit = true; + } + if (!hasOneDigit) { + break tryFail; + } + } + if (index < end) { + c = s.charAt(index); + if (c != 'e' && c != 'E') { + break tryFail; + } + ++index; + boolean negativeExp = false; + if (index == end) { + break tryFail; + } + if (s.charAt(index) == '-') { + ++index; + negativeExp = true; + } else if (s.charAt(index) == '+') { + ++index; + } + int numExp = 0; + hasOneDigit = false; + while (index < end) { + c = s.charAt(index); + if (c < '0' || c > '9') { + break; + } + numExp = 10 * numExp + (c - '0'); + hasOneDigit = true; + ++index; + } + if (!hasOneDigit) { + break tryFail; + } + if (negativeExp) { + numExp = -numExp; + } + exp += numExp; + } + if (exp > 308 || exp == 308 && mantissa > 17976931348623157L) { + return !negative ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY; + } + if (negative) { + mantissa = -mantissa; + } + return mantissa * doubleDecimalExponent(exp); + } + if (log) { + System.err.println("parseDouble: cannot parse '" + s + "'"); + } + return exceptionResult; + } + + public static double doubleDecimalExponent(int n) { + double d; + if (n < 0) { + d = 0.1; + n = -n; + } else { + d = 10; + } + double result = 1; + while (n != 0) { + if (n % 2 != 0) { + result *= d; + } + d *= d; + n /= 2; + } + return result; + } + + public static float parseFloat(String s) { + return parseFloat(s, false, FLOAT_EXCEPTION); + } + + public static float parseFloat(String s, boolean log) { + return parseFloat(s, log, FLOAT_EXCEPTION); + } + + public static float parseFloat(String s, boolean log, float exceptionResult) { + if (s == null) { + if (log) { + System.err.println("parseFloat: string was null"); + } + return exceptionResult; + } + + if (s.isEmpty()) { + if (log) { + System.err.println("parseFloat: string was empty"); + } + return exceptionResult; + } + + tryFail: { + int start = 0; + int end = s.length(); + while (s.charAt(start) <= ' ') { + if (++start == end) { + break tryFail; + } + } + while (s.charAt(end - 1) <= ' ') { + --end; + } + + boolean negative = false; + int index = start; + if (s.charAt(index) == '-') { + ++index; + negative = true; + } else if (s.charAt(index) == '+') { + ++index; + } + if (index == end) { + break tryFail; + } + char c = s.charAt(index); + + int mantissa = 0; + int exp = 0; + + boolean hasOneDigit = false; + if (c != '.') { + hasOneDigit = true; + if (c < '0' || c > '9') { + break tryFail; + } + + while (index < end && s.charAt(index) == '0') { + ++index; + } + while (index < end) { + c = s.charAt(index); + if (c < '0' || c > '9') { + break; + } + if (mantissa < (Integer.MAX_VALUE / 10) - 9) { + mantissa = mantissa * 10 + (c - '0'); + } else { + ++exp; + } + ++index; + } + } + + if (index < end && s.charAt(index) == '.') { + ++index; + while (index < end) { + c = s.charAt(index); + if (c < '0' || c > '9') { + break; + } + if (mantissa < (Integer.MAX_VALUE / 10) - 9) { + mantissa = mantissa * 10 + (c - '0'); + --exp; + } + ++index; + hasOneDigit = true; + } + if (!hasOneDigit) { + break tryFail; + } + } + if (index < end) { + c = s.charAt(index); + if (c != 'e' && c != 'E') { + break tryFail; + } + ++index; + boolean negativeExp = false; + if (index == end) { + break tryFail; + } + if (s.charAt(index) == '-') { + ++index; + negativeExp = true; + } else if (s.charAt(index) == '+') { + ++index; + } + int numExp = 0; + hasOneDigit = false; + while (index < end) { + c = s.charAt(index); + if (c < '0' || c > '9') { + break; + } + numExp = 10 * numExp + (c - '0'); + hasOneDigit = true; + ++index; + } + if (!hasOneDigit) { + break tryFail; + } + if (negativeExp) { + numExp = -numExp; + } + exp += numExp; + } + if (exp > 38 || exp == 38 && mantissa > 34028234) { + return !negative ? Float.POSITIVE_INFINITY : Float.NEGATIVE_INFINITY; + } + if (negative) { + mantissa = -mantissa; + } + return mantissa * floatDecimalExponent(exp); + } + if (log) { + System.err.println("parseFloat: cannot parse '" + s + "'"); + } + return exceptionResult; + } + + private static float floatDecimalExponent(int n) { + double d; + if (n < 0) { + d = 0.1; + n = -n; + } else { + d = 10; + } + double result = 1; + while (n != 0) { + if (n % 2 != 0) { + result *= d; + } + d *= d; + n /= 2; + } + return (float) result; + } +} diff --git a/src/main/java/net/lax1dude/eaglercraft/PKT.java b/src/main/java/net/lax1dude/eaglercraft/PKT.java new file mode 100644 index 0000000..103d8fb --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/PKT.java @@ -0,0 +1,13 @@ +package net.lax1dude.eaglercraft; + +public class PKT { + + public final String channel; + public final byte[] data; + + public PKT(String channel, byte[] data) { + this.channel = channel; + this.data = data; + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/ProfileUUID.java b/src/main/java/net/lax1dude/eaglercraft/ProfileUUID.java new file mode 100644 index 0000000..8352f1d --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/ProfileUUID.java @@ -0,0 +1,97 @@ +package net.lax1dude.eaglercraft; + +public class ProfileUUID { + + public final long msb; + public final long lsb; + + public ProfileUUID(long msb, long lsb) { + this.msb = msb; + this.lsb = lsb; + } + + public ProfileUUID(byte[] uuid) { + long msb = 0; + long lsb = 0; + for (int i = 0; i < 8; i++) + msb = (msb << 8) | (uuid[i] & 0xff); + for (int i = 8; i < 16; i++) + lsb = (lsb << 8) | (uuid[i] & 0xff); + this.msb = msb; + this.lsb = lsb; + } + + public ProfileUUID(String uuid) { + String[] components = uuid.split("-"); + if (components.length != 5) + throw new IllegalArgumentException("Invalid UUID string: " + uuid); + for (int i = 0; i < 5; i++) + components[i] = "0x" + components[i]; + + long mostSigBits = Long.decode(components[0]).longValue(); + mostSigBits <<= 16; + mostSigBits |= Long.decode(components[1]).longValue(); + mostSigBits <<= 16; + mostSigBits |= Long.decode(components[2]).longValue(); + + long leastSigBits = Long.decode(components[3]).longValue(); + leastSigBits <<= 48; + leastSigBits |= Long.decode(components[4]).longValue(); + + this.msb = mostSigBits; + this.lsb = leastSigBits; + } + + private static byte long7(long x) { return (byte)(x >> 56); } + private static byte long6(long x) { return (byte)(x >> 48); } + private static byte long5(long x) { return (byte)(x >> 40); } + private static byte long4(long x) { return (byte)(x >> 32); } + private static byte long3(long x) { return (byte)(x >> 24); } + private static byte long2(long x) { return (byte)(x >> 16); } + private static byte long1(long x) { return (byte)(x >> 8); } + private static byte long0(long x) { return (byte)(x ); } + + public byte[] getBytes() { + byte[] ret = new byte[16]; + ret[0] = long7(msb); + ret[1] = long6(msb); + ret[2] = long5(msb); + ret[3] = long4(msb); + ret[4] = long3(msb); + ret[5] = long2(msb); + ret[6] = long1(msb); + ret[7] = long0(msb); + ret[8] = long7(lsb); + ret[9] = long6(lsb); + ret[10] = long5(lsb); + ret[11] = long4(lsb); + ret[12] = long3(lsb); + ret[13] = long2(lsb); + ret[14] = long1(lsb); + ret[15] = long0(lsb); + return ret; + } + + @Override + public String toString() { + return (digits(msb >> 32, 8) + "-" + digits(msb >> 16, 4) + "-" + digits(msb, 4) + "-" + + digits(lsb >> 48, 4) + "-" + digits(lsb, 12)); + } + + private static String digits(long val, int digits) { + long hi = 1L << (digits * 4); + return Long.toHexString(hi | (val & (hi - 1))).substring(1); + } + + @Override + public int hashCode() { + long hilo = msb ^ lsb; + return ((int) (hilo >> 32)) ^ (int) hilo; + } + + @Override + public boolean equals(Object o) { + return (o instanceof ProfileUUID) && ((ProfileUUID)o).lsb == lsb && ((ProfileUUID)o).msb == msb; + } + +} \ No newline at end of file diff --git a/src/main/java/net/lax1dude/eaglercraft/RelayEntry.java b/src/main/java/net/lax1dude/eaglercraft/RelayEntry.java new file mode 100644 index 0000000..1b8288c --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/RelayEntry.java @@ -0,0 +1,15 @@ +package net.lax1dude.eaglercraft; + +public class RelayEntry { + + public final String address; + public final String comment; + public final boolean primary; + + public RelayEntry(String address, String comment, boolean primary) { + this.address = address; + this.comment = comment; + this.primary = primary; + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/RelayManager.java b/src/main/java/net/lax1dude/eaglercraft/RelayManager.java new file mode 100644 index 0000000..4365770 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/RelayManager.java @@ -0,0 +1,334 @@ +package net.lax1dude.eaglercraft; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.function.Consumer; + +import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket; +import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket00Handshake; +import net.lax1dude.eaglercraft.sp.relay.pkt.IPacketFFErrorCode; +import net.minecraft.src.NBTBase; +import net.minecraft.src.NBTTagCompound; +import net.minecraft.src.NBTTagList; + +public class RelayManager { + + private final List relays = new ArrayList<>(); + private long lastPingThrough = 0l; + + public void load(NBTTagList relayConfig) { + relays.clear(); + if(relayConfig != null && relayConfig.tagCount() > 0) { + boolean gotAPrimary = false; + for(int i = 0, l = relayConfig.tagCount(); i < l; ++i) { + NBTBase relay = relayConfig.tagAt(i); + if(relay instanceof NBTTagCompound) { + NBTTagCompound relayee = (NBTTagCompound) relay; + boolean p = relayee.getBoolean("primary"); + if(p) { + if(gotAPrimary) { + p = false; + }else { + gotAPrimary = true; + } + } + relays.add(new RelayServer(relayee.getString("addr"), relayee.getString("comment"), p)); + } + } + } + if(relays.size() == 0) { + for(int i = 0, l = ConfigConstants.relays.size(); i < l; ++i) { + relays.add(new RelayServer(ConfigConstants.relays.get(i))); + } + } + sort(); + } + + public void save() { + NBTTagList lst = new NBTTagList(); + for(int i = 0, l = relays.size(); i < l; ++i) { + RelayServer srv = relays.get(i); + NBTTagCompound etr = new NBTTagCompound(); + etr.setString("addr", srv.address); + etr.setString("comment", srv.comment); + etr.setBoolean("primary", srv.isPrimary()); + lst.appendTag(etr); + } + LocalStorageManager.gameSettingsStorage.setTag("relays", lst); + LocalStorageManager.saveStorageG(); + } + + private void sort() { + if(relays.size() == 0) { + return; + } + int j = -1; + for(int i = 0, l = relays.size(); i < l; ++i) { + if(relays.get(i).isPrimary()) { + if(j == -1) { + j = i; + }else { + relays.get(i).setPrimary(false); + } + } + } + if(j == -1) { + boolean found = false; + for(int i = 0, l = relays.size(); i < l; ++i) { + RelayServer srv = relays.get(i); + if(srv.getPing() > 0l) { + found = true; + srv.setPrimary(true); + break; + } + } + if(!found) { + relays.get(0).setPrimary(true); + } + }else { + RelayServer srv = relays.remove(j); + relays.add(0, srv); + } + } + + public void ping() { + lastPingThrough = EaglerAdapter.steadyTimeMillis(); + for(int i = 0, l = relays.size(); i < l; ++i) { + relays.get(i).ping(); + } + } + + public void update() { + for(int i = 0, l = relays.size(); i < l; ++i) { + relays.get(i).update(); + } + } + + public void close() { + for(int i = 0, l = relays.size(); i < l; ++i) { + relays.get(i).close(); + } + } + + public int count() { + return relays.size(); + } + + public RelayServer get(int idx) { + return relays.get(idx); + } + + public void add(String addr, String comment, boolean primary) { + lastPingThrough = 0l; + int i = relays.size(); + relays.add(new RelayServer(addr, comment, false)); + if(primary) { + setPrimary0(i); + } + save(); + } + + public void addNew(String addr, String comment, boolean primary) { + lastPingThrough = 0l; + int i = relays.size(); + int j = primary || i == 0 ? 0 : 1; + RelayServer newServer = new RelayServer(addr, comment, false); + relays.add(j, newServer); + newServer.ping(); + if(primary) { + setPrimary0(j); + } + save(); + } + + public void setPrimary(int idx) { + setPrimary0(idx); + save(); + } + + private void setPrimary0(int idx) { + if(idx >= 0 && idx < relays.size()) { + for(int i = 0, l = relays.size(); i < l; ++i) { + RelayServer srv = relays.get(i); + if(srv.isPrimary()) { + srv.setPrimary(false); + } + } + RelayServer pr = relays.remove(idx); + pr.setPrimary(true); + relays.add(0, pr); + } + } + + public void remove(int idx) { + RelayServer srv = relays.remove(idx); + srv.close(); + sort(); + save(); + } + + public RelayServer getPrimary() { + if(relays.size() > 0) { + for(int i = 0, l = relays.size(); i < l; ++i) { + RelayServer srv = relays.get(i); + if(srv.isPrimary()) { + return srv; + } + } + sort(); + save(); + return getPrimary(); + }else { + return null; + } + } + + public RelayServerSocket connectHandshake(RelayServer relay, int type, String code) { + RelayServerSocket sock = relay.openSocket(); + while(!sock.isClosed()) { + if(sock.isOpen()) { + sock.writePacket(new IPacket00Handshake(type, IntegratedServer.preferredRelayVersion, code)); + while(!sock.isClosed()) { + IPacket pkt = sock.nextPacket(); + if(pkt != null) { + if(pkt instanceof IPacket00Handshake) { + return sock; + }else if(pkt instanceof IPacketFFErrorCode) { + IPacketFFErrorCode ipkt = (IPacketFFErrorCode) pkt; + System.err.println("Relay [" + relay.address + "] failed: " + IPacketFFErrorCode.code2string(ipkt.code) + + "(" + ipkt.code + "): " + ipkt.desc); + Throwable t; + while((t = sock.getException()) != null) { + t.printStackTrace(); + } + sock.close(); + return null; + }else { + System.err.println("Relay [" + relay.address + "] unexpected packet: " + pkt.getClass().getSimpleName()); + sock.close(); + return null; + } + } + EaglerAdapter.sleep(20); + } + } + EaglerAdapter.sleep(20); + } + System.err.println("Relay [" + relay.address + "] connection failed!"); + Throwable t; + while((t = sock.getException()) != null) { + t.printStackTrace(); + } + return null; + } + + private final List brokenServers = new LinkedList<>(); + + public RelayServerSocket getWorkingRelay(Consumer progressCallback, int type, String code) { + brokenServers.clear(); + if(relays.size() > 0) { + long millis = EaglerAdapter.steadyTimeMillis(); + if(millis - lastPingThrough < 10000l) { + RelayServer relay = getPrimary(); + if(relay.getPing() > 0l && relay.getPingCompatible().isCompatible()) { + progressCallback.accept(relay.address); + RelayServerSocket sock = connectHandshake(relay, type, code); + if(sock != null) { + if(!sock.isFailed()) { + return sock; + } + }else { + brokenServers.add(relay); + } + } + for(int i = 0, l = relays.size(); i < l; ++i) { + RelayServer relayEtr = relays.get(i); + if(relayEtr != relay) { + if(relayEtr.getPing() > 0l && relayEtr.getPingCompatible().isCompatible()) { + progressCallback.accept(relayEtr.address); + RelayServerSocket sock = connectHandshake(relayEtr, type, code); + if(sock != null) { + if(!sock.isFailed()) { + return sock; + } + }else { + brokenServers.add(relayEtr); + } + } + } + } + } + return getWorkingCodeRelayActive(progressCallback, type, code); + }else { + return null; + } + } + + private RelayServerSocket getWorkingCodeRelayActive(Consumer progressCallback, int type, String code) { + if(relays.size() > 0) { + for(int i = 0, l = relays.size(); i < l; ++i) { + RelayServer srv = relays.get(i); + if(!brokenServers.contains(srv)) { + progressCallback.accept(srv.address); + RelayServerSocket sock = connectHandshake(srv, type, code); + if(sock != null) { + if(!sock.isFailed()) { + return sock; + } + }else { + brokenServers.add(srv); + } + } + } + return null; + }else { + return null; + } + } + + public void loadDefaults() { + int setPrimary = relays.size(); + eee: for(RelayEntry etr : ConfigConstants.relays) { + for(RelayServer exEtr : relays) { + if(exEtr.address.equalsIgnoreCase(etr.address)) { + continue eee; + } + } + relays.add(new RelayServer(etr)); + } + setPrimary(setPrimary); + } + + public String makeNewRelayName() { + String str = "Relay Server #" + (relays.size() + 1); + for(int i = relays.size() + 2, l = relays.size() + 50; i < l; ++i) { + if(str.equalsIgnoreCase("Relay Server #" + i)) { + str = "Relay Server #" + (i + 1); + } + } + eee: while(true) { + for(int i = 0, l = relays.size(); i < l; ++i) { + if(str.equalsIgnoreCase(relays.get(i).comment)) { + str = str + "_"; + continue eee; + } + } + break; + } + return str; + } + + public RelayServer getByURI(String uri) { + Iterator itr = relays.iterator(); + while(itr.hasNext()) { + RelayServer rl = itr.next(); + if(rl.address.equals(uri)) { + return rl; + } + } + return null; + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/RelayQuery.java b/src/main/java/net/lax1dude/eaglercraft/RelayQuery.java new file mode 100644 index 0000000..b105491 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/RelayQuery.java @@ -0,0 +1,26 @@ +package net.lax1dude.eaglercraft; + +import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.RateLimit; + +public interface RelayQuery { + + public static enum VersionMismatch { + COMPATIBLE, CLIENT_OUTDATED, RELAY_OUTDATED, UNKNOWN; + public boolean isCompatible() { + return this == COMPATIBLE; + } + } + + boolean isQueryOpen(); + boolean isQueryFailed(); + RateLimit isQueryRateLimit(); + void close(); + + int getVersion(); + String getComment(); + String getBrand(); + long getPing(); + + VersionMismatch getCompatible(); + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/RelayServer.java b/src/main/java/net/lax1dude/eaglercraft/RelayServer.java new file mode 100644 index 0000000..3bc2d75 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/RelayServer.java @@ -0,0 +1,118 @@ +package net.lax1dude.eaglercraft; + +import net.lax1dude.eaglercraft.RelayQuery.VersionMismatch; +import net.minecraft.src.Minecraft; + +public class RelayServer { + + public final String address; + public final String comment; + private boolean primary; + + private RelayQuery query = null; + private int queriedVersion = -1; + private String queriedComment; + private String queriedVendor; + private VersionMismatch queriedCompatible; + private long ping = 0l; + private long workingPing = 0l; + public long lastPing = 0l; + + public RelayServer(String address, String comment, boolean primary) { + this.address = address; + this.comment = comment; + this.primary = primary; + } + + public RelayServer(RelayEntry etr) { + this(etr.address, etr.comment, etr.primary); + } + + public boolean isPrimary() { + return primary; + } + + public void setPrimary(boolean primaryee) { + primary = primaryee; + } + + public long getPing() { + return ping; + } + + public long getWorkingPing() { + return workingPing; + } + + public int getPingVersion() { + return queriedVersion; + } + + public String getPingComment() { + return queriedComment == null ? "" : queriedComment; + } + + public String getPingVendor() { + return queriedVendor == null ? "" : queriedVendor; + } + + public VersionMismatch getPingCompatible() { + return queriedCompatible; + } + + public void pingBlocking() { + ping(); + while(getPing() < 0l) { + EaglerAdapter.sleep(250); + update(); + } + } + + public void ping() { + close(); + query = EaglerAdapter.openRelayQuery(address); + queriedVersion = -1; + queriedComment = null; + queriedVendor = null; + queriedCompatible = VersionMismatch.UNKNOWN; + ping = -1l; + } + + public void update() { + if(query != null && !query.isQueryOpen()) { + if(query.isQueryFailed()) { + queriedVersion = -1; + queriedComment = null; + queriedVendor = null; + queriedCompatible = VersionMismatch.UNKNOWN; + ping = 0l; + }else { + queriedVersion = query.getVersion(); + queriedComment = query.getComment(); + queriedVendor = query.getBrand(); + ping = query.getPing(); + queriedCompatible = query.getCompatible(); + workingPing = ping; + } + lastPing = EaglerAdapter.steadyTimeMillis(); + query = null; + } + } + + public void close() { + if(query != null && query.isQueryOpen()) { + query.close(); + query = null; + queriedVersion = -1; + queriedComment = null; + queriedVendor = null; + queriedCompatible = VersionMismatch.UNKNOWN; + ping = 0l; + } + } + + public RelayServerSocket openSocket() { + return EaglerAdapter.openRelayConnection(address, Minecraft.getMinecraft().gameSettings.relayTimeout * 1000); + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/RelayServerSocket.java b/src/main/java/net/lax1dude/eaglercraft/RelayServerSocket.java new file mode 100644 index 0000000..1394acf --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/RelayServerSocket.java @@ -0,0 +1,24 @@ +package net.lax1dude.eaglercraft; + +import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.RateLimit; +import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket; + +public interface RelayServerSocket { + + boolean isOpen(); + boolean isClosed(); + void close(); + + boolean isFailed(); + Throwable getException(); + + void writePacket(IPacket pkt); + + IPacket readPacket(); + IPacket nextPacket(); + + RateLimit getRatelimitHistory(); + + String getURI(); + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/RelayWorldsQuery.java b/src/main/java/net/lax1dude/eaglercraft/RelayWorldsQuery.java new file mode 100644 index 0000000..0e15460 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/RelayWorldsQuery.java @@ -0,0 +1,20 @@ +package net.lax1dude.eaglercraft; + +import java.util.List; + +import net.lax1dude.eaglercraft.RelayQuery.VersionMismatch; +import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.RateLimit; +import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket07LocalWorlds.LocalWorld; + +public interface RelayWorldsQuery { + + boolean isQueryOpen(); + boolean isQueryFailed(); + RateLimit isQueryRateLimit(); + void close(); + + List getWorlds(); + + VersionMismatch getCompatible(); + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/SHA1Digest.java b/src/main/java/net/lax1dude/eaglercraft/SHA1Digest.java new file mode 100644 index 0000000..2163594 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/SHA1Digest.java @@ -0,0 +1,258 @@ +package net.lax1dude.eaglercraft; + + +/** + * implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349. + * + * It is interesting to ponder why the, apart from the extra IV, the other difference here from MD5 + * is the "endienness" of the word processing! + */ +public class SHA1Digest + extends GeneralDigest +{ + private static final int DIGEST_LENGTH = 20; + + private int H1, H2, H3, H4, H5; + + private int[] X = new int[80]; + private int xOff; + + /** + * Standard constructor + */ + public SHA1Digest() + { + reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public SHA1Digest(SHA1Digest t) + { + super(t); + + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + H4 = t.H4; + H5 = t.H5; + + System.arraycopy(t.X, 0, X, 0, t.X.length); + xOff = t.xOff; + } + + public String getAlgorithmName() + { + return "SHA-1"; + } + + public int getDigestSize() + { + return DIGEST_LENGTH; + } + + protected void processWord( + byte[] in, + int inOff) + { + X[xOff++] = ((in[inOff] & 0xff) << 24) | ((in[inOff + 1] & 0xff) << 16) + | ((in[inOff + 2] & 0xff) << 8) | ((in[inOff + 3] & 0xff)); + + if (xOff == 16) + { + processBlock(); + } + } + + private void unpackWord( + int word, + byte[] out, + int outOff) + { + out[outOff] = (byte)(word >>> 24); + out[outOff + 1] = (byte)(word >>> 16); + out[outOff + 2] = (byte)(word >>> 8); + out[outOff + 3] = (byte)word; + } + + protected void processLength( + long bitLength) + { + if (xOff > 14) + { + processBlock(); + } + + X[14] = (int)(bitLength >>> 32); + X[15] = (int)(bitLength & 0xffffffff); + } + + public int doFinal( + byte[] out, + int outOff) + { + finish(); + + unpackWord(H1, out, outOff); + unpackWord(H2, out, outOff + 4); + unpackWord(H3, out, outOff + 8); + unpackWord(H4, out, outOff + 12); + unpackWord(H5, out, outOff + 16); + + reset(); + + return DIGEST_LENGTH; + } + + /** + * reset the chaining variables + */ + public void reset() + { + super.reset(); + + H1 = 0x67452301; + H2 = 0xefcdab89; + H3 = 0x98badcfe; + H4 = 0x10325476; + H5 = 0xc3d2e1f0; + + xOff = 0; + for (int i = 0; i != X.length; i++) + { + X[i] = 0; + } + } + + // + // Additive constants + // + private static final int Y1 = 0x5a827999; + private static final int Y2 = 0x6ed9eba1; + private static final int Y3 = 0x8f1bbcdc; + private static final int Y4 = 0xca62c1d6; + + private int f( + int u, + int v, + int w) + { + return ((u & v) | ((~u) & w)); + } + + private int h( + int u, + int v, + int w) + { + return (u ^ v ^ w); + } + + private int g( + int u, + int v, + int w) + { + return ((u & v) | (u & w) | (v & w)); + } + + private int rotateLeft( + int x, + int n) + { + return (x << n) | (x >>> (32 - n)); + } + + protected void processBlock() + { + // + // expand 16 word block into 80 word block. + // + for (int i = 16; i <= 79; i++) + { + X[i] = rotateLeft((X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16]), 1); + } + + // + // set up working variables. + // + int A = H1; + int B = H2; + int C = H3; + int D = H4; + int E = H5; + + // + // round 1 + // + for (int j = 0; j <= 19; j++) + { + int t = rotateLeft(A, 5) + f(B, C, D) + E + X[j] + Y1; + + E = D; + D = C; + C = rotateLeft(B, 30); + B = A; + A = t; + } + + // + // round 2 + // + for (int j = 20; j <= 39; j++) + { + int t = rotateLeft(A, 5) + h(B, C, D) + E + X[j] + Y2; + + E = D; + D = C; + C = rotateLeft(B, 30); + B = A; + A = t; + } + + // + // round 3 + // + for (int j = 40; j <= 59; j++) + { + int t = rotateLeft(A, 5) + g(B, C, D) + E + X[j] + Y3; + + E = D; + D = C; + C = rotateLeft(B, 30); + B = A; + A = t; + } + + // + // round 4 + // + for (int j = 60; j <= 79; j++) + { + int t = rotateLeft(A, 5) + h(B, C, D) + E + X[j] + Y4; + + E = D; + D = C; + C = rotateLeft(B, 30); + B = A; + A = t; + } + + H1 += A; + H2 += B; + H3 += C; + H4 += D; + H5 += E; + + // + // reset the offset and clean out the word buffer. + // + xOff = 0; + for (int i = 0; i != X.length; i++) + { + X[i] = 0; + } + } +} diff --git a/src/main/java/net/lax1dude/eaglercraft/ServerQuery.java b/src/main/java/net/lax1dude/eaglercraft/ServerQuery.java new file mode 100644 index 0000000..9ebf702 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/ServerQuery.java @@ -0,0 +1,132 @@ +package net.lax1dude.eaglercraft; + +import org.json.JSONObject; + +import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.RateLimit; + +public interface ServerQuery { + + public static final long defaultTimeout = 10000l; + + public static class QueryResponse { + public final String responseType; + private final Object responseData; + public final String serverVersion; + public final String serverBrand; + public final String serverName; + public final long serverTime; + public final long clientTime; + public final boolean serverCracked; + public final RateLimit rateLimitStatus; + public final boolean rateLimitIsTCP; + public final long ping; + public QueryResponse(JSONObject obj, long ping) { + this.responseType = obj.getString("type").toLowerCase(); + this.ping = ping; + if(this.responseType.equals("blocked") || this.responseType.equals("locked")) { + this.responseData = null; + this.serverVersion = "Unknown"; + this.serverBrand = "Unknown"; + this.serverName = "Unknown"; + this.serverTime = 0l; + this.clientTime = EaglerAdapter.steadyTimeMillis(); + this.serverCracked = false; + this.rateLimitStatus = this.responseType.equals("locked") ? RateLimit.LOCKED : RateLimit.BLOCKED; + this.rateLimitIsTCP = false; + }else { + this.responseData = obj.get("data"); + this.serverVersion = obj.getString("vers"); + this.serverBrand = obj.getString("brand"); + this.serverName = obj.getString("name"); + this.serverTime = obj.getLong("time"); + this.clientTime = EaglerAdapter.steadyTimeMillis(); + this.serverCracked = obj.optBoolean("cracked", false); + this.rateLimitStatus = null; + this.rateLimitIsTCP = false; + } + } + public QueryResponse(boolean lockedNotBlocked, long ping) { + this.ping = ping; + this.responseType = lockedNotBlocked ? "locked" : "blocked"; + this.responseData = null; + this.serverVersion = "Unknown"; + this.serverBrand = "Unknown"; + this.serverName = "Unknown"; + this.serverTime = 0l; + this.clientTime = EaglerAdapter.steadyTimeMillis(); + this.serverCracked = false; + this.rateLimitStatus = lockedNotBlocked ? RateLimit.LOCKED : RateLimit.BLOCKED; + this.rateLimitIsTCP = true; + } + public boolean isResponseString() { + return responseData instanceof String; + } + public boolean isResponseJSON() { + return responseData instanceof JSONObject; + } + public String getResponseString() { + return (String)responseData; + } + public JSONObject getResponseJSON() { + return (JSONObject)responseData; + } + } + + public boolean isQueryOpen(); + public void close(); + + public void send(String str); + + public default void send(JSONObject obj) { + send(obj.toString()); + } + + public int responseAvailable(); + public int responseBinaryAvailable(); + public QueryResponse getResponse(); + public byte[] getBinaryResponse(); + + // normally I wouldn't resort to race conditions but TeaVM has no + // java.util.concurrent classes for semaphore-like behavior + + public default boolean awaitResponseAvailable(long timeout) { + long start = EaglerAdapter.steadyTimeMillis(); + while(isQueryOpen() && responseAvailable() <= 0 && (timeout <= 0l || EaglerAdapter.steadyTimeMillis() - start < timeout)) { + EaglerAdapter.sleep(10); + } + return responseAvailable() > 0; + } + + public default boolean awaitResponseAvailable() { + return awaitResponseAvailable(defaultTimeout); + } + + public default boolean awaitResponseBinaryAvailable(long timeout) { + long start = EaglerAdapter.steadyTimeMillis(); + while(isQueryOpen() && responseBinaryAvailable() <= 0 && (timeout <= 0l || EaglerAdapter.steadyTimeMillis() - start < timeout)) { + EaglerAdapter.sleep(10); + } + return responseBinaryAvailable() > 0; + } + + public default boolean awaitResponseBinaryAvailable() { + return awaitResponseBinaryAvailable(defaultTimeout); + } + + public default QueryResponse awaitResponse(long timeout) { + return awaitResponseAvailable(timeout) ? getResponse() : null; + } + + public default QueryResponse awaitResponse() { + return awaitResponseAvailable() ? getResponse() : null; + } + + public default byte[] awaitResponseBinary(long timeout) { + return awaitResponseBinaryAvailable(timeout) ? getBinaryResponse() : null; + } + + public default byte[] awaitResponseBinary() { + return awaitResponseBinaryAvailable() ? getBinaryResponse() : null; + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/TextureLocation.java b/src/main/java/net/lax1dude/eaglercraft/TextureLocation.java new file mode 100644 index 0000000..27fea12 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/TextureLocation.java @@ -0,0 +1,38 @@ +package net.lax1dude.eaglercraft; + +import java.util.ArrayList; + +import net.minecraft.src.Minecraft; +import net.minecraft.src.RenderEngine; + +public class TextureLocation { + + private String path; + private int glObject; + + public TextureLocation(String path) { + this.path = path; + this.glObject = -1; + locations.add(this); + } + + public static void freeTextures() { + for(TextureLocation l : locations) { + l.glObject = -1; + } + } + + public void bindTexture() { + RenderEngine r = Minecraft.getMinecraft().renderEngine; + if(glObject == -1) { + glObject = r.getTexture(path); + if(glObject == -1) { + System.err.println("could not load: "+path); + } + } + r.bindTexture(glObject); + } + + private static final ArrayList locations = new ArrayList<>(); + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/TextureTerrainMap.java b/src/main/java/net/lax1dude/eaglercraft/TextureTerrainMap.java new file mode 100644 index 0000000..d800476 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/TextureTerrainMap.java @@ -0,0 +1,559 @@ +package net.lax1dude.eaglercraft; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.IntBuffer; +import java.util.ArrayList; + +import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.FramebufferGL; +import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.TextureGL; +import net.minecraft.src.Minecraft; +import net.minecraft.src.Block; +import net.minecraft.src.GLAllocation; +import net.minecraft.src.Icon; +import net.minecraft.src.IconRegister; +import net.minecraft.src.RenderManager; + +//supports only 16x16 textures, mipmap is four levels deep +public class TextureTerrainMap implements IconRegister { + + private static class TerrainIconV2 implements Icon { + + public final TextureTerrainMap map; + public final String name; + public final int id; + public final int size; + private TextureGL frames = null; + private int[] framesIdx = null; + + protected int originX; + protected int originY; + private float minU; + private float maxU; + private float minV; + private float maxV; + + protected int originX_center; + protected int originY_center; + private float minU_center; + private float maxU_center; + private float minV_center; + private float maxV_center; + + protected int frameCounter = 0; + protected int frameCurrent = 0; + + private TerrainIconV2(int id, int s, TextureTerrainMap map, String name) { + this.id = id; + this.size = s; + this.map = map; + this.name = name; + + if(s != 1 && s != 2) { + throw new IllegalArgumentException("Size " + s + " (" + (s * 16) + "px) is not supported on this texture map"); + } + + int tw = s * 16 + 32; + + int adjId = id; + if(s == 2) { + adjId = (map.width / tw - 1) * (map.height / tw - 1) - id; + } + + this.originX = (adjId % (map.width / tw)) * tw; + this.originY = (adjId / (map.width / tw)) * tw; + this.minU = (float)originX / (float)map.width; + this.minV = (float)originY / (float)map.height; + this.maxU = (float)(originX + tw) / (float)map.width; + this.maxV = (float)(originY + tw) / (float)map.height; + this.originX_center = originX + 16; + this.originY_center = originY + 16; + this.minU_center = (float)(originX_center + 0.025f) / (float)map.width; + this.minV_center = (float)(originY_center + 0.025f) / (float)map.height; + this.maxU_center = (float)(originX_center + 16 - 0.025f) / (float)map.width; + this.maxV_center = (float)(originY_center + 16 - 0.025f) / (float)map.height; + } + + private void free() { + if(frames != null) { + EaglerAdapter._wglDeleteTextures(frames); + frames = null; + } + } + + @Override + public int getOriginX() { + return originX_center; + } + + @Override + public int getOriginY() { + return originY_center; + } + + @Override + public float getMinU() { + return minU_center; + } + + @Override + public float getMaxU() { + return maxU_center; + } + + @Override + public float getInterpolatedU(double var1) { + float var3 = this.maxU_center - this.minU_center; + return this.minU_center + var3 * ((float) var1 * size / 16.0F); + } + + @Override + public float getMinV() { + return minV_center; + } + + @Override + public float getMaxV() { + return maxV_center; + } + + @Override + public float getInterpolatedV(double var1) { + float var3 = this.maxV_center - this.minV_center; + return this.minV_center + var3 * ((float) var1 * size / 16.0F); + } + + @Override + public String getIconName() { + return name == null ? "missingno" : name; + } + + @Override + public int getSheetWidth() { + return map.width; + } + + @Override + public int getSheetHeight() { + return map.height; + } + + private void updateAnimation() { + if(frames != null) { + this.frameCounter = (this.frameCounter + 1) % this.framesIdx.length; + int i = framesIdx[this.frameCounter]; + if (this.frameCurrent != i) { + this.frameCurrent = i; + map.copyFrame(this, i); + } + } + } + + private void loadData() { + byte[] data = Minecraft.getMinecraft().texturePackList.getSelectedTexturePack().getResourceAsBytes("/" + map.basePath + name + ".png"); + if(data == null) { + map.replaceTexture(this, map.missingData); + }else { + EaglerImage img = EaglerAdapter.loadPNG(data); + if(img == null) { + map.replaceTexture(this, map.missingData); + }else { + int ss = size * 16; + int divs = img.h / ss; + if(divs == 1) { + map.replaceTexture(this, generateMip(img)); + this.frames = null; + this.framesIdx = null; + }else { + map.replaceTexture(this, generateMip(img.getSubImage(0, 0, ss, ss))); + + EaglerAdapter.glBindTexture(EaglerAdapter.GL_TEXTURE_2D, -1); + frames = EaglerAdapter._wglGenTextures(); + EaglerAdapter.glBindTexture(EaglerAdapter.GL_TEXTURE_2D, frames); + + EaglerImage mipLvl = populateAlpha(img); + uploadBuffer.clear(); + uploadBuffer.put(mipLvl.data); + uploadBuffer.flip(); + EaglerAdapter.glTexImage2D(EaglerAdapter.GL_TEXTURE_2D, 0, EaglerAdapter.GL_RGBA, mipLvl.w, mipLvl.h, 0, + EaglerAdapter.GL_RGBA, EaglerAdapter.GL_UNSIGNED_BYTE, uploadBuffer); + + mipLvl = generateLevel(mipLvl); + uploadBuffer.clear(); + uploadBuffer.put(mipLvl.data); + uploadBuffer.flip(); + EaglerAdapter.glTexImage2D(EaglerAdapter.GL_TEXTURE_2D, 1, EaglerAdapter.GL_RGBA, mipLvl.w, mipLvl.h, 0, + EaglerAdapter.GL_RGBA, EaglerAdapter.GL_UNSIGNED_BYTE, uploadBuffer); + + mipLvl = generateLevel(mipLvl); + uploadBuffer.clear(); + uploadBuffer.put(mipLvl.data); + uploadBuffer.flip(); + EaglerAdapter.glTexImage2D(EaglerAdapter.GL_TEXTURE_2D, 2, EaglerAdapter.GL_RGBA, mipLvl.w, mipLvl.h, 0, + EaglerAdapter.GL_RGBA, EaglerAdapter.GL_UNSIGNED_BYTE, uploadBuffer); + + mipLvl = generateLevel(mipLvl); + uploadBuffer.clear(); + uploadBuffer.put(mipLvl.data); + uploadBuffer.flip(); + EaglerAdapter.glTexImage2D(EaglerAdapter.GL_TEXTURE_2D, 3, EaglerAdapter.GL_RGBA, mipLvl.w, mipLvl.h, 0, + EaglerAdapter.GL_RGBA, EaglerAdapter.GL_UNSIGNED_BYTE, uploadBuffer); + + mipLvl = generateLevel(mipLvl); + uploadBuffer.clear(); + uploadBuffer.put(mipLvl.data); + uploadBuffer.flip(); + EaglerAdapter.glTexImage2D(EaglerAdapter.GL_TEXTURE_2D, 4, EaglerAdapter.GL_RGBA, mipLvl.w, mipLvl.h, 0, + EaglerAdapter.GL_RGBA, EaglerAdapter.GL_UNSIGNED_BYTE, uploadBuffer); + + EaglerAdapter.glTexParameteri(EaglerAdapter.GL_TEXTURE_2D, EaglerAdapter.GL_TEXTURE_MAX_LEVEL, 4); + + String dat = EaglerMisc.bytesToString(Minecraft.getMinecraft().texturePackList.getSelectedTexturePack().getResourceAsBytes("/" + map.basePath + name + ".txt")); + if(dat != null) System.out.println("Found animation info for: " + map.basePath + name + ".png"); + if(dat == null || (dat = dat.trim()).isEmpty()) { + framesIdx = new int[divs]; + for(int i = 0; i < divs; ++i) { + framesIdx[i] = i; + } + }else { + String[] fd = dat.split(","); + int len = 0; + for(int i = 0; i < fd.length; ++i) { + int j = fd[i].indexOf('*'); + len += (j == -1 ? 1 : Integer.parseInt(fd[i].substring(j + 1))); + } + framesIdx = new int[len]; + len = 0; + for(int i = 0; i < fd.length; ++i) { + int j = fd[i].indexOf('*'); + if(j == -1) { + framesIdx[len++] = Integer.parseInt(fd[i]); + }else { + int c = Integer.parseInt(fd[i].substring(0, j)); + int l = Integer.parseInt(fd[i].substring(j + 1)); + for(int k = 0; k < l; ++k) { + framesIdx[len++] = c; + } + } + } + } + } + } + } + } + + } + + private final String basePath; + private final int width; + private final int height; + private TerrainIconV2 missingImage; + private ArrayList iconList; + public final int texture; + private final EaglerImage[] missingData; + public final FramebufferGL copyFramebuffer; + + private int[] nextSlot = new int[3]; + + private static final IntBuffer uploadBuffer = EaglerAdapter.isWebGL ? IntBuffer.wrap(new int[0xFFFF]) : + ByteBuffer.allocateDirect(0xFFFF << 2).order(ByteOrder.nativeOrder()).asIntBuffer(); + + public TextureTerrainMap(int size, String par2, String par3Str, EaglerImage par4BufferedImage) { + this.width = size; + this.height = size; + this.basePath = par3Str; + this.missingImage = new TerrainIconV2(nextSlot[1]++, 1, this, null); + this.iconList = new ArrayList<>(); + this.texture = EaglerAdapter.glGenTextures(); + this.copyFramebuffer = EaglerAdapter._wglCreateFramebuffer(); + EaglerAdapter.glBindTexture(EaglerAdapter.GL_TEXTURE_2D, texture); + int levelW = width; + int levelH = height; + IntBuffer blank = GLAllocation.createDirectIntBuffer(levelW * levelH); + for(int i = 0; i < 5; ++i) { + blank.clear().limit(levelW * levelH); + for(int j = 0; j < blank.limit(); ++j) { + blank.put(j, ((j / levelW + (j % levelW)) % 2 == 0) ? 0xffff00ff : 0xff000000); + } + EaglerAdapter.glTexImage2D(EaglerAdapter.GL_TEXTURE_2D, i, EaglerAdapter.GL_RGBA, levelW, levelH, 0, EaglerAdapter.GL_RGBA, EaglerAdapter.GL_UNSIGNED_BYTE, blank); + levelW /= 2; + levelH /= 2; + } + EaglerAdapter.glTexParameteri(EaglerAdapter.GL_TEXTURE_2D, EaglerAdapter.GL_TEXTURE_MIN_FILTER, EaglerAdapter.GL_NEAREST_MIPMAP_LINEAR); + EaglerAdapter.glTexParameteri(EaglerAdapter.GL_TEXTURE_2D, EaglerAdapter.GL_TEXTURE_MAG_FILTER, EaglerAdapter.GL_NEAREST); + EaglerAdapter.glTexParameteri(EaglerAdapter.GL_TEXTURE_2D, EaglerAdapter.GL_TEXTURE_WRAP_S, EaglerAdapter.GL_CLAMP); + EaglerAdapter.glTexParameteri(EaglerAdapter.GL_TEXTURE_2D, EaglerAdapter.GL_TEXTURE_WRAP_T, EaglerAdapter.GL_CLAMP); + EaglerAdapter.glTexParameteri(EaglerAdapter.GL_TEXTURE_2D, EaglerAdapter.GL_TEXTURE_MAX_LEVEL, 4); + EaglerAdapter.glTexParameterf(EaglerAdapter.GL_TEXTURE_2D, EaglerAdapter.GL_TEXTURE_MAX_ANISOTROPY, 1.0f); + replaceTexture(missingImage, missingData = generateMip(par4BufferedImage)); + } + + public static EaglerImage[] generateMip(EaglerImage src16x16) { + EaglerImage[] ret = new EaglerImage[5]; + ret[0] = populateAlpha(create3x3_V2(src16x16)); + ret[1] = generateLevel(ret[0]); + ret[2] = generateLevel(ret[1]); + ret[3] = generateLevel(ret[2]); + ret[4] = generateLevel(ret[3]); + return ret; + } + + public static EaglerImage generateLevel(EaglerImage src) { + EaglerImage e = new EaglerImage(src.w / 2, src.h / 2, true); + for(int y = 0; y < e.h; ++y) { + for(int x = 0; x < e.w; ++x) { + int x2 = x * 2; + int y2 = y * 2; + int a = src.data[y2 * src.w + x2]; + int b = src.data[y2 * src.w + x2 + 1]; + int c = src.data[(y2 + 1) * src.w + x2]; + int d = src.data[(y2 + 1) * src.w + x2 + 1]; + int ca = (((a >> 24) & 255) + ((b >> 24) & 255) + ((c >> 24) & 255) + ((d >> 24) & 255)) >> 2; + int cr = (((a >> 16) & 255) + ((b >> 16) & 255) + ((c >> 16) & 255) + ((d >> 16) & 255)) >> 2; + int cg = (((a >> 8) & 255) + ((b >> 8) & 255) + ((c >> 8) & 255) + ((d >> 8) & 255)) >> 2; + int cb = ((a & 255) + (b & 255) + (c & 255) + (d & 255)) >> 2; + e.data[y * e.w + x] = (ca << 24) | (cr << 16) | (cg << 8) | cb; + } + } + return e; + } + + public static EaglerImage populateAlpha(EaglerImage src) { + EaglerImage ret = new EaglerImage(src.w, src.h, true); + int reducedR = 0; + int reducedG = 0; + int reducedB = 0; + int divisor = 0; + int[] array = src.data; + for(int i = 0; i < array.length; ++i) { + int x = array[i]; + int a = (x >> 24) & 255; + if(a > 2) { + reducedR += (x >> 16) & 255; + reducedG += (x >> 8) & 255; + reducedB += x & 255; + ++divisor; + } + } + if(divisor == 0) { + reducedR = 0; + reducedG = 0; + reducedB = 0; + }else { + reducedR /= divisor; + reducedG /= divisor; + reducedB /= divisor; + } + int reducedR2, reducedG2, reducedB2, blend1, blend2, blend3, blend4, j; + int alpha = (reducedR << 16) | (reducedG << 8) | reducedB; + for(int i = 0; i < array.length; ++i) { + int x = array[i]; + int a = (x >> 24) & 255; + if(a < 2) { + reducedR2 = 0; + reducedG2 = 0; + reducedB2 = 0; + divisor = 0; + blend1 = i + 1; + blend2 = i - 1; + blend3 = i + src.w; + blend4 = i - src.w; + if(blend1 >= 0 && blend1 < array.length) { + j = array[blend1]; + if(((x >> 24) & 255) > 2){ + reducedR2 += (x >> 16) & 255; + reducedG2 += (x >> 8) & 255; + reducedB2 += x & 255; + ++divisor; + } + } + if(blend2 >= 0 && blend2 < array.length) { + j = array[blend2]; + if(((x >> 24) & 255) > 2){ + reducedR2 += (x >> 16) & 255; + reducedG2 += (x >> 8) & 255; + reducedB2 += x & 255; + ++divisor; + } + } + if(blend3 >= 0 && blend3 < array.length) { + j = array[blend3]; + if(((x >> 24) & 255) > 2){ + reducedR2 += (x >> 16) & 255; + reducedG2 += (x >> 8) & 255; + reducedB2 += x & 255; + ++divisor; + } + } + if(blend4 >= 0 && blend4 < array.length) { + j = array[blend4]; + if(((x >> 24) & 255) > 2){ + reducedR2 += (x >> 16) & 255; + reducedG2 += (x >> 8) & 255; + reducedB2 += x & 255; + ++divisor; + } + } + if(divisor == 0) { + ret.data[i] = alpha; + }else { + ret.data[i] = ((reducedR2 / divisor) << 16) | ((reducedG2 / divisor) << 8) | (reducedB2 / divisor); + } + }else { + ret.data[i] = src.data[i]; + } + } + return ret; + } + + public static EaglerImage create3x3_V2(EaglerImage src) { + EaglerImage ret = new EaglerImage(src.w + 32, src.h + 32, true); + for(int y = 0; y < src.h; ++y) { + for(int x = 0; x < src.w; ++x) { + int pixel = src.data[y * src.w + x]; + + ret.data[(y + 16) * ret.w + (x + 16)] = pixel; + + if(x < 16) { + ret.data[(y + 16) * ret.w + x] = pixel; + } + + if(y < 16) { + ret.data[y * ret.w + (x + 16)] = pixel; + } + + if(x < 16 && y < 16) { + ret.data[y * ret.w + x] = pixel; + } + + int mw = src.w - 16; + int mh = src.h - 16; + + if(x >= mw) { + ret.data[(y + 16) * ret.w + src.w + (x - mw + 16)] = pixel; + } + + if(y >= mh) { + ret.data[(y - mh + src.h + 16) * ret.w + (x + 16)] = pixel; + } + + if(x >= mw && y >= mh) { + ret.data[(y - mh + src.h + 16) * ret.w + src.w + (x - mw + 16)] = pixel; + } + + if(x >= mw && y < 16) { + ret.data[y * ret.w + src.w + (x - mw + 16)] = pixel; + } + + if(x < 16 && y >= mh) { + ret.data[(y - mh + src.h + 16) * ret.w + x] = pixel; + } + + } + } + return ret; + } + + public void refreshTextures() { + for(TerrainIconV2 t : iconList) { + t.free(); + } + iconList.clear(); + nextSlot = new int[3]; + nextSlot[1] = 1; + Block[] var1 = Block.blocksList; + int var2 = var1.length; + + for (int var3 = 0; var3 < var2; ++var3) { + Block var4 = var1[var3]; + + if (var4 != null) { + var4.registerIcons(this); + } + } + + Minecraft.getMinecraft().renderGlobal.registerDestroyBlockIcons(this); + RenderManager.instance.updateIcons(this); + + for(TerrainIconV2 t : iconList) { + t.loadData(); + } + } + + private void replaceTexture(TerrainIconV2 icon, EaglerImage[] textures) { + int divisor = 1; + EaglerAdapter.glBindTexture(EaglerAdapter.GL_TEXTURE_2D, texture); + for(int i = 0; i < 5; i++) { + uploadBuffer.clear(); + uploadBuffer.put(textures[i].data); + uploadBuffer.flip(); + EaglerAdapter.glTexSubImage2D(EaglerAdapter.GL_TEXTURE_2D, i, icon.originX / divisor, icon.originY / divisor, + (16 * icon.size + 32) / divisor, (16 * icon.size + 32) / divisor, EaglerAdapter.GL_RGBA, EaglerAdapter.GL_UNSIGNED_BYTE, uploadBuffer); + divisor *= 2; + } + } + + private void copyFrame(TerrainIconV2 icon, int frame) { + int off = icon.size * 16; + int divisor = 1; + EaglerAdapter._wglBindFramebuffer(EaglerAdapter._wGL_FRAMEBUFFER, copyFramebuffer); + EaglerAdapter._wglReadBuffer(EaglerAdapter._wGL_COLOR_ATTACHMENT0); + for(int i = 0; i < 5; i++) { + EaglerAdapter.glBindTexture(EaglerAdapter.GL_TEXTURE_2D, icon.frames); + EaglerAdapter._wglFramebufferTexture2D(EaglerAdapter._wGL_COLOR_ATTACHMENT0, icon.frames, i); + EaglerAdapter.glBindTexture(EaglerAdapter.GL_TEXTURE_2D, texture); + + // 0, -1 + EaglerAdapter.glCopyTexSubImage2D(EaglerAdapter.GL_TEXTURE_2D, i, icon.originX_center / divisor, (icon.originY_center - 16) / divisor, + 0, (frame * off + off - 16 / divisor), off, 16 / divisor); + + // -1, 0 + EaglerAdapter.glCopyTexSubImage2D(EaglerAdapter.GL_TEXTURE_2D, i, (icon.originX_center - 16) / divisor, icon.originY_center / divisor, + off - 16 / divisor, frame * off, 16 / divisor, off); + + // 0, 0 + EaglerAdapter.glCopyTexSubImage2D(EaglerAdapter.GL_TEXTURE_2D, i, icon.originX_center / divisor, icon.originY_center / divisor, + 0, frame * off, off, off); + + // 0, 1 + EaglerAdapter.glCopyTexSubImage2D(EaglerAdapter.GL_TEXTURE_2D, i, icon.originX_center / divisor, (icon.originY_center + 16 * icon.size) / divisor, + 0, frame * off, off, 16 / divisor); + + // 1, 0 + EaglerAdapter.glCopyTexSubImage2D(EaglerAdapter.GL_TEXTURE_2D, i, (icon.originX_center + 16 * icon.size) / divisor, icon.originY_center / divisor, + 0, frame * off, 16 / divisor, off); + + off /= 2; + divisor *= 2; + } + EaglerAdapter._wglBindFramebuffer(EaglerAdapter._wGL_FRAMEBUFFER, null); + } + + public void updateAnimations() { + for(TerrainIconV2 t : iconList) { + t.updateAnimation(); + } + } + + public Icon registerIcon(String par1Str, int w) { + if(w != 1 && w != 2) { + System.err.println("Error, texture '" + par1Str + "' was registered with size " + w + ", the terrain texure map only supports size 1 and 2 (16px and 32px)"); + return missingImage; + }else if(par1Str != null) { + for(TerrainIconV2 t : iconList) { + if(par1Str.equals(t.name) && w == t.size) { + return t; + } + } + TerrainIconV2 ret = new TerrainIconV2(nextSlot[w]++, w, this, par1Str); + iconList.add(ret); + return ret; + }else{ + return missingImage; + } + } + + public Icon getMissingIcon() { + return missingImage; + } +} diff --git a/src/main/java/net/lax1dude/eaglercraft/WebsocketNetworkManager.java b/src/main/java/net/lax1dude/eaglercraft/WebsocketNetworkManager.java new file mode 100644 index 0000000..674285f --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/WebsocketNetworkManager.java @@ -0,0 +1,144 @@ +package net.lax1dude.eaglercraft; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.util.LinkedList; + +import net.minecraft.src.INetworkManager; +import net.minecraft.src.NetHandler; +import net.minecraft.src.Packet; + +public class WebsocketNetworkManager implements INetworkManager { + + private NetHandler netHandler; + private String serverURI; + + public WebsocketNetworkManager(String uri, String eagler, NetHandler netHandler) throws IOException { + this.serverURI = uri; + this.netHandler = netHandler; + if(!EaglerAdapter.startConnection(uri)) { + throw new IOException("websocket to "+uri+" failed"); + } + EaglerAdapter.setDebugVar("minecraftServer", uri); + } + + public void setNetHandler(NetHandler netHandler) { + this.netHandler = netHandler; + } + + private ByteArrayOutputStream sendBuffer = new ByteArrayOutputStream(); + + public void addToSendQueue(Packet var1) { + try { + sendBuffer.reset(); + DataOutputStream yee = new DataOutputStream(sendBuffer); + Packet.writePacket(var1, yee); + EaglerAdapter.writePacket(sendBuffer.toByteArray()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void wakeThreads() { + } + + private static class ByteBufferDirectInputStream extends InputStream { + private ByteBuffer buf; + private ByteBufferDirectInputStream(ByteBuffer b) { + this.buf = b; + } + + @Override + public int read() throws IOException { + return buf.remaining() > 0 ? ((int)buf.get() & 0xFF) : -1; + } + + @Override + public int available() { + return buf.remaining(); + } + } + + private ByteBuffer oldChunkBuffer = null; + private LinkedList readChunks = new LinkedList<>(); + + public void processReadPackets() { + readChunks.clear(); + + if(oldChunkBuffer != null) { + readChunks.add(oldChunkBuffer); + } + + byte[] packet; + while((packet = EaglerAdapter.readPacket()) != null) { + readChunks.add(ByteBuffer.wrap(packet)); + } + if(!readChunks.isEmpty()) { + int cap = 0; + for(ByteBuffer b : readChunks) { + cap += b.limit(); + } + + ByteBuffer stream = ByteBuffer.allocate(cap); + for(ByteBuffer b : readChunks) { + stream.put(b); + } + stream.flip(); + + DataInputStream packetStream = new DataInputStream(new ByteBufferDirectInputStream(stream)); + while(stream.hasRemaining()) { + stream.mark(); + try { + Packet pkt = Packet.readPacket(packetStream, false); + pkt.processPacket(this.netHandler); + } catch (EOFException e) { + stream.reset(); + break; + } catch (IOException e) { + continue; + } catch (Throwable e2) { + e2.printStackTrace(); + } + } + + if(stream.hasRemaining()) { + oldChunkBuffer = stream.slice(); + }else { + oldChunkBuffer = null; + } + + } + } + + public void serverShutdown() { + if(EaglerAdapter.connectionOpen()) { + EaglerAdapter.endConnection(); + EaglerAdapter.setDebugVar("minecraftServer", "null"); + } + } + + public int packetSize() { + return 0; + } + + public void networkShutdown(String var1, Object... var2) { + serverShutdown(); + } + + public void closeConnections() { + if(EaglerAdapter.connectionOpen()) { + EaglerAdapter.endConnection(); + EaglerAdapter.setDebugVar("minecraftServer", "null"); + } + } + + public String getServerURI() { + return this.serverURI; + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/WorkerNetworkManager.java b/src/main/java/net/lax1dude/eaglercraft/WorkerNetworkManager.java new file mode 100644 index 0000000..8f75837 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/WorkerNetworkManager.java @@ -0,0 +1,121 @@ +package net.lax1dude.eaglercraft; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import net.minecraft.src.INetworkManager; +import net.minecraft.src.NetHandler; +import net.minecraft.src.Packet; + +public class WorkerNetworkManager implements INetworkManager { + + private NetHandler theNetHandler; + private String ipcChannel; + private boolean hasClosed; + + public WorkerNetworkManager(String ipcChannel, NetHandler netHandler) { + this.ipcChannel = ipcChannel; + this.theNetHandler = netHandler; + this.hasClosed = false; + } + + @Override + public void setNetHandler(NetHandler var1) { + theNetHandler = var1; + } + + private ByteArrayOutputStream sendBuffer = new ByteArrayOutputStream(); + + @Override + public void addToSendQueue(Packet var1) { + try { + sendBuffer.reset(); + Packet.writePacket(var1, new DataOutputStream(sendBuffer)); + EaglerAdapter.sendToIntegratedServer("NET|" + ipcChannel, sendBuffer.toByteArray()); + }catch(IOException e) { + System.err.println("Failed to serialize minecraft packet '" + var1.getClass().getSimpleName() + "' for IPC channel 'NET|" + ipcChannel + "'"); + e.printStackTrace(); + } + } + + @Override + public void wakeThreads() { + // no + } + + @Override + public void processReadPackets() { + PKT ipcPacket; + while((ipcPacket = EaglerAdapter.recieveFromIntegratedServer("NET|" + ipcChannel)) != null) { + byte[] bytes = ipcPacket.data; + try { + EaglerInputStream bai = new EaglerInputStream(bytes); + int pktId = bai.read(); + + if(pktId == -1) { + System.err.println("Recieved invalid '-1' packet"); + continue; + } + + Packet pkt = Packet.getNewPacket(pktId); + + if(pkt == null) { + System.err.println("Recieved invalid '" + pktId + "' packet"); + continue; + } + + pkt.readPacketData(new DataInputStream(bai)); + + //System.out.println("[Client][" + ipcChannel + "]: packet 0x" + Integer.toHexString(pkt.getPacketId()) + " class '" + pkt.getClass().getSimpleName() + "' recieved"); + + try { + pkt.processPacket(theNetHandler); + }catch(Throwable t) { + System.err.println("Could not process minecraft packet 0x" + Integer.toHexString(pkt.getPacketId()) + " class '" + pkt.getClass().getSimpleName() + "' on channel 'NET|" + ipcChannel + "'"); + t.printStackTrace(); + } + + }catch(IOException ex) { + System.err.println("Could not deserialize a " + bytes.length + " byte long minecraft packet of type '" + (bytes.length <= 0 ? -1 : (int)(bytes[0] & 0xFF)) + "' on channel 'NET|" + ipcChannel + "'"); + } + } + + } + + @Override + public void serverShutdown() { + if(!hasClosed) { + hasClosed = true; + IntegratedServer.closeChannel(ipcChannel); + } + } + + @Override + public void networkShutdown(String var1, Object... var2) { + if(!hasClosed) { + hasClosed = true; + IntegratedServer.closeChannel(ipcChannel); + } + } + + @Override + public int packetSize() { + return 0; + } + + @Override + public void closeConnections() { + if(!hasClosed) { + hasClosed = true; + IntegratedServer.closeChannel(ipcChannel); + } + } + + @Override + public String getServerURI() { + return "[integrated]"; + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/EaglerAdapterGL30.java b/src/main/java/net/lax1dude/eaglercraft/glemu/EaglerAdapterGL30.java new file mode 100644 index 0000000..91ff668 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/EaglerAdapterGL30.java @@ -0,0 +1,1653 @@ +package net.lax1dude.eaglercraft.glemu; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.HashMap; + +import net.lax1dude.eaglercraft.EaglerAdapter; +import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2; +import net.lax1dude.eaglercraft.glemu.StreamBuffer.StreamBufferInstance; +import net.lax1dude.eaglercraft.glemu.vector.Matrix4f; +import net.lax1dude.eaglercraft.glemu.vector.Vector3f; +import net.lax1dude.eaglercraft.glemu.vector.Vector4f; + +public class EaglerAdapterGL30 extends EaglerAdapterImpl2 { + + public static final int GL_ZERO = RealOpenGLEnums.GL_ZERO; + public static final int GL_ONE = RealOpenGLEnums.GL_ONE; + public static final int GL_TEXTURE_2D = RealOpenGLEnums.GL_TEXTURE_2D; + public static final int GL_SMOOTH = RealOpenGLEnums.GL_SMOOTH; + public static final int GL_DEPTH_TEST = RealOpenGLEnums.GL_DEPTH_TEST; + public static final int GL_LEQUAL = RealOpenGLEnums.GL_LEQUAL; + public static final int GL_ALPHA_TEST = RealOpenGLEnums.GL_ALPHA_TEST; + public static final int GL_GREATER = RealOpenGLEnums.GL_GREATER; + public static final int GL_BACK = RealOpenGLEnums.GL_BACK; + public static final int GL_PROJECTION = RealOpenGLEnums.GL_PROJECTION; + public static final int GL_MODELVIEW = RealOpenGLEnums.GL_MODELVIEW; + public static final int GL_COLOR_BUFFER_BIT = RealOpenGLEnums.GL_COLOR_BUFFER_BIT; + public static final int GL_DEPTH_BUFFER_BIT = RealOpenGLEnums.GL_DEPTH_BUFFER_BIT; + public static final int GL_LIGHTING = RealOpenGLEnums.GL_LIGHTING; + public static final int GL_FOG = RealOpenGLEnums.GL_FOG; + public static final int GL_COLOR_MATERIAL = RealOpenGLEnums.GL_COLOR_MATERIAL; + public static final int GL_BLEND = RealOpenGLEnums.GL_BLEND; + public static final int GL_RGBA = RealOpenGLEnums.GL_RGBA; + public static final int GL_UNSIGNED_BYTE = RealOpenGLEnums.GL_UNSIGNED_BYTE; + public static final int GL_TEXTURE_WIDTH = RealOpenGLEnums.GL_TEXTURE_WIDTH; + public static final int GL_LIGHT0 = RealOpenGLEnums.GL_LIGHT0; + public static final int GL_LIGHT1 = RealOpenGLEnums.GL_LIGHT1; + public static final int GL_POSITION = RealOpenGLEnums.GL_POSITION; + public static final int GL_DIFFUSE = RealOpenGLEnums.GL_DIFFUSE; + public static final int GL_SPECULAR = RealOpenGLEnums.GL_SPECULAR; + public static final int GL_AMBIENT = RealOpenGLEnums.GL_AMBIENT; + public static final int GL_FLAT = RealOpenGLEnums.GL_FLAT; + public static final int GL_LIGHT_MODEL_AMBIENT = RealOpenGLEnums.GL_LIGHT_MODEL_AMBIENT; + public static final int GL_FRONT_AND_BACK = RealOpenGLEnums.GL_FRONT_AND_BACK; + public static final int GL_AMBIENT_AND_DIFFUSE = RealOpenGLEnums.GL_AMBIENT_AND_DIFFUSE; + public static final int GL_MODELVIEW_MATRIX = RealOpenGLEnums.GL_MODELVIEW_MATRIX; + public static final int GL_PROJECTION_MATRIX = RealOpenGLEnums.GL_PROJECTION_MATRIX; + public static final int GL_VIEWPORT = RealOpenGLEnums.GL_VIEWPORT; + public static final int GL_RESCALE_NORMAL = RealOpenGLEnums.GL_RESCALE_NORMAL; + public static final int GL_SRC_ALPHA = RealOpenGLEnums.GL_SRC_ALPHA; + public static final int GL_ONE_MINUS_SRC_ALPHA = RealOpenGLEnums.GL_ONE_MINUS_SRC_ALPHA; + public static final int GL_ONE_MINUS_DST_COLOR = RealOpenGLEnums.GL_ONE_MINUS_DST_COLOR; + public static final int GL_ONE_MINUS_SRC_COLOR = RealOpenGLEnums.GL_ONE_MINUS_SRC_COLOR; + public static final int GL_CULL_FACE = RealOpenGLEnums.GL_CULL_FACE; + public static final int GL_TEXTURE_MIN_FILTER = RealOpenGLEnums.GL_TEXTURE_MIN_FILTER; + public static final int GL_TEXTURE_MAG_FILTER = RealOpenGLEnums.GL_TEXTURE_MAG_FILTER; + public static final int GL_LINEAR = RealOpenGLEnums.GL_LINEAR; + public static final int GL_COLOR_LOGIC_OP = RealOpenGLEnums.GL_COLOR_LOGIC_OP; + public static final int GL_OR_REVERSE = RealOpenGLEnums.GL_OR_REVERSE; + public static final int GL_EQUAL = RealOpenGLEnums.GL_EQUAL; + public static final int GL_SRC_COLOR = RealOpenGLEnums.GL_SRC_COLOR; + public static final int GL_TEXTURE = RealOpenGLEnums.GL_TEXTURE; + public static final int GL_FRONT = RealOpenGLEnums.GL_FRONT; + public static final int GL_COMPILE = RealOpenGLEnums.GL_COMPILE; + public static final int GL_S = RealOpenGLEnums.GL_S; + public static final int GL_T = RealOpenGLEnums.GL_T; + public static final int GL_R = RealOpenGLEnums.GL_R; + public static final int GL_Q = RealOpenGLEnums.GL_Q; + public static final int GL_TEXTURE_GEN_S = RealOpenGLEnums.GL_TEXTURE_GEN_S; + public static final int GL_TEXTURE_GEN_T = RealOpenGLEnums.GL_TEXTURE_GEN_T; + public static final int GL_TEXTURE_GEN_R = RealOpenGLEnums.GL_TEXTURE_GEN_R; + public static final int GL_TEXTURE_GEN_Q = RealOpenGLEnums.GL_TEXTURE_GEN_Q; + public static final int GL_TEXTURE_GEN_MODE = RealOpenGLEnums.GL_TEXTURE_GEN_MODE; + public static final int GL_OBJECT_PLANE = RealOpenGLEnums.GL_OBJECT_PLANE; + public static final int GL_EYE_PLANE = RealOpenGLEnums.GL_EYE_PLANE; + public static final int GL_OBJECT_LINEAR = RealOpenGLEnums.GL_OBJECT_LINEAR; + public static final int GL_EYE_LINEAR = RealOpenGLEnums.GL_EYE_LINEAR; + public static final int GL_NEAREST = RealOpenGLEnums.GL_NEAREST; + public static final int GL_CLAMP = RealOpenGLEnums.GL_CLAMP_TO_EDGE; + public static final int GL_TEXTURE_WRAP_S = RealOpenGLEnums.GL_TEXTURE_WRAP_S; + public static final int GL_TEXTURE_WRAP_T = RealOpenGLEnums.GL_TEXTURE_WRAP_T; + public static final int GL_REPEAT = RealOpenGLEnums.GL_REPEAT; + public static final int GL_BGRA = RealOpenGLEnums.GL_BGRA; + public static final int GL_UNSIGNED_INT_8_8_8_8_REV = RealOpenGLEnums.GL_UNSIGNED_INT_8_8_8_8_REV; + public static final int GL_DST_COLOR = RealOpenGLEnums.GL_DST_COLOR; + public static final int GL_CONSTANT_COLOR = RealOpenGLEnums.GL_CONSTANT_COLOR; + public static final int GL_ONE_MINUS_CONSTANT_COLOR = RealOpenGLEnums.GL_ONE_MINUS_CONSTANT_COLOR; + public static final int GL_CONSTANT_ALPHA = RealOpenGLEnums.GL_CONSTANT_ALPHA; + public static final int GL_ONE_MINUS_CONSTANT_ALPHA = RealOpenGLEnums.GL_ONE_MINUS_CONSTANT_ALPHA; + public static final int GL_POLYGON_OFFSET_FILL = RealOpenGLEnums.GL_POLYGON_OFFSET_FILL; + public static final int GL_NORMALIZE = RealOpenGLEnums.GL_NORMALIZE; + public static final int GL_DST_ALPHA = RealOpenGLEnums.GL_DST_ALPHA; + public static final int GL_FLOAT = RealOpenGLEnums.GL_FLOAT; + public static final int GL_TEXTURE_COORD_ARRAY = RealOpenGLEnums.GL_TEXTURE_COORD_ARRAY; + public static final int GL_SHORT = RealOpenGLEnums.GL_SHORT; + public static final int GL_COLOR_ARRAY = RealOpenGLEnums.GL_COLOR_ARRAY; + public static final int GL_VERTEX_ARRAY = RealOpenGLEnums.GL_VERTEX_ARRAY; + public static final int GL_TRIANGLES = RealOpenGLEnums.GL_TRIANGLES; + public static final int GL_NORMAL_ARRAY = RealOpenGLEnums.GL_NORMAL_ARRAY; + public static final int GL_TEXTURE_3D = RealOpenGLEnums.GL_TEXTURE_3D; + public static final int GL_FOG_MODE = RealOpenGLEnums.GL_FOG_MODE; + public static final int GL_EXP = RealOpenGLEnums.GL_EXP; + public static final int GL_FOG_DENSITY = RealOpenGLEnums.GL_FOG_DENSITY; + public static final int GL_FOG_START = RealOpenGLEnums.GL_FOG_START; + public static final int GL_FOG_END = RealOpenGLEnums.GL_FOG_END; + public static final int GL_FOG_COLOR = RealOpenGLEnums.GL_FOG_COLOR; + public static final int GL_TRIANGLE_STRIP = RealOpenGLEnums.GL_TRIANGLE_STRIP; + public static final int GL_PACK_ALIGNMENT = RealOpenGLEnums.GL_PACK_ALIGNMENT; + public static final int GL_UNPACK_ALIGNMENT = RealOpenGLEnums.GL_UNPACK_ALIGNMENT; + public static final int GL_QUADS = RealOpenGLEnums.GL_QUADS; + public static final int GL_TEXTURE0 = RealOpenGLEnums.GL_TEXTURE0; + public static final int GL_TEXTURE1 = RealOpenGLEnums.GL_TEXTURE1; + public static final int GL_TEXTURE2 = RealOpenGLEnums.GL_TEXTURE2; + public static final int GL_TEXTURE3 = RealOpenGLEnums.GL_TEXTURE3; + public static final int GL_INVALID_ENUM = RealOpenGLEnums.GL_INVALID_ENUM; + public static final int GL_INVALID_VALUE = RealOpenGLEnums.GL_INVALID_VALUE; + public static final int GL_INVALID_OPERATION = RealOpenGLEnums.GL_INVALID_OPERATION; + public static final int GL_OUT_OF_MEMORY = RealOpenGLEnums.GL_OUT_OF_MEMORY; + public static final int GL_CONTEXT_LOST_WEBGL = -100; + public static final int GL_TRIANGLE_FAN = RealOpenGLEnums.GL_TRIANGLE_FAN; + public static final int GL_LINE_STRIP = RealOpenGLEnums.GL_LINE_STRIP; + public static final int EAG_SWAP_RB = -101; + public static final int GL_LINES = RealOpenGLEnums.GL_LINES; + public static final int GL_NEAREST_MIPMAP_LINEAR = RealOpenGLEnums.GL_NEAREST_MIPMAP_LINEAR; + public static final int GL_TEXTURE_MAX_ANISOTROPY = -103; + public static final int GL_TEXTURE_MAX_LEVEL = RealOpenGLEnums.GL_TEXTURE_MAX_LEVEL; + public static final int GL_LINEAR_MIPMAP_LINEAR = RealOpenGLEnums.GL_LINEAR_MIPMAP_LINEAR; + public static final int GL_LINEAR_MIPMAP_NEAREST = RealOpenGLEnums.GL_LINEAR_MIPMAP_NEAREST; + public static final int GL_NEAREST_MIPMAP_NEAREST = RealOpenGLEnums.GL_NEAREST_MIPMAP_NEAREST; + + public static final boolean isWebGL = _wisWebGL(); + + static final GLObjectMap texObjects = new GLObjectMap<>(256); + + static boolean enableTexture2D = false; + static boolean enableTexture2D_1 = false; + static boolean enableLighting = false; + static boolean enableAlphaTest = false; + static float alphaThresh = 0.1f; + + static boolean isDepthTest = false; + static int currentDepthFunc = -99999; + static boolean isCullFace = false; + static int currentCullFace = -99999; + static boolean isPolygonOffset = false; + static float polygonOffset1 = -999.9f; + static float polygonOffset2 = -999.9f; + static boolean isBlend = false; + static int blendSRC = 0; + static int blendDST = 0; + static int colorMask = 15; + static boolean isDepthMask = true; + + static boolean isCompilingDisplayList = false; + static DisplayList compilingDisplayList = null; + + static boolean enableColorArray = false; + static boolean enableNormalArray = false; + static boolean enableTex0Array = false; + static boolean enableTex1Array = false; + + static boolean enableAnisotropicFix = false; + static int anisotropicFixSerial = 0; + static float anisotropicFixX = 1024.0f; + static float anisotropicFixY = 1024.0f; + + static int colorSerial = 0; + static float colorR = 1.0f; + static float colorG = 1.0f; + static float colorB = 1.0f; + static float colorA = 1.0f; + + static int normalSerial = 0; + static float normalX = 1.0f; + static float normalY = 0.0f; + static float normalZ = 0.0f; + + static int selectedTex = 0; + static int selectedClientTex = 0; + static int[] boundTexI = new int[2]; + static TextureGL[] boundTex = new TextureGL[2]; + static int tex0Serial = 0; + static float tex0X = 0; + static float tex0Y = 0; + static int tex1Serial = 0; + static float tex1X = 0; + static float tex1Y = 0; + static TextureGL boundTexture0 = null; + static boolean enableAnisotropicPatch = false; + static boolean hintAnisotropicPatch = false; + static boolean swapRB = false; + + public static final void anisotropicPatch(boolean e) { + enableAnisotropicPatch = e; + } + + static boolean enableTexGen = false; + static boolean enableColorMaterial = false; + + static int texPlaneSerial = 0; + static int texSSerial = 0; + static int texS_plane = 0; + static float texS_X = 0.0f; + static float texS_Y = 0.0f; + static float texS_Z = 0.0f; + static float texS_W = 0.0f; + + static int texTSerial = 0; + static int texT_plane = 0; + static float texT_X = 0.0f; + static float texT_Y = 0.0f; + static float texT_Z = 0.0f; + static float texT_W = 0.0f; + + static int texRSerial = 0; + static int texR_plane = 0; + static float texR_X = 0.0f; + static float texR_Y = 0.0f; + static float texR_Z = 0.0f; + static float texR_W = 0.0f; + + static int texQSerial = 0; + static int texQ_plane = 0; + static float texQ_X = 0.0f; + static float texQ_Y = 0.0f; + static float texQ_Z = 0.0f; + static float texQ_W = 0.0f; + + static int fogColorSerial = 0; + static float fogColorR = 1.0f; + static float fogColorG = 1.0f; + static float fogColorB = 1.0f; + static float fogColorA = 1.0f; + static int fogCfgSerial = 0; + static int fogMode = 1; + static boolean fogEnabled = false; + static float fogStart = 1.0f; + static float fogEnd = 1.0f; + static float fogDensity = 1.0f; + + static int bytesUploaded = 0; + static int vertexDrawn = 0; + static int triangleDrawn = 0; + + static int matrixMode = GL_MODELVIEW; + + static int matModelSerialCounter = 0; + static int[] matModelVSerial = new int[32]; + static Matrix4f[] matModelV = new Matrix4f[32]; + static int matModelPointer = 0; + + static int matProjSerialCounter = 0; + static int[] matProjVSerial = new int[6]; + static Matrix4f[] matProjV = new Matrix4f[6]; + static int matProjPointer = 0; + + static int matTexSerialCounter = 0; + static int[] matTexVSerial = new int[16]; + static Matrix4f[] matTexV = new Matrix4f[16]; + static int matTexPointer = 0; + + static { + for (int i = 0; i < matModelV.length; ++i) { + matModelV[i] = new Matrix4f(); + } + for (int i = 0; i < matProjV.length; ++i) { + matProjV[i] = new Matrix4f(); + } + for (int i = 0; i < matTexV.length; ++i) { + matTexV[i] = new Matrix4f(); + } + } + + public static void glClearStack() { + matModelV[0].load(matModelV[matModelPointer]); + matModelPointer = 0; + matProjV[0].load(matProjV[matProjPointer]); + matProjPointer = 0; + matTexV[0].load(matTexV[matTexPointer]); + matTexPointer = 0; + } + + private static BufferGL quadsToTrianglesBuffer = null; + private static BufferArrayGL currentArray = null; + + private static class DisplayList { + private final int id; + private BufferArrayGL glarray; + private BufferGL glbuffer; + private int shaderMode; + private int listLength; + + private DisplayList(int id) { + this.id = id; + this.glarray = null; + this.glbuffer = null; + this.shaderMode = -1; + this.listLength = 0; + } + } + + private static final HashMap displayLists = new HashMap<>(); + private static final HashMap displayListsInitialized = new HashMap<>(); + + public static final int getDisplayListCount() { + return displayListsInitialized.size(); + } + + public static final void glEnable(int p1) { + switch (p1) { + case GL_DEPTH_TEST: + if(!isDepthTest) { + _wglEnable(_wGL_DEPTH_TEST); + isDepthTest = true; + } + break; + case GL_CULL_FACE: + if(!isCullFace) { + _wglEnable(_wGL_CULL_FACE); + isCullFace = true; + } + break; + case GL_BLEND: + if(!isBlend) { + _wglEnable(_wGL_BLEND); + isBlend = true; + } + break; + case GL_RESCALE_NORMAL: + break; + case GL_TEXTURE_2D: + if (selectedTex == 0) { + enableTexture2D = true; + } + if (selectedTex == 1) { + enableTexture2D_1 = true; + } + break; + case GL_LIGHTING: + enableLighting = true; + break; + case GL_ALPHA_TEST: + enableAlphaTest = true; + break; + case GL_FOG: + fogEnabled = true; + break; + case GL_COLOR_MATERIAL: + enableColorMaterial = true; + break; + case GL_TEXTURE_GEN_S: + case GL_TEXTURE_GEN_T: + case GL_TEXTURE_GEN_R: + case GL_TEXTURE_GEN_Q: + enableTexGen = true; + break; + case GL_POLYGON_OFFSET_FILL: + if(!isPolygonOffset) { + _wglEnable(_wGL_POLYGON_OFFSET_FILL); + isPolygonOffset = true; + } + break; + case EAG_SWAP_RB: + swapRB = true; + break; + default: + break; + } + } + + public static final void glShadeModel(int p1) { + + } + + public static final void glClearDepth(float p1) { + _wglClearDepth(-p1); + } + + public static final void glDepthFunc(int p1) { + int f = _wGL_GEQUAL; + switch (p1) { + case GL_GREATER: + f = _wGL_LESS; + break; + case GL_LEQUAL: + f = _wGL_GEQUAL; + break; + case GL_EQUAL: + f = _wGL_EQUAL; + default: + break; + } + if(f != currentDepthFunc) { + _wglDepthFunc(f); + currentDepthFunc = f; + } + } + + public static final void glAlphaFunc(int p1, float p2) { + alphaThresh = p2; + } + + public static final void glCullFace(int p1) { + if(p1 != currentCullFace) { + _wglCullFace(p1); + currentCullFace = p1; + } + } + + public static final void glMatrixMode(int p1) { + matrixMode = p1; + } + + private static final Matrix4f getMatrixIncrSerial() { + switch (matrixMode) { + case GL_MODELVIEW: + default: + matModelVSerial[matModelPointer] = ++matModelSerialCounter; + return matModelV[matModelPointer]; + case GL_PROJECTION: + matProjVSerial[matProjPointer] = ++matProjSerialCounter; + return matProjV[matProjPointer]; + case GL_TEXTURE: + matTexVSerial[matTexPointer] = ++matTexSerialCounter; + return matTexV[matTexPointer]; + } + } + + public static final void glLoadIdentity() { + getMatrixIncrSerial().setIdentity(); + } + + public static final void glViewport(int p1, int p2, int p3, int p4) { + _wglViewport(p1, p2, p3, p4); + } + + public static final void glClear(int p1) { + _wglClear(p1); + } + + public static final void glOrtho(float left, float right, float bottom, float top, float zNear, float zFar) { + Matrix4f res = getMatrixIncrSerial(); + res.m00 = 2.0f / (right - left); + res.m01 = 0.0f; + res.m02 = 0.0f; + res.m03 = 0.0f; + res.m10 = 0.0f; + res.m11 = 2.0f / (top - bottom); + res.m12 = 0.0f; + res.m13 = 0.0f; + res.m20 = 0.0f; + res.m21 = 0.0f; + res.m22 = 2.0f / (zFar - zNear); + res.m23 = 0.0f; + res.m30 = -(right + left) / (right - left); + res.m31 = -(top + bottom) / (top - bottom); + res.m32 = (zFar + zNear) / (zFar - zNear); + res.m33 = 1.0f; + } + + private static final Vector3f deevis = new Vector3f(); + + public static final void glTranslatef(float p1, float p2, float p3) { + deevis.set(p1, p2, p3); + getMatrixIncrSerial().translate(deevis); + if (isCompilingDisplayList) { + System.err.println("matrix is not supported while recording display list use tessellator class instead"); + } + } + + public static final void glClearColor(float p1, float p2, float p3, float p4) { + _wglClearColor(p1, p2, p3, p4); + } + + public static final void glDisable(int p1) { + switch (p1) { + case GL_DEPTH_TEST: + if(isDepthTest) { + _wglDisable(_wGL_DEPTH_TEST); + isDepthTest = false; + } + break; + case GL_CULL_FACE: + if(isCullFace) { + _wglDisable(_wGL_CULL_FACE); + isCullFace = false; + } + break; + case GL_BLEND: + if(isBlend) { + _wglDisable(_wGL_BLEND); + isBlend = false; + } + break; + case GL_RESCALE_NORMAL: + break; + case GL_TEXTURE_2D: + if (selectedTex == 0) { + enableTexture2D = false; + } + if (selectedTex == 1) { + enableTexture2D_1 = false; + } + break; + case GL_LIGHTING: + enableLighting = false; + break; + case GL_ALPHA_TEST: + enableAlphaTest = false; + break; + case GL_FOG: + fogEnabled = false; + break; + case GL_COLOR_MATERIAL: + enableColorMaterial = false; + break; + case GL_TEXTURE_GEN_S: + case GL_TEXTURE_GEN_T: + case GL_TEXTURE_GEN_R: + case GL_TEXTURE_GEN_Q: + enableTexGen = false; + break; + case GL_POLYGON_OFFSET_FILL: + if(isPolygonOffset) { + _wglDisable(_wGL_POLYGON_OFFSET_FILL); + isPolygonOffset = false; + } + break; + case EAG_SWAP_RB: + swapRB = false; + break; + default: + break; + } + } + + public static final void glColor4f(float p1, float p2, float p3, float p4) { + ++colorSerial; + colorR = p1; + colorG = p2; + colorB = p3; + colorA = p4; + } + + public static final int glGetError() { + int err = _wglGetError(); + if (err == _wGL_CONTEXT_LOST_WEBGL) + return GL_CONTEXT_LOST_WEBGL; + return err; + } + + public static final void glFlush() { + EaglerAdapter._wglFlush(); + } + + public static final void glLineWidth(float p1) { + + } + + public static final void glTexImage2D(int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, + ByteBuffer p9) { + if (p2 == 0 && selectedTex == 0 && boundTexture0 != null) { + boundTexture0.w = p4; + boundTexture0.h = p5; + } + _wglTexImage2D(_wGL_TEXTURE_2D, p2, _wGL_RGBA8, p4, p5, p6, _wGL_RGBA, _wGL_UNSIGNED_BYTE, p9); + } + + public static final void glLight(int p1, int p2, FloatBuffer p3) { + + } + + public static final void glLightModel(int p1, FloatBuffer p2) { + + } + + static int lightPos0Serial = 0; + static int lightPos1Serial = 0; + private static Vector4f lightPos0vec0 = new Vector4f(); + private static Vector4f lightPos1vec0 = new Vector4f(); + static Vector4f lightPos0vec = new Vector4f(); + static Vector4f lightPos1vec = new Vector4f(); + + public static final void copyModelToLightMatrix() { + ++lightPos0Serial; + ++lightPos1Serial; + lightPos0vec0.set(lightPos0vec); + lightPos1vec0.set(lightPos1vec); + lightPos0vec.set(0.2f, 1.0f, -0.7f, 0.0f); + lightPos0vec.normalise(); + lightPos1vec.set(-0.2f, 1.0f, 0.7f, 0.0f); + lightPos1vec.normalise(); + Matrix4f.transform(matModelV[matModelPointer], lightPos0vec, lightPos0vec).normalise(); + Matrix4f.transform(matModelV[matModelPointer], lightPos1vec, lightPos1vec).normalise(); + } + + public static final void flipLightMatrix() { + ++lightPos0Serial; + ++lightPos1Serial; + lightPos0vec.x = -lightPos0vec.x; + lightPos1vec.x = -lightPos1vec.x; + lightPos0vec.y = -lightPos0vec.y; + lightPos1vec.y = -lightPos1vec.y; + lightPos0vec.z = -lightPos0vec.z; + lightPos1vec.z = -lightPos1vec.z; + } + + public static final void revertLightMatrix() { + ++lightPos0Serial; + ++lightPos1Serial; + lightPos0vec.set(lightPos0vec0); + lightPos1vec.set(lightPos1vec0); + } + + public static final void glPushMatrix() { + switch (matrixMode) { + case GL_MODELVIEW: + default: + if (matModelPointer < matModelV.length - 1) { + ++matModelPointer; + matModelV[matModelPointer].load(matModelV[matModelPointer - 1]); + matModelVSerial[matModelPointer] = matModelVSerial[matModelPointer - 1]; + } else { + System.err.println("modelview matrix stack overflow"); + } + break; + case GL_PROJECTION: + if (matProjPointer < matProjV.length - 1) { + ++matProjPointer; + matProjV[matProjPointer].load(matProjV[matProjPointer - 1]); + matProjVSerial[matProjPointer] = matProjVSerial[matProjPointer - 1]; + } else { + System.err.println("projection matrix stack overflow"); + } + break; + case GL_TEXTURE: + if (matTexPointer < matTexV.length - 1) { + ++matTexPointer; + matTexV[matTexPointer].load(matTexV[matTexPointer - 1]); + matTexVSerial[matTexPointer] = matTexVSerial[matTexPointer - 1]; + } else { + System.err.println("texture matrix stack overflow"); + } + break; + } + } + + private static final float toRad = 0.0174532925f; + + public static final void glRotatef(float p1, float p2, float p3, float p4) { + deevis.set(p2, p3, p4); + getMatrixIncrSerial().rotate(p1 * toRad, deevis); + if (isCompilingDisplayList) { + System.err.println("matrix is not supported while recording display list use tessellator class instead"); + } + } + + public static final void glPopMatrix() { + switch (matrixMode) { + case GL_MODELVIEW: + default: + if (matModelPointer > 0) { + --matModelPointer; + } else { + System.err.println("modelview matrix stack underflow"); + } + break; + case GL_PROJECTION: + if (matProjPointer > 0) { + --matProjPointer; + } else { + System.err.println("projection matrix stack underflow"); + } + break; + case GL_TEXTURE: + if (matTexPointer > 0) { + --matTexPointer; + } else { + System.err.println("texture matrix stack underflow"); + } + break; + } + } + + public static final void glColorMaterial(int p1, int p2) { + + } + + public static final void glGetFloat(int p1, FloatBuffer p2) { + switch (p1) { + case GL_MODELVIEW_MATRIX: + default: + matModelV[matModelPointer].store(p2); + break; + case GL_PROJECTION_MATRIX: + matProjV[matProjPointer].store(p2); + break; + } + } + + public static final void glGetInteger(int p1, int[] p2) { + if (p1 == GL_VIEWPORT) { + _wglGetParameter(_wGL_VIEWPORT, 4, p2); + } + } + + public static final void glScalef(float p1, float p2, float p3) { + deevis.set(p1, p2, p3); + getMatrixIncrSerial().scale(deevis); + if (isCompilingDisplayList) { + System.err.println("matrix is not supported while recording display list use tessellator class instead"); + } + } + + private static final Matrix4f tmpMat = new Matrix4f(); + + public static final void glMultMatrixf(Matrix4f mat) { + getMatrixIncrSerial().load(Matrix4f.mul(getMatrixIncrSerial(), mat, tmpMat)); + } + + public static final void glBlendFunc(int p1, int p2) { + if(overlayFBOBlending) { + int i = p1 | 0x10000; + int j = p2 | 0x10000; + if(blendSRC != i || blendDST != j) { + _wglBlendFuncSeparate(p1, p2, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + blendSRC = i; + blendDST = j; + } + }else { + if(blendSRC != p1 || blendDST != p2) { + _wglBlendFunc(p1, p2); + blendSRC = p1; + blendDST = p2; + } + } + } + + private static boolean overlayFBOBlending = false; + + public static final void enableOverlayFramebufferBlending(boolean en) { + overlayFBOBlending = en; + } + + public static final void glDepthMask(boolean p1) { + if(isDepthMask != p1) { + _wglDepthMask(p1); + isDepthMask = p1; + } + } + + public static final void glColorMask(boolean p1, boolean p2, boolean p3, boolean p4) { + int hsh = (p1 ? 1 : 0) | (p2 ? 2 : 0) | (p3 ? 4 : 0) | (p4 ? 8 : 0); + if(colorMask != hsh) { + _wglColorMask(p1, p2, p3, p4); + colorMask = hsh; + } + } + + private static final void updateAnisotropicPatch() { + if (selectedTex == 0) { + enableAnisotropicFix = false; + if (enableAnisotropicPatch && boundTexture0 != null && boundTexture0.anisotropic && boundTexture0.nearest) { + enableAnisotropicFix = true; + ++anisotropicFixSerial; + anisotropicFixX = boundTexture0.w; + anisotropicFixY = boundTexture0.h; + } + } + } + + public static final void glBindTexture(int p1, int p2) { + if(boundTexI[selectedTex] != p2) { + TextureGL t = texObjects.get(p2); + if(boundTex[selectedTex] != t) { + _wglBindTexture(_wGL_TEXTURE_2D, t); + if (selectedTex == 0) { + boundTexture0 = t; + updateAnisotropicPatch(); + } + boundTex[selectedTex] = t; + } + boundTexI[selectedTex] = p2; + } + } + + public static final void glBindTexture(int p1, TextureGL p2) { + boundTexI[selectedTex] = -1; + if(boundTex[selectedTex] != p2) { + _wglBindTexture(_wGL_TEXTURE_2D, p2); + if (selectedTex == 0) { + boundTexture0 = p2; + updateAnisotropicPatch(); + } + boundTex[selectedTex] = p2; + } + } + + public static final void glCopyTexSubImage2D(int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8) { + _wglCopyTexSubImage2D(_wGL_TEXTURE_2D, p2, p3, p4, p5, p6, p7, p8); + } + + public static final void glTexParameteri(int p1, int p2, int p3) { + if (selectedTex == 0 && boundTexture0 != null && p2 == GL_TEXTURE_MAG_FILTER) { + boundTexture0.nearest = p3 == GL_NEAREST; + } + _wglTexParameteri(p1, p2, p3); + updateAnisotropicPatch(); + } + + public static final void glTexParameterf(int p1, int p2, float p3) { + if(p2 == GL_TEXTURE_MAX_ANISOTROPY && !anisotropicFilteringSupported()) { + return; + } + if (selectedTex == 0 && boundTexture0 != null && p2 == GL_TEXTURE_MAX_ANISOTROPY) { + boundTexture0.anisotropic = p3 > 1.0f; + } + _wglTexParameterf(p1, p2 == GL_TEXTURE_MAX_ANISOTROPY ? _wGL_TEXTURE_MAX_ANISOTROPY : p2, p3); + updateAnisotropicPatch(); + } + + public static final void glLogicOp(int p1) { + + } + + public static final void glNormal3f(float p1, float p2, float p3) { + ++normalSerial; + float len = (float) Math.sqrt(p1 * p1 + p2 * p2 + p3 * p3); + normalX = p1 / len; + normalY = p2 / len; + normalZ = p3 / len; + } + + public static final int glGenLists(int p1) { + int base = displayListId + 1; + for (int i = 0; i < p1; i++) { + int id = ++displayListId; + displayLists.put(id, new DisplayList(id)); + } + return base; + } + + public static final void _wglBindVertexArray0(BufferArrayGL p1) { + if(currentArray != p1) { + currentArray = p1; + _wglBindVertexArray(p1); + } + } + + private static int displayListId = 0; + + public static final void glCallList(int p1) { + if (!isCompilingDisplayList) { + DisplayList d = displayListsInitialized.get(p1); + if (d != null && d.listLength > 0) { + bindTheShader(d.shaderMode | getShaderModeFlag1()); + _wglBindVertexArray0(d.glarray); + _wglDrawQuadArrays(0, d.listLength); + shader.unuseProgram(); + vertexDrawn += d.listLength * 6 / 4; + triangleDrawn += d.listLength / 2; + } + } + } + + public static final void glNewList(int p1, int p2) { + if (!isCompilingDisplayList) { + compilingDisplayList = displayLists.get(p1); + if (compilingDisplayList != null) { + compilingDisplayList.shaderMode = -1; + compilingDisplayList.listLength = 0; + isCompilingDisplayList = true; + } + } + } + + public static final void glEndList() { + if (isCompilingDisplayList) { + isCompilingDisplayList = false; + Object upload = _wGetLowLevelBuffersAppended(); + int l = _wArrayByteLength(upload); + if (l > 0) { + if (compilingDisplayList.glbuffer == null) { + displayListsInitialized.put(compilingDisplayList.id, compilingDisplayList); + compilingDisplayList.glarray = _wglCreateVertexArray(); + compilingDisplayList.glbuffer = _wglCreateBuffer(); + FixedFunctionShader f = FixedFunctionShader.instance(compilingDisplayList.shaderMode); + _wglBindVertexArray0(compilingDisplayList.glarray); + _wglBindBuffer(_wGL_ARRAY_BUFFER, compilingDisplayList.glbuffer); + f.setupArrayForProgram(); + } + _wglBindBuffer(_wGL_ARRAY_BUFFER, compilingDisplayList.glbuffer); + _wglBufferData(_wGL_ARRAY_BUFFER, upload, _wGL_STATIC_DRAW); + bytesUploaded += l; + } + } + } + + public static final void flushDisplayList(int p1) { + DisplayList d = displayListsInitialized.get(p1); + if (d != null) { + if (d.glbuffer != null) { + _wglDeleteBuffer(d.glbuffer); + _wglDeleteVertexArray(d.glarray); + d.glbuffer = null; + d.glarray = null; + } + } + } + + public static final HighPolyMesh loadMesh(String path) { + try { + HighPolyMesh ret = HighPolyMesh.loadMeshData(EaglerAdapter.loadResourceBytes(path)); + currentArray = ret.vertexArray; + return ret; + } catch (IOException ex) { + System.err.println("Could not load HighPolyMesh! " + ex.toString()); + ex.printStackTrace(); + return null; + } + } + + public static final void glColor3f(float p1, float p2, float p3) { + ++colorSerial; + colorR = p1; + colorG = p2; + colorB = p3; + colorA = 1.0f; + } + + public static final void glTexGeni(int p1, int p2, int p3) { + + } + + private static final Vector4f tmpTexGenPlane = new Vector4f(); + + public static final void glTexGen(int p1, int p2, FloatBuffer p3) { + Vector4f vec = tmpTexGenPlane; + vec.load(p3); + if(p2 == GL_EYE_PLANE) { + tmpMat.load(matModelV[matModelPointer]).invert().transpose(); + Matrix4f.transform(tmpMat, vec, vec); + } + switch (p1) { + case GL_S: + ++texPlaneSerial; + ++texSSerial; + texS_plane = (p2 == GL_EYE_PLANE ? 1 : 0); + texS_X = vec.x; + texS_Y = vec.y; + texS_Z = vec.z; + texS_W = vec.w; + break; + case GL_T: + ++texPlaneSerial; + ++texTSerial; + texT_plane = (p2 == GL_EYE_PLANE ? 1 : 0); + texT_X = vec.x; + texT_Y = vec.y; + texT_Z = vec.z; + texT_W = vec.w; + break; + case GL_R: + ++texPlaneSerial; + ++texRSerial; + texR_plane = (p2 == GL_EYE_PLANE ? 1 : 0); + texR_X = vec.x; + texR_Y = vec.y; + texR_Z = vec.z; + texR_W = vec.w; + break; + case GL_Q: + ++texPlaneSerial; + ++texQSerial; + texQ_plane = (p2 == GL_EYE_PLANE ? 1 : 0); + texQ_X = vec.x; + texQ_Y = vec.y; + texQ_Z = vec.z; + texQ_W = vec.w; + break; + } + } + + public static final void glTexImage2D(int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, + IntBuffer p9) { + /* + * int pp2 = 0; switch(p3) { default: case GL_RGBA: pp2 = _wGL_RGBA; break; case + * GL_BGRA: pp2 = _wGL_BGRA; break; } int pp3 = 0; switch(p7) { default: case + * GL_RGBA: pp3 = _wGL_RGBA; break; case GL_BGRA: pp3 = _wGL_BGRA; break; } + */ + if (p2 == 0 && selectedTex == 0 && boundTexture0 != null) { + boundTexture0.w = p4; + boundTexture0.h = p5; + } + bytesUploaded += p9.remaining() * 4; + _wglTexImage2D(_wGL_TEXTURE_2D, p2, _wGL_RGBA8, p4, p5, p6, _wGL_RGBA, _wGL_UNSIGNED_BYTE, p9); + updateAnisotropicPatch(); + } + + public static final void glTexImage2D_2(int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, + IntBuffer p9) { + if (p2 == 0 && selectedTex == 0 && boundTexture0 != null) { + boundTexture0.w = p4; + boundTexture0.h = p5; + } + bytesUploaded += p9.remaining() * 4; + _wglTexImage2D(_wGL_TEXTURE_2D, p2, _wGL_RGB8, p4, p5, p6, _wGL_RGB, _wGL_UNSIGNED_BYTE, p9); + updateAnisotropicPatch(); + } + + public static final void glTexSubImage2D(int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, + IntBuffer p9) { + int pp1 = 0; + switch (p1) { + default: + case GL_TEXTURE_2D: + pp1 = _wGL_TEXTURE_2D; + break; + // case GL_TEXTURE_3D: pp1 = _wGL_TEXTURE_3D; break; + } + /* + * int pp3 = 0; switch(p7) { default: case GL_RGBA: pp3 = _wGL_RGBA; break; case + * GL_BGRA: pp3 = _wGL_BGRA; break; } + */ + bytesUploaded += p9.remaining() * 4; + _wglTexSubImage2D(pp1, p2, p3, p4, p5, p6, _wGL_RGBA, _wGL_UNSIGNED_BYTE, p9); + } + + public static final void glDeleteTextures(int p1) { + _wglDeleteTextures(texObjects.free(p1)); + } + + public static final void glPolygonOffset(float p1, float p2) { + if(p1 != polygonOffset1 || p2 != polygonOffset2) { + _wglPolygonOffset(p1, p2); + polygonOffset1 = p1; + polygonOffset2 = p2; + } + } + + public static final void glCallLists(IntBuffer p1) { + while (p1.hasRemaining()) { + glCallList(p1.get()); + } + } + + public static final void glEnableVertexAttrib(int p1) { + switch (p1) { + case GL_COLOR_ARRAY: + enableColorArray = true; + break; + case GL_NORMAL_ARRAY: + enableNormalArray = true; + break; + case GL_TEXTURE_COORD_ARRAY: + switch (selectedClientTex) { + case 0: + enableTex0Array = true; + break; + case 1: + enableTex1Array = true; + break; + default: + break; + } + break; + default: + break; + } + } + + public static final void glDisableVertexAttrib(int p1) { + switch (p1) { + case GL_COLOR_ARRAY: + enableColorArray = false; + break; + case GL_NORMAL_ARRAY: + enableNormalArray = false; + break; + case GL_TEXTURE_COORD_ARRAY: + switch (selectedClientTex) { + case 0: + enableTex0Array = false; + break; + case 1: + enableTex1Array = false; + break; + default: + break; + } + break; + default: + break; + } + } + + public static final void hintAnisotropicFix(boolean hint) { + hintAnisotropicPatch = hint; + } + + private static final int getShaderModeFlag0() { + int mode = 0; + mode = (mode | (enableColorArray ? FixedFunctionShader.COLOR : 0)); + mode = (mode | (enableNormalArray ? FixedFunctionShader.NORMAL : 0)); + mode = (mode | (enableTex0Array ? FixedFunctionShader.TEXTURE0 : 0)); + mode = (mode | (enableTex1Array ? FixedFunctionShader.TEXTURE1 : 0)); + return mode; + } + + private static final int getShaderModeFlag1() { + int mode = 0; + mode = (mode | (enableTexGen ? FixedFunctionShader.TEXGEN : 0)); + mode = (mode | ((enableColorMaterial && enableLighting) ? FixedFunctionShader.LIGHTING : 0)); + mode = (mode | (fogEnabled ? FixedFunctionShader.FOG : 0)); + mode = (mode | (enableAlphaTest ? FixedFunctionShader.ALPHATEST : 0)); + mode = (mode | (enableTexture2D ? FixedFunctionShader.UNIT0 : 0)); + mode = (mode | (enableTexture2D_1 ? FixedFunctionShader.UNIT1 : 0)); + mode = (mode | ((enableTexture2D && (enableAnisotropicFix || (hintAnisotropicPatch && enableAnisotropicPatch))) + ? FixedFunctionShader.FIX_ANISOTROPIC + : 0)); + mode = (mode | (swapRB ? FixedFunctionShader.SWAP_RB : 0)); + return mode; + } + + private static final int getShaderModeFlag() { + int mode = 0; + mode = (mode | (enableColorArray ? FixedFunctionShader.COLOR : 0)); + mode = (mode | (enableNormalArray ? FixedFunctionShader.NORMAL : 0)); + mode = (mode | (enableTex0Array ? FixedFunctionShader.TEXTURE0 : 0)); + mode = (mode | (enableTex1Array ? FixedFunctionShader.TEXTURE1 : 0)); + mode = (mode | (enableTexGen ? FixedFunctionShader.TEXGEN : 0)); + mode = (mode | ((enableColorMaterial && enableLighting) ? FixedFunctionShader.LIGHTING : 0)); + mode = (mode | (fogEnabled ? FixedFunctionShader.FOG : 0)); + mode = (mode | (enableAlphaTest ? FixedFunctionShader.ALPHATEST : 0)); + mode = (mode | (enableTexture2D ? FixedFunctionShader.UNIT0 : 0)); + mode = (mode | (enableTexture2D_1 ? FixedFunctionShader.UNIT1 : 0)); + mode = (mode | ((enableTexture2D && (enableAnisotropicFix || (hintAnisotropicPatch && enableAnisotropicPatch))) + ? FixedFunctionShader.FIX_ANISOTROPIC + : 0)); + mode = (mode | (swapRB ? FixedFunctionShader.SWAP_RB : 0)); + return mode; + } + + private static FixedFunctionShader shader = null; + + private static final void bindTheShader() { + bindTheShader(getShaderModeFlag()); + } + + private static final void bindTheShader(int mode) { + FixedFunctionShader s = shader = FixedFunctionShader.instance(mode); + s.useProgram(); + s.update(); + } + + public static final void drawHighPoly(HighPolyMesh msh) { + bindTheShader((msh.hasTexture ? (FixedFunctionShader.NORMAL | FixedFunctionShader.TEXTURE0) + : FixedFunctionShader.NORMAL) | getShaderModeFlag1()); + _wglBindVertexArray0(msh.vertexArray); + _wglDrawElements(_wGL_TRIANGLES, msh.indexCount, _wGL_UNSIGNED_SHORT, 0); + triangleDrawn += msh.indexCount / 3; + shader.unuseProgram(); + } + + private static Object blankUploadArray = _wCreateLowLevelIntBuffer(525000); + + public static final void glDrawArrays(int p1, int p2, int p3, Object buffer) { + if (isCompilingDisplayList) { + if (p1 == GL_QUADS) { + if (compilingDisplayList.shaderMode == -1) { + compilingDisplayList.shaderMode = getShaderModeFlag0(); + } else { + if (compilingDisplayList.shaderMode != getShaderModeFlag0()) { + System.err.println("vertex format inconsistent in display list"); + } + } + compilingDisplayList.listLength += p3; + _wAppendLowLevelBuffer(buffer); + } else { + System.err.println("only GL_QUADS supported in a display list"); + } + } else { + int bl = _wArrayByteLength(buffer); + bytesUploaded += bl; + vertexDrawn += p3; + + bindTheShader(); + + StreamBufferInstance sb = shader.streamBuffer.getBuffer(bl); + _wglBindVertexArray0(sb.getVertexArray()); + _wglBindBuffer(_wGL_ARRAY_BUFFER, sb.getVertexBuffer()); + if (!shader.bufferIsInitialized) { + shader.bufferIsInitialized = true; + _wglBufferData(_wGL_ARRAY_BUFFER, blankUploadArray, _wGL_DYNAMIC_DRAW); + } + _wglBufferSubData(_wGL_ARRAY_BUFFER, 0, buffer); + + if (p1 == GL_QUADS) { + _wglDrawQuadArrays(p2, p3); + triangleDrawn += p3 / 2; + } else { + switch (p1) { + default: + case GL_TRIANGLES: + triangleDrawn += p3 / 3; + break; + case GL_TRIANGLE_STRIP: + triangleDrawn += p3 - 2; + break; + case GL_TRIANGLE_FAN: + triangleDrawn += p3 - 2; + break; + case GL_LINE_STRIP: + triangleDrawn += p3 - 1; + break; + case GL_LINES: + triangleDrawn += p3 / 2; + break; + } + _wglDrawArrays(p1, p2, p3); + } + + shader.unuseProgram(); + + } + } + + private static final void _wglDrawQuadArrays(int p2, int p3) { + if (quadsToTrianglesBuffer == null) { + IntBuffer upload = isWebGL ? IntBuffer.wrap(new int[98400 / 2]) + : ByteBuffer.allocateDirect(98400 * 2).order(ByteOrder.nativeOrder()).asIntBuffer(); + for (int i = 0; i < 16384; ++i) { + int v1 = i * 4; + int v2 = i * 4 + 1; + int v3 = i * 4 + 2; + int v4 = i * 4 + 3; + upload.put(v1 | (v2 << 16)); + upload.put(v4 | (v2 << 16)); + upload.put(v3 | (v4 << 16)); + } + upload.flip(); + quadsToTrianglesBuffer = _wglCreateBuffer(); + _wglBindBuffer(_wGL_ELEMENT_ARRAY_BUFFER, quadsToTrianglesBuffer); + _wglBufferData0(_wGL_ELEMENT_ARRAY_BUFFER, upload, _wGL_STATIC_DRAW); + } + if (!currentArray.isQuadBufferBound) { + currentArray.isQuadBufferBound = true; + _wglBindBuffer(_wGL_ELEMENT_ARRAY_BUFFER, quadsToTrianglesBuffer); + } + _wglDrawElements(_wGL_TRIANGLES, p3 * 6 / 4, _wGL_UNSIGNED_SHORT, p2 * 6 / 4); + } + + private static BufferArrayGL occlusion_vao = null; + private static BufferGL occlusion_vbo = null; + private static ProgramGL occlusion_program = null; + private static UniformGL occlusion_matrix_m = null; + private static UniformGL occlusion_matrix_p = null; + + private static final void initializeOcclusionObjects() { + occlusion_vao = _wglCreateVertexArray(); + occlusion_vbo = _wglCreateBuffer(); + + IntBuffer upload = (isWebGL ? IntBuffer.wrap(new int[108]) + : ByteBuffer.allocateDirect(108 << 2).order(ByteOrder.nativeOrder()).asIntBuffer()); + float[] verts = new float[] { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f }; + for (int i = 0; i < verts.length; i++) { + upload.put(Float.floatToRawIntBits(verts[i])); + } + upload.flip(); + + _wglBindVertexArray(occlusion_vao); + _wglBindBuffer(_wGL_ARRAY_BUFFER, occlusion_vbo); + _wglBufferData0(_wGL_ARRAY_BUFFER, upload, _wGL_STATIC_DRAW); + _wglEnableVertexAttribArray(0); + _wglVertexAttribPointer(0, 3, _wGL_FLOAT, false, 12, 0); + + ShaderGL vert = _wglCreateShader(_wGL_VERTEX_SHADER); + ShaderGL frag = _wglCreateShader(_wGL_FRAGMENT_SHADER); + + String src = fileContents("/glsl/occl.glsl"); + _wglShaderSource(vert, _wgetShaderHeader() + "\n#define CC_VERT\n" + src); + _wglShaderSource(frag, _wgetShaderHeader() + "\n#define CC_FRAG\n" + src); + + _wglCompileShader(vert); + if (!_wglGetShaderCompiled(vert)) + System.err.println(("\n" + _wglGetShaderInfoLog(vert)).replace("\n", "\n[/glsl/occl.glsl][VERT] ") + "\n"); + + _wglCompileShader(frag); + if (!_wglGetShaderCompiled(frag)) + System.err.println(("\n" + _wglGetShaderInfoLog(frag)).replace("\n", "\n[/glsl/occl.glsl][FRAG] ") + "\n"); + + occlusion_program = _wglCreateProgram(); + + _wglAttachShader(occlusion_program, vert); + _wglAttachShader(occlusion_program, frag); + _wglLinkProgram(occlusion_program); + _wglDetachShader(occlusion_program, vert); + _wglDetachShader(occlusion_program, frag); + _wglDeleteShader(vert); + _wglDeleteShader(frag); + + if (!_wglGetProgramLinked(occlusion_program)) + System.err.println( + ("\n\n" + _wglGetProgramInfoLog(occlusion_program)).replace("\n", "\n[/glsl/occl.glsl][LINKER] ")); + + _wglUseProgram(occlusion_program); + occlusion_matrix_m = _wglGetUniformLocation(occlusion_program, "matrix_m"); + occlusion_matrix_p = _wglGetUniformLocation(occlusion_program, "matrix_p"); + + } + + private static final GLObjectMap queryObjs = new GLObjectMap<>(256); + + public static final int glCreateQuery() { + return queryObjs.register(_wglCreateQuery()); + } + + public static final void glBeginQuery(int obj) { + _wglBeginQuery(_wGL_ANY_SAMPLES_PASSED, queryObjs.get(obj)); + } + + public static final void glDeleteQuery(int obj) { + _wglDeleteQuery(queryObjs.free(obj)); + } + + private static final Matrix4f cachedOcclusionP = (Matrix4f) (new Matrix4f()).setZero(); + private static float[] occlusionModel = new float[16]; + private static float[] occlusionProj = new float[16]; + + public static final void glBindOcclusionBB() { + if (occlusion_vao == null) + initializeOcclusionObjects(); + _wglUseProgram(occlusion_program); + _wglBindVertexArray0(occlusion_vao); + if (!cachedOcclusionP.equals(matProjV[matProjPointer])) { + cachedOcclusionP.load(matProjV[matProjPointer]); + cachedOcclusionP.store(occlusionProj); + _wglUniformMat4fv(occlusion_matrix_p, occlusionProj); + } + } + + public static final void glEndOcclusionBB() { + + } + + public static final void glDrawOcclusionBB(float posX, float posY, float posZ, float sizeX, float sizeY, + float sizeZ) { + glPushMatrix(); + glTranslatef(posX - sizeX * 0.01f, posY - sizeY * 0.01f, posZ - sizeZ * 0.01f); + glScalef(sizeX * 1.02f, sizeY * 1.02f, sizeZ * 1.02f); + matModelV[matModelPointer].store(occlusionModel); + _wglUniformMat4fv(occlusion_matrix_m, occlusionModel); + _wglDrawArrays(_wGL_TRIANGLES, 0, 36); + glPopMatrix(); + + } + + public static final void glEndQuery() { + _wglEndQuery(_wGL_ANY_SAMPLES_PASSED); + } + + public static final boolean glGetQueryResult(int obj) { + QueryGL q = queryObjs.get(obj); + return _wglGetQueryObjecti(q, _wGL_QUERY_RESULT) > 0; + } + + public static final boolean glGetQueryResultAvailable(int obj) { + QueryGL q = queryObjs.get(obj); + return _wglGetQueryObjecti(q, _wGL_QUERY_RESULT_AVAILABLE) > 0; + } + + public static final int glGenTextures() { + return texObjects.register(_wglGenTextures()); + } + + public static final void glTexSubImage2D(int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, + ByteBuffer p9) { + int pp1 = 0; + switch (p1) { + default: + case GL_TEXTURE_2D: + pp1 = _wGL_TEXTURE_2D; + break; + // case GL_TEXTURE_3D: pp1 = _wGL_TEXTURE_3D; break; + } + /* + * int pp3 = 0; switch(p7) { default: case GL_RGBA: pp3 = _wGL_RGBA; break; case + * GL_BGRA: pp3 = _wGL_BGRA; break; } + */ + bytesUploaded += p9.remaining(); + _wglTexSubImage2D(pp1, p2, p3, p4, p5, p6, _wGL_RGBA, _wGL_UNSIGNED_BYTE, p9); + } + + public static final void glFogi(int p1, int p2) { + if (p1 == GL_FOG_MODE) { + switch (p2) { + default: + case GL_LINEAR: + ++fogCfgSerial; + fogMode = 1; + break; + case GL_EXP: + ++fogCfgSerial; + fogMode = 2; + break; + } + } + } + + public static final void glFogf(int p1, float p2) { + switch (p1) { + case GL_FOG_START: + ++fogCfgSerial; + fogStart = p2; + break; + case GL_FOG_END: + ++fogCfgSerial; + fogEnd = p2; + break; + case GL_FOG_DENSITY: + ++fogCfgSerial; + fogDensity = p2; + break; + default: + break; + } + } + + public static final void glFog(int p1, FloatBuffer p2) { + if (p1 == GL_FOG_COLOR) { + ++fogColorSerial; + fogColorR = p2.get(); + fogColorG = p2.get(); + fogColorB = p2.get(); + fogColorA = p2.get(); + } + } + + public static final void glDeleteLists(int p1, int p2) { + for (int i = 0; i < p2; i++) { + DisplayList d = displayListsInitialized.remove(p1 + i); + if (d != null) { + _wglDeleteVertexArray(d.glarray); + _wglDeleteBuffer(d.glbuffer); + } + displayLists.remove(p1 + i); + } + } + + public static final void glActiveTexture(int p1) { + switch (p1) { + case GL_TEXTURE0: + if(selectedTex != 0) { + selectedTex = 0; + _wglActiveTexture(_wGL_TEXTURE0); + } + break; + case GL_TEXTURE1: + if(selectedTex != 1) { + selectedTex = 1; + _wglActiveTexture(_wGL_TEXTURE1); + } + break; + default: + System.err.println("only two texture units implemented"); + break; + } + } + + public static final void glClientActiveTexture(int p1) { + switch (p1) { + case GL_TEXTURE0: + selectedClientTex = 0; + break; + case GL_TEXTURE1: + selectedClientTex = 1; + break; + default: + System.err.println("only two texture units implemented"); + break; + } + } + + public static final void glMultiTexCoord2f(int p1, float p2, float p3) { + switch (p1) { + case GL_TEXTURE0: + ++tex0Serial; + tex0X = p2; + tex0Y = p3; + break; + case GL_TEXTURE1: + ++tex1Serial; + tex1X = p2; + tex1Y = p3; + break; + default: + System.err.println("only two texture units implemented"); + break; + } + } + + private static Matrix4f unprojA = new Matrix4f(); + private static Matrix4f unprojB = new Matrix4f(); + private static Vector4f unprojC = new Vector4f(); + + public static final void gluUnProject(float p1, float p2, float p3, FloatBuffer p4, FloatBuffer p5, int[] p6, + FloatBuffer p7) { + unprojA.load(p4); + unprojB.load(p5); + Matrix4f.mul(unprojA, unprojB, unprojB); + unprojB.invert(); + unprojC.set(((p1 - (float) p6[0]) / (float) p6[2]) * 2f - 1f, ((p2 - (float) p6[1]) / (float) p6[3]) * 2f - 1f, + p3, 1.0f); + Matrix4f.transform(unprojB, unprojC, unprojC); + p7.put(unprojC.x / unprojC.w); + p7.put(unprojC.y / unprojC.w); + p7.put(unprojC.z / unprojC.w); + } + + public static final void gluPerspective(float fovy, float aspect, float zNear, float zFar) { + Matrix4f res = getMatrixIncrSerial(); + float cotangent = (float) Math.cos(fovy * toRad * 0.5f) / (float) Math.sin(fovy * toRad * 0.5f); + res.m00 = cotangent / aspect; + res.m01 = 0.0f; + res.m02 = 0.0f; + res.m03 = 0.0f; + res.m10 = 0.0f; + res.m11 = cotangent; + res.m12 = 0.0f; + res.m13 = 0.0f; + res.m20 = 0.0f; + res.m21 = 0.0f; + res.m22 = (zFar + zNear) / (zFar - zNear); + res.m23 = -1.0f; + res.m30 = 0.0f; + res.m31 = 0.0f; + res.m32 = 2.0f * zFar * zNear / (zFar - zNear); + res.m33 = 0.0f; + } + + public static final void gluPerspectiveFlat(float fovy, float aspect, float zNear, float zFar) { + Matrix4f res = getMatrixIncrSerial(); + float cotangent = (float) Math.cos(fovy * toRad * 0.5f) / (float) Math.sin(fovy * toRad * 0.5f); + res.m00 = cotangent / aspect; + res.m01 = 0.0f; + res.m02 = 0.0f; + res.m03 = 0.0f; + res.m10 = 0.0f; + res.m11 = cotangent; + res.m12 = 0.0f; + res.m13 = 0.0f; + res.m20 = 0.0f; + res.m21 = 0.0f; + res.m22 = ((zFar + zNear) / (zFar - zNear)) * 0.001f; + res.m23 = -1.0f; + res.m30 = 0.0f; + res.m31 = 0.0f; + res.m32 = 2.0f * zFar * zNear / (zFar - zNear); + res.m33 = 0.0f; + } + + public static final String gluErrorString(int p1) { + switch (p1) { + case GL_INVALID_ENUM: + return "GL_INVALID_ENUM"; + case GL_INVALID_VALUE: + return "GL_INVALID_VALUE"; + case GL_INVALID_OPERATION: + return "GL_INVALID_OPERATION"; + case GL_OUT_OF_MEMORY: + return "GL_OUT_OF_MEMORY"; + case GL_CONTEXT_LOST_WEBGL: + return "CONTEXT_LOST_WEBGL"; + default: + return "Unknown Error"; + } + } + + public static final void optimize() { + FixedFunctionShader.optimize(); + } + + private static long lastBandwidthReset = 0l; + private static int lastBandwidth = 0; + + public static final int getBitsPerSecond() { + if (steadyTimeMillis() - lastBandwidthReset > 1000) { + lastBandwidthReset = steadyTimeMillis(); + lastBandwidth = bytesUploaded * 8; + bytesUploaded = 0; + } + return lastBandwidth; + } + + public static final int getVertexesPerSecond() { + int ret = vertexDrawn; + vertexDrawn = 0; + return ret; + } + + public static final int getTrianglesPerSecond() { + int ret = triangleDrawn; + triangleDrawn = 0; + return ret; + } + + public static boolean sync(int limitFramerate, long[] timerPtr) { + boolean limitFPS = limitFramerate > 0 && limitFramerate <= 1000; + boolean blocked = false; + + if(limitFPS) { + long frameMillis = (1000l / limitFramerate); + if(timerPtr[0] == 0l) { + timerPtr[0] = steadyTimeMillis() + frameMillis; + }else { + long millis = steadyTimeMillis(); + long remaining = timerPtr[0] - millis; + if(remaining > 0) { + if(isWebGL && immediateContinueSupported()) { + immediateContinue(); // cannot stack setTimeouts, or it will throttle + millis = steadyTimeMillis(); + remaining = timerPtr[0] - millis; + if(remaining > 0) { + sleep((int)remaining); + millis = steadyTimeMillis(); + } + }else { + sleep((int)remaining); + millis = steadyTimeMillis(); + } + blocked = true; + } + if((timerPtr[0] += frameMillis) < millis) { + timerPtr[0] = millis; + } + } + }else { + timerPtr[0] = 0l; + } + + return blocked; + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/EffectPipeline.java b/src/main/java/net/lax1dude/eaglercraft/glemu/EffectPipeline.java new file mode 100644 index 0000000..77a637c --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/EffectPipeline.java @@ -0,0 +1,295 @@ +package net.lax1dude.eaglercraft.glemu; + +import static net.lax1dude.eaglercraft.EaglerAdapter.*; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.IntBuffer; + +import net.lax1dude.eaglercraft.EaglercraftRandom; +import net.lax1dude.eaglercraft.adapter.Tessellator; +import net.minecraft.src.Minecraft; +import net.minecraft.src.EntityLiving; +import net.minecraft.src.GLAllocation; +import net.minecraft.src.MathHelper; + +public class EffectPipeline { + + private static FramebufferGL noiseGenFramebuffer = null; + private static TextureGL noiseGenTexture = null; + + private static ProgramGL noiseProgram = null; + private static TextureGL noiseSourceTexture = null; + private static UniformGL noiseCounter = null; + + private static BufferArrayGL renderQuadArray = null; + private static BufferGL renderQuadBuffer; + + private static final int NOISE_WIDTH = 128; + private static final int NOISE_HEIGHT = 128; + + private static boolean hasInit = false; + + public static void updateNoiseTexture(int viewportW, int viewportH, float intensity) { + if(!hasInit) { + hasInit = true; + String src = fileContents("/glsl/adderallNoise.glsl"); + if(src != null) { + renderQuadArray = _wglCreateVertexArray(); + renderQuadBuffer = _wglCreateBuffer(); + + IntBuffer upload = (isWebGL ? IntBuffer.wrap(new int[12]) : ByteBuffer.allocateDirect(12 << 2).order(ByteOrder.nativeOrder()).asIntBuffer()); + upload.put(Float.floatToRawIntBits(0.0f)); upload.put(Float.floatToRawIntBits(0.0f)); + upload.put(Float.floatToRawIntBits(0.0f)); upload.put(Float.floatToRawIntBits(1.0f)); + upload.put(Float.floatToRawIntBits(1.0f)); upload.put(Float.floatToRawIntBits(0.0f)); + upload.put(Float.floatToRawIntBits(0.0f)); upload.put(Float.floatToRawIntBits(1.0f)); + upload.put(Float.floatToRawIntBits(1.0f)); upload.put(Float.floatToRawIntBits(1.0f)); + upload.put(Float.floatToRawIntBits(1.0f)); upload.put(Float.floatToRawIntBits(0.0f)); + upload.flip(); + + _wglBindVertexArray0(renderQuadArray); + _wglBindBuffer(_wGL_ARRAY_BUFFER, renderQuadBuffer); + _wglBufferData0(_wGL_ARRAY_BUFFER, upload, _wGL_STATIC_DRAW); + _wglEnableVertexAttribArray(0); + _wglVertexAttribPointer(0, 2, _wGL_FLOAT, false, 8, 0); + + ShaderGL pvert_shader = _wglCreateShader(_wGL_VERTEX_SHADER); + + _wglShaderSource(pvert_shader, _wgetShaderHeader() + "\n" + fileContents("/glsl/pvert.glsl")); + _wglCompileShader(pvert_shader); + + if (!_wglGetShaderCompiled(pvert_shader)) System.err.println(("\n" + _wglGetShaderInfoLog(pvert_shader)).replace("\n", "\n[/glsl/pvert.glsl] ") + "\n"); + + ShaderGL noise_shader = _wglCreateShader(_wGL_FRAGMENT_SHADER); + _wglShaderSource(noise_shader, _wgetShaderHeader() + "\n" + src); + _wglCompileShader(noise_shader); + + if (!_wglGetShaderCompiled(noise_shader)) System.err.println(("\n" + _wglGetShaderInfoLog(noise_shader)).replace("\n", "\n[/glsl/fxaa.glsl] ") + "\n"); + + noiseProgram = _wglCreateProgram(); + _wglAttachShader(noiseProgram, pvert_shader); + _wglAttachShader(noiseProgram, noise_shader); + _wglLinkProgram(noiseProgram); + _wglDetachShader(noiseProgram, pvert_shader); + _wglDetachShader(noiseProgram, noise_shader); + _wglDeleteShader(pvert_shader); + _wglDeleteShader(noise_shader); + + if(!_wglGetProgramLinked(noiseProgram)) { + System.err.println(("\n"+_wglGetProgramInfoLog(noiseProgram)).replace("\n", "\n[/glsl/fxaa.glsl][LINKER] ") + "\n"); + noiseProgram = null; + throw new RuntimeException("Invalid shader code"); + } + + noiseCounter = _wglGetUniformLocation(noiseProgram, "counter"); + + noiseSourceTexture = _wglGenTextures(); + glBindTexture(_wGL_TEXTURE_2D, noiseSourceTexture); + _wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MAG_FILTER, _wGL_NEAREST); + _wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MIN_FILTER, _wGL_NEAREST); + _wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_S, _wGL_REPEAT); + _wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_T, _wGL_REPEAT); + + EaglercraftRandom noiseRandom = new EaglercraftRandom(696969696969l); + + byte[] b = new byte[NOISE_WIDTH * NOISE_HEIGHT]; + noiseRandom.nextBytes(b); + + ByteBuffer buf = GLAllocation.createDirectByteBuffer(NOISE_WIDTH * NOISE_HEIGHT); + buf.put(b); + buf.flip(); + + _wglTexImage2D(_wGL_TEXTURE_2D, 0, _wGL_R8, NOISE_WIDTH, NOISE_HEIGHT, 0, _wGL_RED, _wGL_UNSIGNED_BYTE, buf); + + noiseGenFramebuffer = _wglCreateFramebuffer(); + noiseGenTexture = _wglGenTextures(); + + glBindTexture(_wGL_TEXTURE_2D, noiseGenTexture); + _wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MAG_FILTER, _wGL_LINEAR); + _wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MIN_FILTER, _wGL_LINEAR); + _wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_S, _wGL_REPEAT); + _wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_T, _wGL_REPEAT); + + _wglTexImage2D(_wGL_TEXTURE_2D, 0, _wGL_RGBA, NOISE_WIDTH, NOISE_HEIGHT, 0, _wGL_RGBA, _wGL_UNSIGNED_BYTE, (ByteBuffer)null); + + _wglBindFramebuffer(_wGL_FRAMEBUFFER, noiseGenFramebuffer); + _wglFramebufferTexture2D(_wGL_COLOR_ATTACHMENT0, noiseGenTexture); + } + } + + if(noiseProgram != null) { + _wglBindFramebuffer(_wGL_FRAMEBUFFER, noiseGenFramebuffer); + _wglViewport(0, 0, NOISE_WIDTH, NOISE_HEIGHT); + _wglUseProgram(noiseProgram); + + long l = steadyTimeMillis(); + if(timer > 0l && l - timer < 20000l) { + counter += (float)((l - timer) * 0.0007) * intensity; + if(counter > 10000.0f) { + counter = 0.0f; + } + } + timer = l; + + _wglUniform1f(noiseCounter, counter * 3.0f); + + _wglBindVertexArray0(renderQuadArray); + glActiveTexture(_wGL_TEXTURE0); + glBindTexture(_wGL_TEXTURE_2D, noiseSourceTexture); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_BLEND); + glColorMask(true, true, true, true); + glDepthMask(false); + _wglDrawArrays(_wGL_TRIANGLES, 0, 6); + glColorMask(true, true, true, false); + glDepthMask(true); + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + _wglBindFramebuffer(_wGL_FRAMEBUFFER, null); + _wglViewport(0, 0, viewportW, viewportH); + } + + } + + private static float counter = 0.0f; + private static long timer = 0l; + + public static void drawNoise(int viewportW, int viewportH, float intensity) { + if(noiseProgram == null) { + return; + } + + glActiveTexture(_wGL_TEXTURE0); + glBindTexture(_wGL_TEXTURE_2D, noiseGenTexture); + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + glPushMatrix(); // 1 + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + + float aspect = (float) viewportW / viewportH; + + float bb = 3.0f * intensity; + float intensityModifier = 0.0f; + + EntityLiving lv = Minecraft.getMinecraft().renderViewEntity; + if(lv != null) { + int j = lv.getBrightnessForRender(0.0f); + intensityModifier = Math.min(1.0f - ((j / 65536) / 256.0f), 1.0f - ((j % 65536) / 256.0f)) * 3.0f; + bb += intensityModifier * bb; + } + + glColor4f(0.0166f * bb, 0.0166f * bb, 0.0166f * bb, 0.0f); + + glPushMatrix(); // 2 + + _wglBlendColor(0.0f, 0.0f, 0.0f, 1.0f - (intensity * 0.1f)); + glBlendFunc(GL_DST_COLOR, GL_CONSTANT_ALPHA); + + glMatrixMode(GL_TEXTURE); + glPushMatrix(); + glScalef(1.5f, 1.25f * aspect, 1.0f); + drawGradientTextureRect(1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f); + + if(intensityModifier > 1.5f) { + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + glColor4f(0.8f, 1.0f, 0.5f, (intensityModifier - 1.5f) * 0.03f * intensity); + glPushMatrix(); + glScalef(0.5f, 0.5f, 1.0f); + drawGradientTextureRect(1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f); + glPopMatrix(); + glColor4f(0.05f, 0.05f, 0.05f, 0.0f); + glBlendFunc(GL_DST_COLOR, GL_CONSTANT_ALPHA); + } + + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); // 2 + + float fs1 = MathHelper.sin(counter) + MathHelper.sin(counter * 0.7f + 0.3f) * 0.5f; + fs1 = fs1 * 0.1f; + float fs3 = MathHelper.sin(counter * 0.7f) + MathHelper.sin(counter * 1.1f + 0.6f) * 0.4f + + MathHelper.sin(counter * 2.3f + 1.1f) * 0.2f + MathHelper.sin(counter * 3.3f + 0.75f) * 0.3f; + + glPushMatrix(); // 1.5 + glRotatef(50.0f * fs1, 0.0f, 0.0f, 1.0f); + + _wglBlendColor(0.0f, 0.0f, 0.0f, 1.0f); + + for(int i = 0; i < 4; ++i) { + float fs2 = MathHelper.sin(counter * 0.7f + i * i * 0.2f) + MathHelper.sin(counter * 2.2f + 0.44f + i * 0.3f) * 0.2f + + MathHelper.sin(counter * 5.0f + 0.7f + i * i * 0.5f) * 0.2f; + + glPushMatrix(); // 2 + + glRotatef(90.0f * i, 0.0f, 0.0f, 1.0f); + glTranslatef(-fs1 * 0.1f, 0.3f + Math.max(fs3 * 0.25f + 0.1f, -0.25f), 0.0f); + + glRotatef(45.0f, 0.0f, 0.0f, 1.0f); + glScalef(1.5f, 0.7f, 1.0f); + glTranslatef(0.0f, 1.0f, 0.0f); + + float f1 = Math.max(fs1 * 0.5f + 1.0f, 0.0f); + glColor4f(0.1f * bb * f1, 0.1f * bb * f1, 0.1f * bb * f1, 0.0f); + + + + glMatrixMode(GL_TEXTURE); + glPushMatrix(); + + glTranslatef(-counter * 0.2f + fs1 * 1.4f, -counter * 0.2f, 0.0f); + glScalef(3.0f * 1.5f, 0.5f * aspect, 1.0f); + + drawGradientTextureRect(1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f); + glPopMatrix(); + + + glMatrixMode(GL_MODELVIEW); + + glTranslatef(0.0f, Math.max(fs2 * 0.5f + 1.0f, 0.0f) * 0.8f, 0.0f); + glMatrixMode(GL_TEXTURE); + + glPushMatrix(); + + glTranslatef(-counter * 0.2f, counter * 0.2f, 0.0f); + glScalef(3.0f * 1.5f, 0.3f * aspect, 1.0f); + + glRotatef(190.0f, 0.0f, 0.0f, 1.0f); + + glColor4f(0.1f * bb, 0.1f * bb, 0.1f * bb, 0.0f); + + drawGradientTextureRect(1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f); + glPopMatrix(); + + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); // 2 + } + + glPopMatrix(); // 1.5 + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); // 1 + glEnable(GL_ALPHA_TEST); + glDisable(GL_BLEND); + } + + private static void drawGradientTextureRect(float r1, float g1, float b1, float a1, float r2, float g2, float b2, float a2) { + Tessellator var9 = Tessellator.instance; + var9.startDrawingQuads(); + var9.setColorRGBA_F(r2, g2, b2, a2); + var9.addVertexWithUV(-1.0, -1.0, 0.0, 0.0, 0.0); + var9.addVertexWithUV(1.0, -1.0, 0.0, 1.0, 0.0); + var9.setColorRGBA_F(r1, g1, b1, a1); + var9.addVertexWithUV(1.0, 1.0, 0.0, 1.0, 1.0); + var9.addVertexWithUV(-1.0, 1.0, 0.0, 0.0, 1.0); + var9.draw(); + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/EffectPipelineFXAA.java b/src/main/java/net/lax1dude/eaglercraft/glemu/EffectPipelineFXAA.java new file mode 100644 index 0000000..7752ff6 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/EffectPipelineFXAA.java @@ -0,0 +1,233 @@ +package net.lax1dude.eaglercraft.glemu; + +import static net.lax1dude.eaglercraft.EaglerAdapter.*; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.IntBuffer; + +import net.lax1dude.eaglercraft.EaglerAdapter; +import net.minecraft.src.Minecraft; + +public class EffectPipelineFXAA { + + private static boolean isUsingFXAA = false; + + private static FramebufferGL framebuffer = null; + private static RenderbufferGL framebuffer_color = null; + private static RenderbufferGL framebuffer_depth = null; + + private static ProgramGL fxaaProgram = null; + private static TextureGL fxaaSourceTexture = null; + private static UniformGL fxaaScreenSize = null; + + private static BufferArrayGL renderQuadArray = null; + private static BufferGL renderQuadBuffer; + + public static int displayWidth = -1; + public static int displayHeight = -1; + public static int width = -1; + public static int height = -1; + + private static int[] originalViewport = new int[4]; + + private static int state = 1; + private static int newState = -1; + private static boolean msaaInit = false; + + private static void initFXAA() { + if(fxaaProgram == null) { + renderQuadArray = _wglCreateVertexArray(); + renderQuadBuffer = _wglCreateBuffer(); + + IntBuffer upload = (isWebGL ? IntBuffer.wrap(new int[12]) : ByteBuffer.allocateDirect(12 << 2).order(ByteOrder.nativeOrder()).asIntBuffer()); + upload.put(Float.floatToRawIntBits(0.0f)); upload.put(Float.floatToRawIntBits(0.0f)); + upload.put(Float.floatToRawIntBits(0.0f)); upload.put(Float.floatToRawIntBits(1.0f)); + upload.put(Float.floatToRawIntBits(1.0f)); upload.put(Float.floatToRawIntBits(0.0f)); + upload.put(Float.floatToRawIntBits(0.0f)); upload.put(Float.floatToRawIntBits(1.0f)); + upload.put(Float.floatToRawIntBits(1.0f)); upload.put(Float.floatToRawIntBits(1.0f)); + upload.put(Float.floatToRawIntBits(1.0f)); upload.put(Float.floatToRawIntBits(0.0f)); + upload.flip(); + + _wglBindVertexArray0(renderQuadArray); + _wglBindBuffer(_wGL_ARRAY_BUFFER, renderQuadBuffer); + _wglBufferData0(_wGL_ARRAY_BUFFER, upload, _wGL_STATIC_DRAW); + _wglEnableVertexAttribArray(0); + _wglVertexAttribPointer(0, 2, _wGL_FLOAT, false, 8, 0); + + ShaderGL pvert_shader = _wglCreateShader(_wGL_VERTEX_SHADER); + + _wglShaderSource(pvert_shader, _wgetShaderHeader() + "\n" + fileContents("/glsl/pvert.glsl")); + _wglCompileShader(pvert_shader); + + if (!_wglGetShaderCompiled(pvert_shader)) System.err.println(("\n" + _wglGetShaderInfoLog(pvert_shader)).replace("\n", "\n[/glsl/pvert.glsl] ") + "\n"); + + ShaderGL fxaa_shader = _wglCreateShader(_wGL_FRAGMENT_SHADER); + _wglShaderSource(fxaa_shader, _wgetShaderHeader() + "\n" + fileContents("/glsl/fxaa.glsl")); + _wglCompileShader(fxaa_shader); + + if (!_wglGetShaderCompiled(fxaa_shader)) System.err.println(("\n" + _wglGetShaderInfoLog(fxaa_shader)).replace("\n", "\n[/glsl/fxaa.glsl] ") + "\n"); + + fxaaProgram = _wglCreateProgram(); + _wglAttachShader(fxaaProgram, pvert_shader); + _wglAttachShader(fxaaProgram, fxaa_shader); + _wglLinkProgram(fxaaProgram); + _wglDetachShader(fxaaProgram, pvert_shader); + _wglDetachShader(fxaaProgram, fxaa_shader); + _wglDeleteShader(pvert_shader); + _wglDeleteShader(fxaa_shader); + + if(!_wglGetProgramLinked(fxaaProgram)) { + System.err.println(("\n"+_wglGetProgramInfoLog(fxaaProgram)).replace("\n", "\n[/glsl/fxaa.glsl][LINKER] ") + "\n"); + fxaaProgram = null; + throw new RuntimeException("Invalid shader code"); + } + + _wglUseProgram(fxaaProgram); + + UniformGL c = _wglGetUniformLocation(fxaaProgram, "f_color"); + if(c != null) _wglUniform1i(c, 0); + + fxaaScreenSize = _wglGetUniformLocation(fxaaProgram, "screenSize"); + } + + destroy(); + + isUsingFXAA = true; + framebuffer = _wglCreateFramebuffer(); + fxaaSourceTexture = _wglGenTextures(); + + glBindTexture(_wGL_TEXTURE_2D, fxaaSourceTexture); + _wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MAG_FILTER, _wGL_NEAREST); + _wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MIN_FILTER, _wGL_NEAREST); + _wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_S, _wGL_CLAMP); + _wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_T, _wGL_CLAMP); + _wglTexImage2D(_wGL_TEXTURE_2D, 0, _wGL_RGBA8, width, height, 0, _wGL_RGBA, _wGL_UNSIGNED_BYTE, (ByteBuffer)null); + + + framebuffer_depth = _wglCreateRenderBuffer(); + _wglBindRenderbuffer(framebuffer_depth); + _wglRenderbufferStorage(_wGL_DEPTH_COMPONENT32F, width, height); + + _wglBindFramebuffer(_wGL_FRAMEBUFFER, framebuffer); + _wglFramebufferTexture2D(_wGL_COLOR_ATTACHMENT0, fxaaSourceTexture); + _wglFramebufferRenderbuffer(_wGL_DEPTH_ATTACHMENT, framebuffer_depth); + } + + private static void initMSAA() { + destroy(); + msaaInit = true; + framebuffer = _wglCreateFramebuffer(); + framebuffer_color = _wglCreateRenderBuffer(); + framebuffer_depth = _wglCreateRenderBuffer(); + _wglBindFramebuffer(_wGL_FRAMEBUFFER, framebuffer); + _wglBindRenderbuffer(framebuffer_color); + _wglRenderbufferStorageMultisample(state == 2 ? 4 : 8, _wGL_RGBA8, width, height); + _wglBindRenderbuffer(framebuffer_depth); + _wglRenderbufferStorageMultisample(state == 2 ? 4 : 8, _wGL_DEPTH_COMPONENT32F, width, height); + _wglFramebufferRenderbuffer(_wGL_COLOR_ATTACHMENT0, framebuffer_color); + _wglFramebufferRenderbuffer(_wGL_DEPTH_ATTACHMENT, framebuffer_depth); + } + + public static void destroy() { + isUsingFXAA = false; + msaaInit = false; + if(framebuffer != null) _wglDeleteFramebuffer(framebuffer); + if(framebuffer_color != null) _wglDeleteRenderbuffer(framebuffer_color); + if(framebuffer_depth != null) _wglDeleteRenderbuffer(framebuffer_depth); + if(fxaaSourceTexture != null) _wglDeleteTextures(fxaaSourceTexture); + framebuffer = null; + framebuffer_color = null; + framebuffer_depth = null; + fxaaSourceTexture = null; + } + + public static void beginPipelineRender() { + if(displayWidth <= 0 || displayHeight <= 0) { + return; + } + int mode = Minecraft.getMinecraft().gameSettings.antialiasMode; + if(mode == 0) newState = 0; + if(mode == 1) newState = Minecraft.getMinecraft().gameSettings.fancyGraphics ? 1 : 0; + if(mode == 2) newState = 1; + if(mode == 3) newState = 2; + if(mode == 4) newState = 3; + if(newState == 0) { + state = newState; + destroy(); + return; + } + if(newState != state && !(newState == 3 && state == 2)) { + destroy(); + } + //_wglGetParameter(_wGL_VIEWPORT, 4, originalViewport); + if (displayWidth != width || displayHeight != height || state != newState) { + state = newState; + width = displayWidth; + height = displayHeight; + originalViewport[0] = 0; + originalViewport[1] = 0; + originalViewport[2] = width; + originalViewport[3] = height; + if(state == 1) { + if(isUsingFXAA == false) { + initFXAA(); + }else { + glBindTexture(_wGL_TEXTURE_2D, fxaaSourceTexture); + _wglTexImage2D(_wGL_TEXTURE_2D, 0, _wGL_RGBA8, width, height, 0, _wGL_RGBA, _wGL_UNSIGNED_BYTE, (ByteBuffer)null); + _wglBindRenderbuffer(framebuffer_depth); + _wglRenderbufferStorage(_wGL_DEPTH_COMPONENT32F, width, height); + } + }else if(state == 2 || state == 3) { + if(msaaInit == false) { + initMSAA(); + }else { + _wglBindRenderbuffer(framebuffer_color); + _wglRenderbufferStorageMultisample(state == 2 ? 4 : 8, _wGL_RGBA8, width, height); + _wglBindRenderbuffer(framebuffer_depth); + _wglRenderbufferStorageMultisample(state == 2 ? 4 : 8, _wGL_DEPTH_COMPONENT32F, width, height); + } + } + } + _wglBindFramebuffer(_wGL_FRAMEBUFFER, framebuffer); + _wglViewport(0, 0, width, height); + if(!EaglerAdapter.isWebGL && (state == 2 || state == 3)) { + _wglEnable(_wGL_MULTISAMPLE); + _wglEnable(_wGL_LINE_SMOOTH); + } + } + + public static void endPipelineRender() { + if(displayWidth <= 0 || displayHeight <= 0 || state == 0) { + return; + } + _wglBindFramebuffer(_wGL_FRAMEBUFFER, null); + _wglClear(_wGL_COLOR_BUFFER_BIT | _wGL_DEPTH_BUFFER_BIT); + if(state == 1) { + _wglViewport(originalViewport[0], originalViewport[1], originalViewport[2], originalViewport[3]); + glActiveTexture(GL_TEXTURE0); + glBindTexture(_wGL_TEXTURE_2D, fxaaSourceTexture); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDepthMask(false); + _wglUseProgram(fxaaProgram); + _wglUniform2f(fxaaScreenSize, 1.0f / width, 1.0f / height); + _wglBindVertexArray0(renderQuadArray); + _wglDrawArrays(_wGL_TRIANGLES, 0, 6); + glEnable(GL_DEPTH_TEST); + glDepthMask(true); + }else if(state == 2 || state == 3) { + if(!EaglerAdapter.isWebGL) { + _wglDisable(_wGL_MULTISAMPLE); + _wglDisable(_wGL_LINE_SMOOTH); + } + _wglViewport(originalViewport[0], originalViewport[1], originalViewport[2], originalViewport[3]); + _wglBindFramebuffer(_wGL_READ_FRAMEBUFFER, framebuffer); + _wglBindFramebuffer(_wGL_DRAW_FRAMEBUFFER, null); + _wglDrawBuffer(_wGL_COLOR_ATTACHMENT0); + _wglBlitFramebuffer(0, 0, width, height, 0, 0, width, height, _wGL_COLOR_BUFFER_BIT, _wGL_NEAREST); + _wglBindFramebuffer(_wGL_READ_FRAMEBUFFER, null); + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/FixedFunctionShader.java b/src/main/java/net/lax1dude/eaglercraft/glemu/FixedFunctionShader.java new file mode 100644 index 0000000..4e0f5be --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/FixedFunctionShader.java @@ -0,0 +1,636 @@ +package net.lax1dude.eaglercraft.glemu; + +import static net.lax1dude.eaglercraft.EaglerAdapter.*; + +import java.util.ArrayList; +import java.util.List; + +import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.ProgramGL; +import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.ShaderGL; +import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.UniformGL; +import net.lax1dude.eaglercraft.glemu.vector.Vector2f; +import net.lax1dude.eaglercraft.glemu.vector.Vector4f; + +public class FixedFunctionShader { + + private static final FixedFunctionShader[] instances = new FixedFunctionShader[4096]; //lol + private static final List instanceList = new ArrayList<>(); + + public static void refreshCoreGL() { + for(int i = 0; i < instances.length; ++i) { + if(instances[i] != null) { + _wglDeleteProgram(instances[i].globject); + instances[i] = null; + } + } + instanceList.clear(); + shaderSource = null; + } + + public static final int COLOR = 1; + public static final int NORMAL = 2; + public static final int TEXTURE0 = 4; + public static final int TEXTURE1 = 8; + public static final int TEXGEN = 16; + public static final int LIGHTING = 32; + public static final int FOG = 64; + public static final int ALPHATEST = 128; + public static final int UNIT0 = 256; + public static final int UNIT1 = 512; + public static final int FIX_ANISOTROPIC = 1024; + public static final int SWAP_RB = 2048; + + public static FixedFunctionShader instance(int i) { + FixedFunctionShader s = instances[i]; + if(s == null) { + boolean CC_a_color = false; + boolean CC_a_normal = false; + boolean CC_a_texture0 = false; + boolean CC_a_texture1 = false; + boolean CC_TEX_GEN_STRQ = false; + boolean CC_lighting = false; + boolean CC_fog = false; + boolean CC_alphatest = false; + boolean CC_unit0 = false; + boolean CC_unit1 = false; + boolean CC_anisotropic = false; + boolean CC_swap_rb = false; + if((i & COLOR) == COLOR) { + CC_a_color = true; + } + if((i & NORMAL) == NORMAL) { + CC_a_normal = true; + } + if((i & TEXTURE0) == TEXTURE0) { + CC_a_texture0 = true; + } + if((i & TEXTURE1) == TEXTURE1) { + CC_a_texture1 = true; + } + if((i & TEXGEN) == TEXGEN) { + CC_TEX_GEN_STRQ = true; + } + if((i & LIGHTING) == LIGHTING) { + CC_lighting = true; + } + if((i & FOG) == FOG) { + CC_fog = true; + } + if((i & ALPHATEST) == ALPHATEST) { + CC_alphatest = true; + } + if((i & UNIT0) == UNIT0) { + CC_unit0 = true; + } + if((i & UNIT1) == UNIT1) { + CC_unit1 = true; + } + if((i & FIX_ANISOTROPIC) == FIX_ANISOTROPIC) { + CC_anisotropic = true; + } + if((i & SWAP_RB) == SWAP_RB) { + CC_swap_rb = true; + } + s = new FixedFunctionShader(i, CC_a_color, CC_a_normal, CC_a_texture0, CC_a_texture1, CC_TEX_GEN_STRQ, CC_lighting, + CC_fog, CC_alphatest, CC_unit0, CC_unit1, CC_anisotropic, CC_swap_rb); + instances[i] = s; + instanceList.add(s); + } + return s; + } + + private static String shaderSource = null; + + private final boolean enable_color; + private final boolean enable_normal; + private final boolean enable_texture0; + private final boolean enable_texture1; + private final boolean enable_TEX_GEN_STRQ; + private final boolean enable_lighting; + private final boolean enable_fog; + private final boolean enable_alphatest; + private final boolean enable_unit0; + private final boolean enable_unit1; + private final boolean enable_anisotropic_fix; + private final boolean enable_swap_rb; + private final ProgramGL globject; + + private UniformGL u_matrix_m = null; + private UniformGL u_matrix_p = null; + private UniformGL u_matrix_t = null; + + private UniformGL u_fogColor = null; + //private UniformGL u_fogMode = null; + //private UniformGL u_fogStart = null; + //private UniformGL u_fogEnd = null; + //private UniformGL u_fogDensity = null; + private UniformGL u_fogParam = null; + + private UniformGL u_colorUniform = null; + private UniformGL u_normalUniform = null; + + private UniformGL u_alphaTestF = null; + + //private UniformGL u_textureGenS_M = null; + //private UniformGL u_textureGenT_M = null; + //private UniformGL u_textureGenR_M = null; + //private UniformGL u_textureGenQ_M = null; + private UniformGL u_textureGen_M = null; + private UniformGL u_textureGenS_V = null; + private UniformGL u_textureGenT_V = null; + private UniformGL u_textureGenR_V = null; + private UniformGL u_textureGenQ_V = null; + + private UniformGL u_texCoordV0 = null; + private UniformGL u_texCoordV1 = null; + + private UniformGL u_light0Pos = null; + private UniformGL u_light1Pos = null; + //private UniformGL u_invertNormals = null; + + private UniformGL u_anisotropic_fix = null; + + private final int a_position; + private final int a_texture0; + private final int a_color; + private final int a_normal; + private final int a_texture1; + + private final int attributeIndexesToEnable; + + public final StreamBuffer streamBuffer; + public boolean bufferIsInitialized = false; + + private FixedFunctionShader(int j, boolean CC_a_color, boolean CC_a_normal, boolean CC_a_texture0, boolean CC_a_texture1, boolean CC_TEX_GEN_STRQ, boolean CC_lighting, + boolean CC_fog, boolean CC_alphatest, boolean CC_unit0, boolean CC_unit1, boolean CC_anisotropic_fix, boolean CC_swap_rb) { + enable_color = CC_a_color; + enable_normal = CC_a_normal; + enable_texture0 = CC_a_texture0; + enable_texture1 = CC_a_texture1; + enable_TEX_GEN_STRQ = CC_TEX_GEN_STRQ; + enable_lighting = CC_lighting; + enable_fog = CC_fog; + enable_alphatest = CC_alphatest; + enable_unit0 = CC_unit0; + enable_unit1 = CC_unit1; + enable_anisotropic_fix = CC_anisotropic_fix; + enable_swap_rb = CC_swap_rb; + + if(shaderSource == null) { + shaderSource = fileContents("/glsl/core.glsl"); + } + + String source = ""; + if(enable_color) source += "\n#define CC_a_color\n"; + if(enable_normal) source += "#define CC_a_normal\n"; + if(enable_texture0) source += "#define CC_a_texture0\n"; + if(enable_texture1) source += "#define CC_a_texture1\n"; + if(enable_TEX_GEN_STRQ) source += "#define CC_TEX_GEN_STRQ\n"; + if(enable_lighting) source += "#define CC_lighting\n"; + if(enable_fog) source += "#define CC_fog\n"; + if(enable_alphatest) source += "#define CC_alphatest\n"; + if(enable_unit0) source += "#define CC_unit0\n"; + if(enable_unit1) source += "#define CC_unit1\n"; + if(enable_anisotropic_fix) source += "#define CC_patch_anisotropic\n"; + if(enable_swap_rb) source += "#define CC_swap_rb\n"; + source += shaderSource; + + ShaderGL v = _wglCreateShader(_wGL_VERTEX_SHADER); + _wglShaderSource(v, _wgetShaderHeader()+"\n#define CC_VERT\n"+source); + _wglCompileShader(v); + + if(!_wglGetShaderCompiled(v)) { + System.err.println(("\n\n"+_wglGetShaderInfoLog(v)).replace("\n", "\n[/glsl/core.glsl][CC_VERT] ")); + throw new RuntimeException("broken shader file"); + } + + ShaderGL f = _wglCreateShader(_wGL_FRAGMENT_SHADER); + _wglShaderSource(f, _wgetShaderHeader()+"\n#define CC_FRAG\n"+source); + _wglCompileShader(f); + + if(!_wglGetShaderCompiled(f)) { + System.err.println(("\n\n"+_wglGetShaderInfoLog(f)).replace("\n", "\n[/glsl/core.glsl][CC_FRAG] ")); + throw new RuntimeException("broken shader file"); + } + + globject = _wglCreateProgram(); + _wglAttachShader(globject, v); + _wglAttachShader(globject, f); + + int i = 0; + a_position = i++; + _wglBindAttributeLocation(globject, a_position, "a_position"); + + if(enable_texture0) { + a_texture0 = i++; + _wglBindAttributeLocation(globject, a_texture0, "a_texture0"); + }else { + a_texture0 = -1; + } + if(enable_color) { + a_color = i++; + _wglBindAttributeLocation(globject, a_color, "a_color"); + }else { + a_color = -1; + } + if(enable_normal) { + a_normal = i++; + _wglBindAttributeLocation(globject, a_normal, "a_normal"); + }else { + a_normal = -1; + } + if(enable_texture1) { + a_texture1 = i++; + _wglBindAttributeLocation(globject, a_texture1, "a_texture1"); + }else { + a_texture1 = -1; + } + + attributeIndexesToEnable = i; + + _wglLinkProgram(globject); + + _wglDetachShader(globject, v); + _wglDetachShader(globject, f); + _wglDeleteShader(v); + _wglDeleteShader(f); + + if(!_wglGetProgramLinked(globject)) { + System.err.println(("\n\n"+_wglGetProgramInfoLog(globject)).replace("\n", "\n[LINKER] ")); + throw new RuntimeException("broken shader file"); + } + + _wglUseProgram(globject); + + u_matrix_m = _wglGetUniformLocation(globject, "matrix_m"); + u_matrix_p = _wglGetUniformLocation(globject, "matrix_p"); + u_matrix_t = _wglGetUniformLocation(globject, "matrix_t"); + + u_colorUniform = _wglGetUniformLocation(globject, "colorUniform"); + + if(enable_lighting) { + u_normalUniform = _wglGetUniformLocation(globject, "normalUniform"); + //u_invertNormals = _wglGetUniformLocation(globject, "invertNormals"); + u_light0Pos = _wglGetUniformLocation(globject, "light0Pos"); + u_light1Pos = _wglGetUniformLocation(globject, "light1Pos"); + } + + if(enable_fog) { + u_fogColor = _wglGetUniformLocation(globject, "fogColor"); + //u_fogMode = _wglGetUniformLocation(globject, "fogMode"); + //u_fogStart = _wglGetUniformLocation(globject, "fogStart"); + //u_fogEnd = _wglGetUniformLocation(globject, "fogEnd"); + //u_fogDensity = _wglGetUniformLocation(globject, "fogDensity"); + u_fogParam = _wglGetUniformLocation(globject, "fogParam"); + } + + if(enable_alphatest) { + u_alphaTestF = _wglGetUniformLocation(globject, "alphaTestF"); + } + + if(enable_TEX_GEN_STRQ) { + //u_textureGenS_M = _wglGetUniformLocation(globject, "textureGenS_M"); + //u_textureGenT_M = _wglGetUniformLocation(globject, "textureGenT_M"); + //u_textureGenR_M = _wglGetUniformLocation(globject, "textureGenR_M"); + //u_textureGenQ_M = _wglGetUniformLocation(globject, "textureGenQ_M"); + u_textureGen_M = _wglGetUniformLocation(globject, "textureGen_M"); + u_textureGenS_V = _wglGetUniformLocation(globject, "textureGenS_V"); + u_textureGenT_V = _wglGetUniformLocation(globject, "textureGenT_V"); + u_textureGenR_V = _wglGetUniformLocation(globject, "textureGenR_V"); + u_textureGenQ_V = _wglGetUniformLocation(globject, "textureGenQ_V"); + } + + if(enable_anisotropic_fix) { + u_anisotropic_fix = _wglGetUniformLocation(globject, "anisotropic_fix"); + _wglUniform2f(u_anisotropic_fix, 1024.0f * 63.0f / 64.0f, 1024.0f * 63.0f / 64.0f); + } + + _wglUniform1i(_wglGetUniformLocation(globject, "tex0"), 0); + _wglUniform1i(_wglGetUniformLocation(globject, "tex1"), 1); + + u_texCoordV0 = _wglGetUniformLocation(globject, "texCoordV0"); + u_texCoordV1 = _wglGetUniformLocation(globject, "texCoordV1"); + + streamBuffer = new StreamBuffer(0x8000, 3, 8, (vertexArray, vertexBuffer) -> { + _wglBindVertexArray0(vertexArray); + _wglBindBuffer(_wGL_ARRAY_BUFFER, vertexBuffer); + setupArrayForProgram(); + }); + + } + + public void setupArrayForProgram() { + _wglEnableVertexAttribArray(a_position); + _wglVertexAttribPointer(a_position, 3, _wGL_FLOAT, false, 32, 0); + if(enable_texture0) { + _wglEnableVertexAttribArray(a_texture0); + _wglVertexAttribPointer(a_texture0, 2, _wGL_FLOAT, false, 32, 12); + } + if(enable_color) { + _wglEnableVertexAttribArray(a_color); + _wglVertexAttribPointer(a_color, 4, _wGL_UNSIGNED_BYTE, true, 32, 20); + } + if(enable_normal) { + _wglEnableVertexAttribArray(a_normal); + _wglVertexAttribPointer(a_normal, 4, _wGL_UNSIGNED_BYTE, true, 32, 24); + } + if(enable_texture1) { + _wglEnableVertexAttribArray(a_texture1); + _wglVertexAttribPointer(a_texture1, 2, _wGL_SHORT, false, 32, 28); + } + } + + public void useProgram() { + _wglUseProgram(globject); + } + + public void unuseProgram() { + + } + + public static void optimize() { + FixedFunctionShader pp; + for(int i = 0, l = instanceList.size(); i < l; ++i) { + instanceList.get(i).streamBuffer.optimize(); + } + } + + private float[] matBuffer = new float[16]; + + private Vector4f light0Pos = new Vector4f(); + private Vector4f light1Pos = new Vector4f(); + private Vector2f anisotropicFix = new Vector2f(0.0f, 0.0f); + + private int fogMode = 0; + + private float fogColorR = 0.0f; + private float fogColorG = 0.0f; + private float fogColorB = 0.0f; + private float fogColorA = 0.0f; + + private float fogStart = 0.0f; + private float fogEnd = 0.0f; + + private float fogDensity = 0.0f; + + private float alphaTestValue = 0.0f; + + private float tex0x = 0.0f; + private float tex0y = 0.0f; + + private float tex1x = 0.0f; + private float tex1y = 0.0f; + + private float colorUniformR = 0.0f; + private float colorUniformG = 0.0f; + private float colorUniformB = 0.0f; + private float colorUniformA = 0.0f; + + private float normalUniformX = 0.0f; + private float normalUniformY = 0.0f; + private float normalUniformZ = 0.0f; + + private int anisotropicFixSerial = -1; + private int colorSerial = -1; + private int normalSerial = -1; + private int tex0Serial = -1; + private int tex1Serial = -1; + private int texPlaneSerial = -1; + private int texSSerial = -1; + private int texTSerial = -1; + private int texRSerial = -1; + private int texQSerial = -1; + private int fogColorSerial = -1; + private int fogCfgSerial = -1; + private int matModelSerialCounter = -1; + private int matProjSerialCounter = -1; + private int matTexSerialCounter = -1; + private int lightPos0Serial = -1; + private int lightPos1Serial = -1; + + private int texS_plane = -1; + private float texS_X = -999.0f; + private float texS_Y = -999.0f; + private float texS_Z = -999.0f; + private float texS_W = -999.0f; + + private int texT_plane = -1; + private float texT_X = -999.0f; + private float texT_Y = -999.0f; + private float texT_Z = -999.0f; + private float texT_W = -999.0f; + + private int texR_plane = -1; + private float texR_X = -999.0f; + private float texR_Y = -999.0f; + private float texR_Z = -999.0f; + private float texR_W = -999.0f; + + private int texQ_plane = -1; + private float texQ_X = -999.0f; + private float texQ_Y = -999.0f; + private float texQ_Z = -999.0f; + private float texQ_W = -999.0f; + + public void update() { + if(anisotropicFixSerial != EaglerAdapterGL30.anisotropicFixSerial) { + float x = EaglerAdapterGL30.anisotropicFixX; + float y = EaglerAdapterGL30.anisotropicFixY; + anisotropicFixSerial = EaglerAdapterGL30.anisotropicFixSerial; + if(anisotropicFix.x != x || anisotropicFix.y != y) { + anisotropicFix.x = x; + anisotropicFix.y = y; + _wglUniform2f(u_anisotropic_fix, x, y); + } + } + if(colorSerial != EaglerAdapterGL30.colorSerial) { + float r = EaglerAdapterGL30.colorR; + float g = EaglerAdapterGL30.colorG; + float b = EaglerAdapterGL30.colorB; + float a = EaglerAdapterGL30.colorA; + colorSerial = EaglerAdapterGL30.colorSerial; + if(colorUniformR != r || colorUniformG != g || colorUniformB != b || colorUniformA != a) { + colorUniformR = r; + colorUniformG = g; + colorUniformB = b; + colorUniformA = a; + _wglUniform4f(u_colorUniform, r, g, b, a); + } + } + if(normalSerial != EaglerAdapterGL30.normalSerial) { + float x = EaglerAdapterGL30.normalX; + float y = EaglerAdapterGL30.normalY; + float z = EaglerAdapterGL30.normalZ; + normalSerial = EaglerAdapterGL30.normalSerial; + if(normalUniformX != x || normalUniformY != y || normalUniformZ != z) { + normalUniformX = x; + normalUniformY = y; + normalUniformZ = z; + _wglUniform3f(u_normalUniform, x, y, z); + } + } + if(tex0Serial != EaglerAdapterGL30.tex0Serial) { + float x = EaglerAdapterGL30.tex0X; + float y = EaglerAdapterGL30.tex0Y; + tex0Serial = EaglerAdapterGL30.tex0Serial; + if(tex0x != x || tex0y != y) { + tex0x = x; + tex0y = y; + _wglUniform2f(u_texCoordV0, x, y); + } + } + if(tex1Serial != EaglerAdapterGL30.tex1Serial) { + float x = EaglerAdapterGL30.tex1X; + float y = EaglerAdapterGL30.tex1Y; + tex1Serial = EaglerAdapterGL30.tex1Serial; + if(tex1x != x || tex1y != y) { + tex1x = x; + tex1y = y; + _wglUniform2f(u_texCoordV1, x, y); + } + } + if(texPlaneSerial != EaglerAdapterGL30.texPlaneSerial) { + int s = EaglerAdapterGL30.texS_plane; + int t = EaglerAdapterGL30.texT_plane; + int r = EaglerAdapterGL30.texR_plane; + int q = EaglerAdapterGL30.texQ_plane; + texPlaneSerial = EaglerAdapterGL30.texPlaneSerial; + if(texS_plane != s || texT_plane != t || texR_plane != r || texQ_plane != q) { + texS_plane = s; + texT_plane = t; + texR_plane = r; + texQ_plane = q; + _wglUniform4i(u_textureGen_M, s, t, r, q); + } + } + if(texSSerial != EaglerAdapterGL30.texSSerial) { + float x = EaglerAdapterGL30.texS_X; + float y = EaglerAdapterGL30.texS_Y; + float z = EaglerAdapterGL30.texS_Z; + float w = EaglerAdapterGL30.texS_W; + texSSerial = EaglerAdapterGL30.texSSerial; + if(texS_X != x || texS_Y != y || texS_Z != z || texS_W != w) { + texS_X = x; + texS_Y = y; + texS_Z = z; + texS_W = w; + _wglUniform4f(u_textureGenS_V, x, y, z, w); + } + } + if(texTSerial != EaglerAdapterGL30.texTSerial) { + float x = EaglerAdapterGL30.texT_X; + float y = EaglerAdapterGL30.texT_Y; + float z = EaglerAdapterGL30.texT_Z; + float w = EaglerAdapterGL30.texT_W; + texTSerial = EaglerAdapterGL30.texTSerial; + if(texT_X != x || texT_Y != y || texT_Z != z || texT_W != w) { + texT_X = x; + texT_Y = y; + texT_Z = z; + texT_W = w; + _wglUniform4f(u_textureGenT_V, x, y, z, w); + } + } + if(texRSerial != EaglerAdapterGL30.texRSerial) { + float x = EaglerAdapterGL30.texR_X; + float y = EaglerAdapterGL30.texR_Y; + float z = EaglerAdapterGL30.texR_Z; + float w = EaglerAdapterGL30.texR_W; + texRSerial = EaglerAdapterGL30.texRSerial; + if(texR_X != x || texR_Y != y || texR_Z != z || texR_W != w) { + texR_X = x; + texR_Y = y; + texR_Z = z; + texR_W = w; + _wglUniform4f(u_textureGenR_V, x, y, z, w); + } + } + if(texQSerial != EaglerAdapterGL30.texQSerial) { + float x = EaglerAdapterGL30.texQ_X; + float y = EaglerAdapterGL30.texQ_Y; + float z = EaglerAdapterGL30.texQ_Z; + float w = EaglerAdapterGL30.texQ_W; + texQSerial = EaglerAdapterGL30.texQSerial; + if(texQ_X != x || texQ_Y != y || texQ_Z != z || texQ_W != w) { + texQ_X = x; + texQ_Y = y; + texQ_Z = z; + texQ_W = w; + _wglUniform4f(u_textureGenQ_V, x, y, z, w); + } + } + if(fogColorSerial != EaglerAdapterGL30.fogColorSerial) { + float r = EaglerAdapterGL30.fogColorR; + float g = EaglerAdapterGL30.fogColorG; + float b = EaglerAdapterGL30.fogColorB; + float a = EaglerAdapterGL30.fogColorA; + fogColorSerial = EaglerAdapterGL30.fogColorSerial; + if(fogColorR != r || fogColorG != g || fogColorB != b || fogColorA != a) { + fogColorR = r; + fogColorG = g; + fogColorB = b; + fogColorA = a; + _wglUniform4f(u_fogColor, r, g, b, a); + } + } + if(fogCfgSerial != EaglerAdapterGL30.fogCfgSerial) { + int fogModex = EaglerAdapterGL30.fogMode; + float fogStarty = EaglerAdapterGL30.fogStart; + float fogEndz = EaglerAdapterGL30.fogEnd - fogStarty; + float fogDensityw = EaglerAdapterGL30.fogDensity; + fogCfgSerial = EaglerAdapterGL30.fogCfgSerial; + if(fogMode != fogModex || fogStart != fogStarty || + fogEnd != fogEndz || fogDensity != fogDensityw) { + fogMode = fogModex; + fogStart = fogStarty; + fogEnd = fogEndz; + fogDensity = fogDensityw; + _wglUniform4f(u_fogParam, fogModex, fogStarty, fogEndz, fogDensityw); + } + } + float limit = EaglerAdapterGL30.alphaThresh; + if(alphaTestValue != limit) { + alphaTestValue = limit; + _wglUniform1f(u_alphaTestF, limit); + } + float[] matCopyBuffer = matBuffer; + int i = EaglerAdapterGL30.matModelPointer; + int j = EaglerAdapterGL30.matModelVSerial[i]; + if(matModelSerialCounter != j) { + matModelSerialCounter = j; + EaglerAdapterGL30.matModelV[i].store(matCopyBuffer); + _wglUniformMat4fv(u_matrix_m, matCopyBuffer); + } + i = EaglerAdapterGL30.matProjPointer; + j = EaglerAdapterGL30.matProjVSerial[i]; + if(matProjSerialCounter != j) { + matProjSerialCounter = j; + EaglerAdapterGL30.matProjV[i].store(matCopyBuffer); + _wglUniformMat4fv(u_matrix_p, matCopyBuffer); + } + i = EaglerAdapterGL30.matTexPointer; + j = EaglerAdapterGL30.matTexVSerial[i]; + if(matTexSerialCounter != j) { + matTexSerialCounter = j; + EaglerAdapterGL30.matTexV[i].store(matCopyBuffer); + _wglUniformMat4fv(u_matrix_t, matCopyBuffer); + } + if(lightPos0Serial != EaglerAdapterGL30.lightPos0Serial) { + lightPos0Serial = EaglerAdapterGL30.lightPos0Serial; + Vector4f pos = EaglerAdapterGL30.lightPos0vec; + if(!pos.equals(light0Pos)) { + light0Pos.set(pos); + _wglUniform3f(u_light0Pos, pos.x, pos.y, pos.z); + } + } + if(lightPos1Serial != EaglerAdapterGL30.lightPos1Serial) { + lightPos1Serial = EaglerAdapterGL30.lightPos1Serial; + Vector4f pos = EaglerAdapterGL30.lightPos1vec; + if(!pos.equals(light1Pos)) { + light1Pos.set(pos); + _wglUniform3f(u_light1Pos, pos.x, pos.y, pos.z); + } + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/GLObjectMap.java b/src/main/java/net/lax1dude/eaglercraft/glemu/GLObjectMap.java new file mode 100644 index 0000000..6485146 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/GLObjectMap.java @@ -0,0 +1,53 @@ +package net.lax1dude.eaglercraft.glemu; + +public class GLObjectMap { + private Object[] values; + private int size; + private int insertIndex; + public int allocatedObjects; + + public GLObjectMap(int initialSize) { + this.values = new Object[initialSize]; + this.size = initialSize; + this.insertIndex = 0; + this.allocatedObjects = 0; + } + + public int register(T obj) { + int start = insertIndex; + do { + ++insertIndex; + if(insertIndex >= size) { + insertIndex = 0; + } + if(insertIndex == start) { + resize(); + return register(obj); + } + }while(values[insertIndex] != null); + values[insertIndex] = obj; + ++allocatedObjects; + return insertIndex; + } + + public T free(int obj) { + if(obj >= size || obj < 0) return null; + Object ret = values[obj]; + values[obj] = null; + --allocatedObjects; + return (T) ret; + } + + public T get(int obj) { + if(obj >= size || obj < 0) return null; + return (T) values[obj]; + } + + private void resize() { + int oldSize = size; + size += size / 2; + Object[] oldValues = values; + values = new Object[size]; + System.arraycopy(oldValues, 0, values, 0, oldSize); + } +} diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/GameOverlayFramebuffer.java b/src/main/java/net/lax1dude/eaglercraft/glemu/GameOverlayFramebuffer.java new file mode 100644 index 0000000..e8b8624 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/GameOverlayFramebuffer.java @@ -0,0 +1,72 @@ +package net.lax1dude.eaglercraft.glemu; + +import static net.lax1dude.eaglercraft.EaglerAdapter.*; + +import java.nio.ByteBuffer; + +public class GameOverlayFramebuffer { + + private long age = -1l; + + private int currentWidth = -1; + private int currentHeight = -1; + + private FramebufferGL framebuffer = null; + private TextureGL framebufferColor = null; + private RenderbufferGL depthBuffer = null; + + public void beginRender(int width, int height) { + if(framebuffer == null) { + framebuffer = _wglCreateFramebuffer(); + depthBuffer = _wglCreateRenderBuffer(); + framebufferColor = _wglGenTextures(); + _wglBindFramebuffer(_wGL_FRAMEBUFFER, framebuffer); + glBindTexture(_wGL_TEXTURE_2D, framebufferColor); + _wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + _wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + _wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + _wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + _wglFramebufferTexture2D(_wGL_COLOR_ATTACHMENT0, framebufferColor, 0); + _wglBindRenderbuffer(depthBuffer); + _wglFramebufferRenderbuffer(_wGL_DEPTH_ATTACHMENT, depthBuffer); + } + + if(currentWidth != width || currentHeight != height) { + currentWidth = width; + currentHeight = height; + glBindTexture(_wGL_TEXTURE_2D, framebufferColor); + _wglTexImage2D(_wGL_TEXTURE_2D, 0, _wGL_RGBA8, width, height, 0, _wGL_RGBA, _wGL_UNSIGNED_BYTE, (ByteBuffer)null); + _wglBindRenderbuffer(depthBuffer); + _wglRenderbufferStorage(0x81A5, width, height); + } + + _wglBindFramebuffer(_wGL_FRAMEBUFFER, framebuffer); + } + + public void endRender() { + _wglBindFramebuffer(_wGL_FRAMEBUFFER, null); + age = steadyTimeMillis(); + } + + public long getAge() { + return age == -1l ? -1l : (steadyTimeMillis() - age); + } + + public void bindTexture() { + glBindTexture(_wGL_TEXTURE_2D, framebufferColor); + } + + public void destroy() { + if(framebuffer != null) { + _wglDeleteFramebuffer(framebuffer); + _wglDeleteRenderbuffer(depthBuffer); + _wglDeleteTextures(framebufferColor); + framebuffer = null; + depthBuffer = null; + framebufferColor = null; + age = -1l; + _wglBindFramebuffer(_wGL_FRAMEBUFFER, null); + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/HighPolyMesh.java b/src/main/java/net/lax1dude/eaglercraft/glemu/HighPolyMesh.java new file mode 100644 index 0000000..b803375 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/HighPolyMesh.java @@ -0,0 +1,119 @@ +package net.lax1dude.eaglercraft.glemu; + +import static net.lax1dude.eaglercraft.EaglerAdapter.*; + +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.nio.IntBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +import net.lax1dude.eaglercraft.EaglerInputStream; +import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.BufferArrayGL; +import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.BufferGL; +import net.minecraft.src.GLAllocation; + +public class HighPolyMesh { + + final BufferArrayGL vertexArray; + final BufferGL vertexBuffer; + final BufferGL indexBuffer; + + public final int vertexCount; + public final int indexCount; + + public final boolean hasTexture; + + public HighPolyMesh(BufferArrayGL vertexArray, BufferGL vertexBuffer, BufferGL indexBuffer, int vertexCount, + int indexCount, boolean hasTexture) { + this.vertexArray = vertexArray; + this.vertexBuffer = vertexBuffer; + this.indexBuffer = indexBuffer; + this.vertexCount = vertexCount; + this.indexCount = indexCount; + this.hasTexture = hasTexture; + } + + public void free() { + _wglDeleteVertexArray(vertexArray); + _wglDeleteBuffer(vertexBuffer); + _wglDeleteBuffer(indexBuffer); + } + + static final byte[] headerSequence = "!EAG%mdl".getBytes(StandardCharsets.UTF_8); + + static HighPolyMesh loadMeshData(byte[] mesh) throws IOException { + DataInputStream mdlIn = new DataInputStream(new EaglerInputStream(mesh)); + + byte[] hd = new byte[headerSequence.length]; + mdlIn.read(hd); + if(!Arrays.equals(headerSequence, hd)) { + throw new IOException("Not an Eaglercraft HighPoly Mesh"); + } + + char CT = (char)mdlIn.read(); + + boolean textureEnabled; + if(CT == 'C') { + textureEnabled = false; + }else if(CT == 'T') { + textureEnabled = true; + }else { + throw new IOException("Unsupported mesh type '" + CT + "'!"); + } + + mdlIn.skipBytes(mdlIn.readUnsignedShort()); + + int vertexCount = mdlIn.readInt(); + int indexCount = mdlIn.readInt(); + int byteIndexCount = indexCount; + if(byteIndexCount % 2 != 0) { // must round up to int + byteIndexCount += 1; + } + int stride = textureEnabled ? 24 : 16; + + int intsOfVertex = vertexCount * stride / 4; + int intsOfIndex = byteIndexCount / 2; + int intsTotal = intsOfIndex + intsOfVertex; + IntBuffer up1 = GLAllocation.createDirectIntBuffer(intsTotal); + + for(int i = 0; i < intsTotal; ++i) { + int ch1 = mdlIn.read(); + int ch2 = mdlIn.read(); + int ch3 = mdlIn.read(); + int ch4 = mdlIn.read(); + if ((ch1 | ch2 | ch3 | ch4) < 0) throw new EOFException(); // rip + up1.put((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0)); + } + + BufferArrayGL vertexArray = _wglCreateVertexArray(); + _wglBindVertexArray0(vertexArray); + + up1.position(0).limit(intsOfVertex); + + BufferGL vertexBuffer = _wglCreateBuffer(); + _wglBindBuffer(_wGL_ARRAY_BUFFER, vertexBuffer); + _wglBufferData0(_wGL_ARRAY_BUFFER, up1, _wGL_STATIC_DRAW); + + up1.position(intsOfVertex).limit(intsTotal); + + BufferGL indexBuffer = _wglCreateBuffer(); + _wglBindBuffer(_wGL_ELEMENT_ARRAY_BUFFER, indexBuffer); + _wglBufferData0(_wGL_ELEMENT_ARRAY_BUFFER, up1, _wGL_STATIC_DRAW); + + _wglEnableVertexAttribArray(0); + _wglVertexAttribPointer(0, 3, _wGL_FLOAT, false, stride, 0); + + if(textureEnabled) { + _wglEnableVertexAttribArray(1); + _wglVertexAttribPointer(1, 2, _wGL_FLOAT, false, stride, 16); + } + + _wglEnableVertexAttribArray(textureEnabled ? 2 : 1); + _wglVertexAttribPointer(textureEnabled ? 2 : 1, 4, _wGL_UNSIGNED_BYTE, true, stride, 12); + + return new HighPolyMesh(vertexArray, vertexBuffer, indexBuffer, vertexCount, indexCount, textureEnabled); + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/RealOpenGLEnums.java b/src/main/java/net/lax1dude/eaglercraft/glemu/RealOpenGLEnums.java new file mode 100644 index 0000000..7641deb --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/RealOpenGLEnums.java @@ -0,0 +1,2417 @@ +package net.lax1dude.eaglercraft.glemu; + +public class RealOpenGLEnums { + + // Field descriptor #544 I + public static final int GL_ACCUM = 256; + + // Field descriptor #544 I + public static final int GL_LOAD = 257; + + // Field descriptor #544 I + public static final int GL_RETURN = 258; + + // Field descriptor #544 I + public static final int GL_MULT = 259; + + // Field descriptor #544 I + public static final int GL_ADD = 260; + + // Field descriptor #544 I + public static final int GL_NEVER = 512; + + // Field descriptor #544 I + public static final int GL_LESS = 513; + + // Field descriptor #544 I + public static final int GL_EQUAL = 514; + + // Field descriptor #544 I + public static final int GL_LEQUAL = 515; + + // Field descriptor #544 I + public static final int GL_GREATER = 516; + + // Field descriptor #544 I + public static final int GL_NOTEQUAL = 517; + + // Field descriptor #544 I + public static final int GL_GEQUAL = 518; + + // Field descriptor #544 I + public static final int GL_ALWAYS = 519; + + // Field descriptor #544 I + public static final int GL_CURRENT_BIT = 1; + + // Field descriptor #544 I + public static final int GL_POINT_BIT = 2; + + // Field descriptor #544 I + public static final int GL_LINE_BIT = 4; + + // Field descriptor #544 I + public static final int GL_POLYGON_BIT = 8; + + // Field descriptor #544 I + public static final int GL_POLYGON_STIPPLE_BIT = 16; + + // Field descriptor #544 I + public static final int GL_PIXEL_MODE_BIT = 32; + + // Field descriptor #544 I + public static final int GL_LIGHTING_BIT = 64; + + // Field descriptor #544 I + public static final int GL_FOG_BIT = 128; + + // Field descriptor #544 I + public static final int GL_DEPTH_BUFFER_BIT = 256; + + // Field descriptor #544 I + public static final int GL_ACCUM_BUFFER_BIT = 512; + + // Field descriptor #544 I + public static final int GL_STENCIL_BUFFER_BIT = 1024; + + // Field descriptor #544 I + public static final int GL_VIEWPORT_BIT = 2048; + + // Field descriptor #544 I + public static final int GL_TRANSFORM_BIT = 4096; + + // Field descriptor #544 I + public static final int GL_ENABLE_BIT = 8192; + + // Field descriptor #544 I + public static final int GL_COLOR_BUFFER_BIT = 16384; + + // Field descriptor #544 I + public static final int GL_HINT_BIT = 32768; + + // Field descriptor #544 I + public static final int GL_EVAL_BIT = 65536; + + // Field descriptor #544 I + public static final int GL_LIST_BIT = 131072; + + // Field descriptor #544 I + public static final int GL_TEXTURE_BIT = 262144; + + // Field descriptor #544 I + public static final int GL_SCISSOR_BIT = 524288; + + // Field descriptor #544 I + public static final int GL_ALL_ATTRIB_BITS = 1048575; + + // Field descriptor #544 I + public static final int GL_POINTS = 0; + + // Field descriptor #544 I + public static final int GL_LINES = 1; + + // Field descriptor #544 I + public static final int GL_LINE_LOOP = 2; + + // Field descriptor #544 I + public static final int GL_LINE_STRIP = 3; + + // Field descriptor #544 I + public static final int GL_TRIANGLES = 4; + + // Field descriptor #544 I + public static final int GL_TRIANGLE_STRIP = 5; + + // Field descriptor #544 I + public static final int GL_TRIANGLE_FAN = 6; + + // Field descriptor #544 I + public static final int GL_QUADS = 7; + + // Field descriptor #544 I + public static final int GL_QUAD_STRIP = 8; + + // Field descriptor #544 I + public static final int GL_POLYGON = 9; + + // Field descriptor #544 I + public static final int GL_ZERO = 0; + + // Field descriptor #544 I + public static final int GL_ONE = 1; + + // Field descriptor #544 I + public static final int GL_SRC_COLOR = 768; + + // Field descriptor #544 I + public static final int GL_ONE_MINUS_SRC_COLOR = 769; + + // Field descriptor #544 I + public static final int GL_SRC_ALPHA = 770; + + // Field descriptor #544 I + public static final int GL_ONE_MINUS_SRC_ALPHA = 771; + + // Field descriptor #544 I + public static final int GL_DST_ALPHA = 772; + + // Field descriptor #544 I + public static final int GL_ONE_MINUS_DST_ALPHA = 773; + + // Field descriptor #544 I + public static final int GL_DST_COLOR = 774; + + // Field descriptor #544 I + public static final int GL_ONE_MINUS_DST_COLOR = 775; + + // Field descriptor #544 I + public static final int GL_SRC_ALPHA_SATURATE = 776; + + // Field descriptor #544 I + public static final int GL_CONSTANT_COLOR = 32769; + + // Field descriptor #544 I + public static final int GL_ONE_MINUS_CONSTANT_COLOR = 32770; + + // Field descriptor #544 I + public static final int GL_CONSTANT_ALPHA = 32771; + + // Field descriptor #544 I + public static final int GL_ONE_MINUS_CONSTANT_ALPHA = 32772; + + // Field descriptor #544 I + public static final int GL_TRUE = 1; + + // Field descriptor #544 I + public static final int GL_FALSE = 0; + + // Field descriptor #544 I + public static final int GL_CLIP_PLANE0 = 12288; + + // Field descriptor #544 I + public static final int GL_CLIP_PLANE1 = 12289; + + // Field descriptor #544 I + public static final int GL_CLIP_PLANE2 = 12290; + + // Field descriptor #544 I + public static final int GL_CLIP_PLANE3 = 12291; + + // Field descriptor #544 I + public static final int GL_CLIP_PLANE4 = 12292; + + // Field descriptor #544 I + public static final int GL_CLIP_PLANE5 = 12293; + + // Field descriptor #544 I + public static final int GL_BYTE = 5120; + + // Field descriptor #544 I + public static final int GL_UNSIGNED_BYTE = 5121; + + // Field descriptor #544 I + public static final int GL_SHORT = 5122; + + // Field descriptor #544 I + public static final int GL_UNSIGNED_SHORT = 5123; + + // Field descriptor #544 I + public static final int GL_INT = 5124; + + // Field descriptor #544 I + public static final int GL_UNSIGNED_INT = 5125; + + // Field descriptor #544 I + public static final int GL_FLOAT = 5126; + + // Field descriptor #544 I + public static final int GL_2_BYTES = 5127; + + // Field descriptor #544 I + public static final int GL_3_BYTES = 5128; + + // Field descriptor #544 I + public static final int GL_4_BYTES = 5129; + + // Field descriptor #544 I + public static final int GL_DOUBLE = 5130; + + // Field descriptor #544 I + public static final int GL_NONE = 0; + + // Field descriptor #544 I + public static final int GL_FRONT_LEFT = 1024; + + // Field descriptor #544 I + public static final int GL_FRONT_RIGHT = 1025; + + // Field descriptor #544 I + public static final int GL_BACK_LEFT = 1026; + + // Field descriptor #544 I + public static final int GL_BACK_RIGHT = 1027; + + // Field descriptor #544 I + public static final int GL_FRONT = 1028; + + // Field descriptor #544 I + public static final int GL_BACK = 1029; + + // Field descriptor #544 I + public static final int GL_LEFT = 1030; + + // Field descriptor #544 I + public static final int GL_RIGHT = 1031; + + // Field descriptor #544 I + public static final int GL_FRONT_AND_BACK = 1032; + + // Field descriptor #544 I + public static final int GL_AUX0 = 1033; + + // Field descriptor #544 I + public static final int GL_AUX1 = 1034; + + // Field descriptor #544 I + public static final int GL_AUX2 = 1035; + + // Field descriptor #544 I + public static final int GL_AUX3 = 1036; + + // Field descriptor #544 I + public static final int GL_NO_ERROR = 0; + + // Field descriptor #544 I + public static final int GL_INVALID_ENUM = 1280; + + // Field descriptor #544 I + public static final int GL_INVALID_VALUE = 1281; + + // Field descriptor #544 I + public static final int GL_INVALID_OPERATION = 1282; + + // Field descriptor #544 I + public static final int GL_STACK_OVERFLOW = 1283; + + // Field descriptor #544 I + public static final int GL_STACK_UNDERFLOW = 1284; + + // Field descriptor #544 I + public static final int GL_OUT_OF_MEMORY = 1285; + + // Field descriptor #544 I + public static final int GL_2D = 1536; + + // Field descriptor #544 I + public static final int GL_3D = 1537; + + // Field descriptor #544 I + public static final int GL_3D_COLOR = 1538; + + // Field descriptor #544 I + public static final int GL_3D_COLOR_TEXTURE = 1539; + + // Field descriptor #544 I + public static final int GL_4D_COLOR_TEXTURE = 1540; + + // Field descriptor #544 I + public static final int GL_PASS_THROUGH_TOKEN = 1792; + + // Field descriptor #544 I + public static final int GL_POINT_TOKEN = 1793; + + // Field descriptor #544 I + public static final int GL_LINE_TOKEN = 1794; + + // Field descriptor #544 I + public static final int GL_POLYGON_TOKEN = 1795; + + // Field descriptor #544 I + public static final int GL_BITMAP_TOKEN = 1796; + + // Field descriptor #544 I + public static final int GL_DRAW_PIXEL_TOKEN = 1797; + + // Field descriptor #544 I + public static final int GL_COPY_PIXEL_TOKEN = 1798; + + // Field descriptor #544 I + public static final int GL_LINE_RESET_TOKEN = 1799; + + // Field descriptor #544 I + public static final int GL_EXP = 2048; + + // Field descriptor #544 I + public static final int GL_EXP2 = 2049; + + // Field descriptor #544 I + public static final int GL_CW = 2304; + + // Field descriptor #544 I + public static final int GL_CCW = 2305; + + // Field descriptor #544 I + public static final int GL_COEFF = 2560; + + // Field descriptor #544 I + public static final int GL_ORDER = 2561; + + // Field descriptor #544 I + public static final int GL_DOMAIN = 2562; + + // Field descriptor #544 I + public static final int GL_CURRENT_COLOR = 2816; + + // Field descriptor #544 I + public static final int GL_CURRENT_INDEX = 2817; + + // Field descriptor #544 I + public static final int GL_CURRENT_NORMAL = 2818; + + // Field descriptor #544 I + public static final int GL_CURRENT_TEXTURE_COORDS = 2819; + + // Field descriptor #544 I + public static final int GL_CURRENT_RASTER_COLOR = 2820; + + // Field descriptor #544 I + public static final int GL_CURRENT_RASTER_INDEX = 2821; + + // Field descriptor #544 I + public static final int GL_CURRENT_RASTER_TEXTURE_COORDS = 2822; + + // Field descriptor #544 I + public static final int GL_CURRENT_RASTER_POSITION = 2823; + + // Field descriptor #544 I + public static final int GL_CURRENT_RASTER_POSITION_VALID = 2824; + + // Field descriptor #544 I + public static final int GL_CURRENT_RASTER_DISTANCE = 2825; + + // Field descriptor #544 I + public static final int GL_POINT_SMOOTH = 2832; + + // Field descriptor #544 I + public static final int GL_POINT_SIZE = 2833; + + // Field descriptor #544 I + public static final int GL_POINT_SIZE_RANGE = 2834; + + // Field descriptor #544 I + public static final int GL_POINT_SIZE_GRANULARITY = 2835; + + // Field descriptor #544 I + public static final int GL_LINE_SMOOTH = 2848; + + // Field descriptor #544 I + public static final int GL_LINE_WIDTH = 2849; + + // Field descriptor #544 I + public static final int GL_LINE_WIDTH_RANGE = 2850; + + // Field descriptor #544 I + public static final int GL_LINE_WIDTH_GRANULARITY = 2851; + + // Field descriptor #544 I + public static final int GL_LINE_STIPPLE = 2852; + + // Field descriptor #544 I + public static final int GL_LINE_STIPPLE_PATTERN = 2853; + + // Field descriptor #544 I + public static final int GL_LINE_STIPPLE_REPEAT = 2854; + + // Field descriptor #544 I + public static final int GL_LIST_MODE = 2864; + + // Field descriptor #544 I + public static final int GL_MAX_LIST_NESTING = 2865; + + // Field descriptor #544 I + public static final int GL_LIST_BASE = 2866; + + // Field descriptor #544 I + public static final int GL_LIST_INDEX = 2867; + + // Field descriptor #544 I + public static final int GL_POLYGON_MODE = 2880; + + // Field descriptor #544 I + public static final int GL_POLYGON_SMOOTH = 2881; + + // Field descriptor #544 I + public static final int GL_POLYGON_STIPPLE = 2882; + + // Field descriptor #544 I + public static final int GL_EDGE_FLAG = 2883; + + // Field descriptor #544 I + public static final int GL_CULL_FACE = 2884; + + // Field descriptor #544 I + public static final int GL_CULL_FACE_MODE = 2885; + + // Field descriptor #544 I + public static final int GL_FRONT_FACE = 2886; + + // Field descriptor #544 I + public static final int GL_LIGHTING = 2896; + + // Field descriptor #544 I + public static final int GL_LIGHT_MODEL_LOCAL_VIEWER = 2897; + + // Field descriptor #544 I + public static final int GL_LIGHT_MODEL_TWO_SIDE = 2898; + + // Field descriptor #544 I + public static final int GL_LIGHT_MODEL_AMBIENT = 2899; + + // Field descriptor #544 I + public static final int GL_SHADE_MODEL = 2900; + + // Field descriptor #544 I + public static final int GL_COLOR_MATERIAL_FACE = 2901; + + // Field descriptor #544 I + public static final int GL_COLOR_MATERIAL_PARAMETER = 2902; + + // Field descriptor #544 I + public static final int GL_COLOR_MATERIAL = 2903; + + // Field descriptor #544 I + public static final int GL_FOG = 2912; + + // Field descriptor #544 I + public static final int GL_FOG_INDEX = 2913; + + // Field descriptor #544 I + public static final int GL_FOG_DENSITY = 2914; + + // Field descriptor #544 I + public static final int GL_FOG_START = 2915; + + // Field descriptor #544 I + public static final int GL_FOG_END = 2916; + + // Field descriptor #544 I + public static final int GL_FOG_MODE = 2917; + + // Field descriptor #544 I + public static final int GL_FOG_COLOR = 2918; + + // Field descriptor #544 I + public static final int GL_DEPTH_RANGE = 2928; + + // Field descriptor #544 I + public static final int GL_DEPTH_TEST = 2929; + + // Field descriptor #544 I + public static final int GL_DEPTH_WRITEMASK = 2930; + + // Field descriptor #544 I + public static final int GL_DEPTH_CLEAR_VALUE = 2931; + + // Field descriptor #544 I + public static final int GL_DEPTH_FUNC = 2932; + + // Field descriptor #544 I + public static final int GL_ACCUM_CLEAR_VALUE = 2944; + + // Field descriptor #544 I + public static final int GL_STENCIL_TEST = 2960; + + // Field descriptor #544 I + public static final int GL_STENCIL_CLEAR_VALUE = 2961; + + // Field descriptor #544 I + public static final int GL_STENCIL_FUNC = 2962; + + // Field descriptor #544 I + public static final int GL_STENCIL_VALUE_MASK = 2963; + + // Field descriptor #544 I + public static final int GL_STENCIL_FAIL = 2964; + + // Field descriptor #544 I + public static final int GL_STENCIL_PASS_DEPTH_FAIL = 2965; + + // Field descriptor #544 I + public static final int GL_STENCIL_PASS_DEPTH_PASS = 2966; + + // Field descriptor #544 I + public static final int GL_STENCIL_REF = 2967; + + // Field descriptor #544 I + public static final int GL_STENCIL_WRITEMASK = 2968; + + // Field descriptor #544 I + public static final int GL_MATRIX_MODE = 2976; + + // Field descriptor #544 I + public static final int GL_NORMALIZE = 2977; + + // Field descriptor #544 I + public static final int GL_VIEWPORT = 2978; + + // Field descriptor #544 I + public static final int GL_MODELVIEW_STACK_DEPTH = 2979; + + // Field descriptor #544 I + public static final int GL_PROJECTION_STACK_DEPTH = 2980; + + // Field descriptor #544 I + public static final int GL_TEXTURE_STACK_DEPTH = 2981; + + // Field descriptor #544 I + public static final int GL_MODELVIEW_MATRIX = 2982; + + // Field descriptor #544 I + public static final int GL_PROJECTION_MATRIX = 2983; + + // Field descriptor #544 I + public static final int GL_TEXTURE_MATRIX = 2984; + + // Field descriptor #544 I + public static final int GL_ATTRIB_STACK_DEPTH = 2992; + + // Field descriptor #544 I + public static final int GL_CLIENT_ATTRIB_STACK_DEPTH = 2993; + + // Field descriptor #544 I + public static final int GL_ALPHA_TEST = 3008; + + // Field descriptor #544 I + public static final int GL_ALPHA_TEST_FUNC = 3009; + + // Field descriptor #544 I + public static final int GL_ALPHA_TEST_REF = 3010; + + // Field descriptor #544 I + public static final int GL_DITHER = 3024; + + // Field descriptor #544 I + public static final int GL_BLEND_DST = 3040; + + // Field descriptor #544 I + public static final int GL_BLEND_SRC = 3041; + + // Field descriptor #544 I + public static final int GL_BLEND = 3042; + + // Field descriptor #544 I + public static final int GL_LOGIC_OP_MODE = 3056; + + // Field descriptor #544 I + public static final int GL_INDEX_LOGIC_OP = 3057; + + // Field descriptor #544 I + public static final int GL_COLOR_LOGIC_OP = 3058; + + // Field descriptor #544 I + public static final int GL_AUX_BUFFERS = 3072; + + // Field descriptor #544 I + public static final int GL_DRAW_BUFFER = 3073; + + // Field descriptor #544 I + public static final int GL_READ_BUFFER = 3074; + + // Field descriptor #544 I + public static final int GL_SCISSOR_BOX = 3088; + + // Field descriptor #544 I + public static final int GL_SCISSOR_TEST = 3089; + + // Field descriptor #544 I + public static final int GL_INDEX_CLEAR_VALUE = 3104; + + // Field descriptor #544 I + public static final int GL_INDEX_WRITEMASK = 3105; + + // Field descriptor #544 I + public static final int GL_COLOR_CLEAR_VALUE = 3106; + + // Field descriptor #544 I + public static final int GL_COLOR_WRITEMASK = 3107; + + // Field descriptor #544 I + public static final int GL_INDEX_MODE = 3120; + + // Field descriptor #544 I + public static final int GL_RGBA_MODE = 3121; + + // Field descriptor #544 I + public static final int GL_DOUBLEBUFFER = 3122; + + // Field descriptor #544 I + public static final int GL_STEREO = 3123; + + // Field descriptor #544 I + public static final int GL_RENDER_MODE = 3136; + + // Field descriptor #544 I + public static final int GL_PERSPECTIVE_CORRECTION_HINT = 3152; + + // Field descriptor #544 I + public static final int GL_POINT_SMOOTH_HINT = 3153; + + // Field descriptor #544 I + public static final int GL_LINE_SMOOTH_HINT = 3154; + + // Field descriptor #544 I + public static final int GL_POLYGON_SMOOTH_HINT = 3155; + + // Field descriptor #544 I + public static final int GL_FOG_HINT = 3156; + + // Field descriptor #544 I + public static final int GL_TEXTURE_GEN_S = 3168; + + // Field descriptor #544 I + public static final int GL_TEXTURE_GEN_T = 3169; + + // Field descriptor #544 I + public static final int GL_TEXTURE_GEN_R = 3170; + + // Field descriptor #544 I + public static final int GL_TEXTURE_GEN_Q = 3171; + + // Field descriptor #544 I + public static final int GL_PIXEL_MAP_I_TO_I = 3184; + + // Field descriptor #544 I + public static final int GL_PIXEL_MAP_S_TO_S = 3185; + + // Field descriptor #544 I + public static final int GL_PIXEL_MAP_I_TO_R = 3186; + + // Field descriptor #544 I + public static final int GL_PIXEL_MAP_I_TO_G = 3187; + + // Field descriptor #544 I + public static final int GL_PIXEL_MAP_I_TO_B = 3188; + + // Field descriptor #544 I + public static final int GL_PIXEL_MAP_I_TO_A = 3189; + + // Field descriptor #544 I + public static final int GL_PIXEL_MAP_R_TO_R = 3190; + + // Field descriptor #544 I + public static final int GL_PIXEL_MAP_G_TO_G = 3191; + + // Field descriptor #544 I + public static final int GL_PIXEL_MAP_B_TO_B = 3192; + + // Field descriptor #544 I + public static final int GL_PIXEL_MAP_A_TO_A = 3193; + + // Field descriptor #544 I + public static final int GL_PIXEL_MAP_I_TO_I_SIZE = 3248; + + // Field descriptor #544 I + public static final int GL_PIXEL_MAP_S_TO_S_SIZE = 3249; + + // Field descriptor #544 I + public static final int GL_PIXEL_MAP_I_TO_R_SIZE = 3250; + + // Field descriptor #544 I + public static final int GL_PIXEL_MAP_I_TO_G_SIZE = 3251; + + // Field descriptor #544 I + public static final int GL_PIXEL_MAP_I_TO_B_SIZE = 3252; + + // Field descriptor #544 I + public static final int GL_PIXEL_MAP_I_TO_A_SIZE = 3253; + + // Field descriptor #544 I + public static final int GL_PIXEL_MAP_R_TO_R_SIZE = 3254; + + // Field descriptor #544 I + public static final int GL_PIXEL_MAP_G_TO_G_SIZE = 3255; + + // Field descriptor #544 I + public static final int GL_PIXEL_MAP_B_TO_B_SIZE = 3256; + + // Field descriptor #544 I + public static final int GL_PIXEL_MAP_A_TO_A_SIZE = 3257; + + // Field descriptor #544 I + public static final int GL_UNPACK_SWAP_BYTES = 3312; + + // Field descriptor #544 I + public static final int GL_UNPACK_LSB_FIRST = 3313; + + // Field descriptor #544 I + public static final int GL_UNPACK_ROW_LENGTH = 3314; + + // Field descriptor #544 I + public static final int GL_UNPACK_SKIP_ROWS = 3315; + + // Field descriptor #544 I + public static final int GL_UNPACK_SKIP_PIXELS = 3316; + + // Field descriptor #544 I + public static final int GL_UNPACK_ALIGNMENT = 3317; + + // Field descriptor #544 I + public static final int GL_PACK_SWAP_BYTES = 3328; + + // Field descriptor #544 I + public static final int GL_PACK_LSB_FIRST = 3329; + + // Field descriptor #544 I + public static final int GL_PACK_ROW_LENGTH = 3330; + + // Field descriptor #544 I + public static final int GL_PACK_SKIP_ROWS = 3331; + + // Field descriptor #544 I + public static final int GL_PACK_SKIP_PIXELS = 3332; + + // Field descriptor #544 I + public static final int GL_PACK_ALIGNMENT = 3333; + + // Field descriptor #544 I + public static final int GL_MAP_COLOR = 3344; + + // Field descriptor #544 I + public static final int GL_MAP_STENCIL = 3345; + + // Field descriptor #544 I + public static final int GL_INDEX_SHIFT = 3346; + + // Field descriptor #544 I + public static final int GL_INDEX_OFFSET = 3347; + + // Field descriptor #544 I + public static final int GL_RED_SCALE = 3348; + + // Field descriptor #544 I + public static final int GL_RED_BIAS = 3349; + + // Field descriptor #544 I + public static final int GL_ZOOM_X = 3350; + + // Field descriptor #544 I + public static final int GL_ZOOM_Y = 3351; + + // Field descriptor #544 I + public static final int GL_GREEN_SCALE = 3352; + + // Field descriptor #544 I + public static final int GL_GREEN_BIAS = 3353; + + // Field descriptor #544 I + public static final int GL_BLUE_SCALE = 3354; + + // Field descriptor #544 I + public static final int GL_BLUE_BIAS = 3355; + + // Field descriptor #544 I + public static final int GL_ALPHA_SCALE = 3356; + + // Field descriptor #544 I + public static final int GL_ALPHA_BIAS = 3357; + + // Field descriptor #544 I + public static final int GL_DEPTH_SCALE = 3358; + + // Field descriptor #544 I + public static final int GL_DEPTH_BIAS = 3359; + + // Field descriptor #544 I + public static final int GL_MAX_EVAL_ORDER = 3376; + + // Field descriptor #544 I + public static final int GL_MAX_LIGHTS = 3377; + + // Field descriptor #544 I + public static final int GL_MAX_CLIP_PLANES = 3378; + + // Field descriptor #544 I + public static final int GL_MAX_TEXTURE_SIZE = 3379; + + // Field descriptor #544 I + public static final int GL_MAX_PIXEL_MAP_TABLE = 3380; + + // Field descriptor #544 I + public static final int GL_MAX_ATTRIB_STACK_DEPTH = 3381; + + // Field descriptor #544 I + public static final int GL_MAX_MODELVIEW_STACK_DEPTH = 3382; + + // Field descriptor #544 I + public static final int GL_MAX_NAME_STACK_DEPTH = 3383; + + // Field descriptor #544 I + public static final int GL_MAX_PROJECTION_STACK_DEPTH = 3384; + + // Field descriptor #544 I + public static final int GL_MAX_TEXTURE_STACK_DEPTH = 3385; + + // Field descriptor #544 I + public static final int GL_MAX_VIEWPORT_DIMS = 3386; + + // Field descriptor #544 I + public static final int GL_MAX_CLIENT_ATTRIB_STACK_DEPTH = 3387; + + // Field descriptor #544 I + public static final int GL_SUBPIXEL_BITS = 3408; + + // Field descriptor #544 I + public static final int GL_INDEX_BITS = 3409; + + // Field descriptor #544 I + public static final int GL_RED_BITS = 3410; + + // Field descriptor #544 I + public static final int GL_GREEN_BITS = 3411; + + // Field descriptor #544 I + public static final int GL_BLUE_BITS = 3412; + + // Field descriptor #544 I + public static final int GL_ALPHA_BITS = 3413; + + // Field descriptor #544 I + public static final int GL_DEPTH_BITS = 3414; + + // Field descriptor #544 I + public static final int GL_STENCIL_BITS = 3415; + + // Field descriptor #544 I + public static final int GL_ACCUM_RED_BITS = 3416; + + // Field descriptor #544 I + public static final int GL_ACCUM_GREEN_BITS = 3417; + + // Field descriptor #544 I + public static final int GL_ACCUM_BLUE_BITS = 3418; + + // Field descriptor #544 I + public static final int GL_ACCUM_ALPHA_BITS = 3419; + + // Field descriptor #544 I + public static final int GL_NAME_STACK_DEPTH = 3440; + + // Field descriptor #544 I + public static final int GL_AUTO_NORMAL = 3456; + + // Field descriptor #544 I + public static final int GL_MAP1_COLOR_4 = 3472; + + // Field descriptor #544 I + public static final int GL_MAP1_INDEX = 3473; + + // Field descriptor #544 I + public static final int GL_MAP1_NORMAL = 3474; + + // Field descriptor #544 I + public static final int GL_MAP1_TEXTURE_COORD_1 = 3475; + + // Field descriptor #544 I + public static final int GL_MAP1_TEXTURE_COORD_2 = 3476; + + // Field descriptor #544 I + public static final int GL_MAP1_TEXTURE_COORD_3 = 3477; + + // Field descriptor #544 I + public static final int GL_MAP1_TEXTURE_COORD_4 = 3478; + + // Field descriptor #544 I + public static final int GL_MAP1_VERTEX_3 = 3479; + + // Field descriptor #544 I + public static final int GL_MAP1_VERTEX_4 = 3480; + + // Field descriptor #544 I + public static final int GL_MAP2_COLOR_4 = 3504; + + // Field descriptor #544 I + public static final int GL_MAP2_INDEX = 3505; + + // Field descriptor #544 I + public static final int GL_MAP2_NORMAL = 3506; + + // Field descriptor #544 I + public static final int GL_MAP2_TEXTURE_COORD_1 = 3507; + + // Field descriptor #544 I + public static final int GL_MAP2_TEXTURE_COORD_2 = 3508; + + // Field descriptor #544 I + public static final int GL_MAP2_TEXTURE_COORD_3 = 3509; + + // Field descriptor #544 I + public static final int GL_MAP2_TEXTURE_COORD_4 = 3510; + + // Field descriptor #544 I + public static final int GL_MAP2_VERTEX_3 = 3511; + + // Field descriptor #544 I + public static final int GL_MAP2_VERTEX_4 = 3512; + + // Field descriptor #544 I + public static final int GL_MAP1_GRID_DOMAIN = 3536; + + // Field descriptor #544 I + public static final int GL_MAP1_GRID_SEGMENTS = 3537; + + // Field descriptor #544 I + public static final int GL_MAP2_GRID_DOMAIN = 3538; + + // Field descriptor #544 I + public static final int GL_MAP2_GRID_SEGMENTS = 3539; + + // Field descriptor #544 I + public static final int GL_TEXTURE_1D = 3552; + + // Field descriptor #544 I + public static final int GL_TEXTURE_2D = 3553; + + // Field descriptor #544 I + public static final int GL_FEEDBACK_BUFFER_POINTER = 3568; + + // Field descriptor #544 I + public static final int GL_FEEDBACK_BUFFER_SIZE = 3569; + + // Field descriptor #544 I + public static final int GL_FEEDBACK_BUFFER_TYPE = 3570; + + // Field descriptor #544 I + public static final int GL_SELECTION_BUFFER_POINTER = 3571; + + // Field descriptor #544 I + public static final int GL_SELECTION_BUFFER_SIZE = 3572; + + // Field descriptor #544 I + public static final int GL_TEXTURE_WIDTH = 4096; + + // Field descriptor #544 I + public static final int GL_TEXTURE_HEIGHT = 4097; + + // Field descriptor #544 I + public static final int GL_TEXTURE_INTERNAL_FORMAT = 4099; + + // Field descriptor #544 I + public static final int GL_TEXTURE_BORDER_COLOR = 4100; + + // Field descriptor #544 I + public static final int GL_TEXTURE_BORDER = 4101; + + // Field descriptor #544 I + public static final int GL_DONT_CARE = 4352; + + // Field descriptor #544 I + public static final int GL_FASTEST = 4353; + + // Field descriptor #544 I + public static final int GL_NICEST = 4354; + + // Field descriptor #544 I + public static final int GL_LIGHT0 = 16384; + + // Field descriptor #544 I + public static final int GL_LIGHT1 = 16385; + + // Field descriptor #544 I + public static final int GL_LIGHT2 = 16386; + + // Field descriptor #544 I + public static final int GL_LIGHT3 = 16387; + + // Field descriptor #544 I + public static final int GL_LIGHT4 = 16388; + + // Field descriptor #544 I + public static final int GL_LIGHT5 = 16389; + + // Field descriptor #544 I + public static final int GL_LIGHT6 = 16390; + + // Field descriptor #544 I + public static final int GL_LIGHT7 = 16391; + + // Field descriptor #544 I + public static final int GL_AMBIENT = 4608; + + // Field descriptor #544 I + public static final int GL_DIFFUSE = 4609; + + // Field descriptor #544 I + public static final int GL_SPECULAR = 4610; + + // Field descriptor #544 I + public static final int GL_POSITION = 4611; + + // Field descriptor #544 I + public static final int GL_SPOT_DIRECTION = 4612; + + // Field descriptor #544 I + public static final int GL_SPOT_EXPONENT = 4613; + + // Field descriptor #544 I + public static final int GL_SPOT_CUTOFF = 4614; + + // Field descriptor #544 I + public static final int GL_CONSTANT_ATTENUATION = 4615; + + // Field descriptor #544 I + public static final int GL_LINEAR_ATTENUATION = 4616; + + // Field descriptor #544 I + public static final int GL_QUADRATIC_ATTENUATION = 4617; + + // Field descriptor #544 I + public static final int GL_COMPILE = 4864; + + // Field descriptor #544 I + public static final int GL_COMPILE_AND_EXECUTE = 4865; + + // Field descriptor #544 I + public static final int GL_CLEAR = 5376; + + // Field descriptor #544 I + public static final int GL_AND = 5377; + + // Field descriptor #544 I + public static final int GL_AND_REVERSE = 5378; + + // Field descriptor #544 I + public static final int GL_COPY = 5379; + + // Field descriptor #544 I + public static final int GL_AND_INVERTED = 5380; + + // Field descriptor #544 I + public static final int GL_NOOP = 5381; + + // Field descriptor #544 I + public static final int GL_XOR = 5382; + + // Field descriptor #544 I + public static final int GL_OR = 5383; + + // Field descriptor #544 I + public static final int GL_NOR = 5384; + + // Field descriptor #544 I + public static final int GL_EQUIV = 5385; + + // Field descriptor #544 I + public static final int GL_INVERT = 5386; + + // Field descriptor #544 I + public static final int GL_OR_REVERSE = 5387; + + // Field descriptor #544 I + public static final int GL_COPY_INVERTED = 5388; + + // Field descriptor #544 I + public static final int GL_OR_INVERTED = 5389; + + // Field descriptor #544 I + public static final int GL_NAND = 5390; + + // Field descriptor #544 I + public static final int GL_SET = 5391; + + // Field descriptor #544 I + public static final int GL_EMISSION = 5632; + + // Field descriptor #544 I + public static final int GL_SHININESS = 5633; + + // Field descriptor #544 I + public static final int GL_AMBIENT_AND_DIFFUSE = 5634; + + // Field descriptor #544 I + public static final int GL_COLOR_INDEXES = 5635; + + // Field descriptor #544 I + public static final int GL_MODELVIEW = 5888; + + // Field descriptor #544 I + public static final int GL_PROJECTION = 5889; + + // Field descriptor #544 I + public static final int GL_TEXTURE = 5890; + + // Field descriptor #544 I + public static final int GL_COLOR = 6144; + + // Field descriptor #544 I + public static final int GL_DEPTH = 6145; + + // Field descriptor #544 I + public static final int GL_STENCIL = 6146; + + // Field descriptor #544 I + public static final int GL_COLOR_INDEX = 6400; + + // Field descriptor #544 I + public static final int GL_STENCIL_INDEX = 6401; + + // Field descriptor #544 I + public static final int GL_DEPTH_COMPONENT = 6402; + + // Field descriptor #544 I + public static final int GL_RED = 6403; + + // Field descriptor #544 I + public static final int GL_GREEN = 6404; + + // Field descriptor #544 I + public static final int GL_BLUE = 6405; + + // Field descriptor #544 I + public static final int GL_ALPHA = 6406; + + // Field descriptor #544 I + public static final int GL_RGB = 6407; + + // Field descriptor #544 I + public static final int GL_RGBA = 6408; + + // Field descriptor #544 I + public static final int GL_LUMINANCE = 6409; + + // Field descriptor #544 I + public static final int GL_LUMINANCE_ALPHA = 6410; + + // Field descriptor #544 I + public static final int GL_BITMAP = 6656; + + // Field descriptor #544 I + public static final int GL_POINT = 6912; + + // Field descriptor #544 I + public static final int GL_LINE = 6913; + + // Field descriptor #544 I + public static final int GL_FILL = 6914; + + // Field descriptor #544 I + public static final int GL_RENDER = 7168; + + // Field descriptor #544 I + public static final int GL_FEEDBACK = 7169; + + // Field descriptor #544 I + public static final int GL_SELECT = 7170; + + // Field descriptor #544 I + public static final int GL_FLAT = 7424; + + // Field descriptor #544 I + public static final int GL_SMOOTH = 7425; + + // Field descriptor #544 I + public static final int GL_KEEP = 7680; + + // Field descriptor #544 I + public static final int GL_REPLACE = 7681; + + // Field descriptor #544 I + public static final int GL_INCR = 7682; + + // Field descriptor #544 I + public static final int GL_DECR = 7683; + + // Field descriptor #544 I + public static final int GL_VENDOR = 7936; + + // Field descriptor #544 I + public static final int GL_RENDERER = 7937; + + // Field descriptor #544 I + public static final int GL_VERSION = 7938; + + // Field descriptor #544 I + public static final int GL_EXTENSIONS = 7939; + + // Field descriptor #544 I + public static final int GL_S = 8192; + + // Field descriptor #544 I + public static final int GL_T = 8193; + + // Field descriptor #544 I + public static final int GL_R = 8194; + + // Field descriptor #544 I + public static final int GL_Q = 8195; + + // Field descriptor #544 I + public static final int GL_MODULATE = 8448; + + // Field descriptor #544 I + public static final int GL_DECAL = 8449; + + // Field descriptor #544 I + public static final int GL_TEXTURE_ENV_MODE = 8704; + + // Field descriptor #544 I + public static final int GL_TEXTURE_ENV_COLOR = 8705; + + // Field descriptor #544 I + public static final int GL_TEXTURE_ENV = 8960; + + // Field descriptor #544 I + public static final int GL_EYE_LINEAR = 9216; + + // Field descriptor #544 I + public static final int GL_OBJECT_LINEAR = 9217; + + // Field descriptor #544 I + public static final int GL_SPHERE_MAP = 9218; + + // Field descriptor #544 I + public static final int GL_TEXTURE_GEN_MODE = 9472; + + // Field descriptor #544 I + public static final int GL_OBJECT_PLANE = 9473; + + // Field descriptor #544 I + public static final int GL_EYE_PLANE = 9474; + + // Field descriptor #544 I + public static final int GL_NEAREST = 9728; + + // Field descriptor #544 I + public static final int GL_LINEAR = 9729; + + // Field descriptor #544 I + public static final int GL_NEAREST_MIPMAP_NEAREST = 9984; + + // Field descriptor #544 I + public static final int GL_LINEAR_MIPMAP_NEAREST = 9985; + + // Field descriptor #544 I + public static final int GL_NEAREST_MIPMAP_LINEAR = 9986; + + // Field descriptor #544 I + public static final int GL_LINEAR_MIPMAP_LINEAR = 9987; + + // Field descriptor #544 I + public static final int GL_TEXTURE_MAG_FILTER = 10240; + + // Field descriptor #544 I + public static final int GL_TEXTURE_MIN_FILTER = 10241; + + // Field descriptor #544 I + public static final int GL_TEXTURE_WRAP_S = 10242; + + // Field descriptor #544 I + public static final int GL_TEXTURE_WRAP_T = 10243; + + // Field descriptor #544 I + public static final int GL_CLAMP = 10496; + + // Field descriptor #544 I + public static final int GL_REPEAT = 10497; + + // Field descriptor #544 I + public static final int GL_CLIENT_PIXEL_STORE_BIT = 1; + + // Field descriptor #544 I + public static final int GL_CLIENT_VERTEX_ARRAY_BIT = 2; + + // Field descriptor #544 I + public static final int GL_ALL_CLIENT_ATTRIB_BITS = -1; + + // Field descriptor #544 I + public static final int GL_POLYGON_OFFSET_FACTOR = 32824; + + // Field descriptor #544 I + public static final int GL_POLYGON_OFFSET_UNITS = 10752; + + // Field descriptor #544 I + public static final int GL_POLYGON_OFFSET_POINT = 10753; + + // Field descriptor #544 I + public static final int GL_POLYGON_OFFSET_LINE = 10754; + + // Field descriptor #544 I + public static final int GL_POLYGON_OFFSET_FILL = 32823; + + // Field descriptor #544 I + public static final int GL_ALPHA4 = 32827; + + // Field descriptor #544 I + public static final int GL_ALPHA8 = 32828; + + // Field descriptor #544 I + public static final int GL_ALPHA12 = 32829; + + // Field descriptor #544 I + public static final int GL_ALPHA16 = 32830; + + // Field descriptor #544 I + public static final int GL_LUMINANCE4 = 32831; + + // Field descriptor #544 I + public static final int GL_LUMINANCE8 = 32832; + + // Field descriptor #544 I + public static final int GL_LUMINANCE12 = 32833; + + // Field descriptor #544 I + public static final int GL_LUMINANCE16 = 32834; + + // Field descriptor #544 I + public static final int GL_LUMINANCE4_ALPHA4 = 32835; + + // Field descriptor #544 I + public static final int GL_LUMINANCE6_ALPHA2 = 32836; + + // Field descriptor #544 I + public static final int GL_LUMINANCE8_ALPHA8 = 32837; + + // Field descriptor #544 I + public static final int GL_LUMINANCE12_ALPHA4 = 32838; + + // Field descriptor #544 I + public static final int GL_LUMINANCE12_ALPHA12 = 32839; + + // Field descriptor #544 I + public static final int GL_LUMINANCE16_ALPHA16 = 32840; + + // Field descriptor #544 I + public static final int GL_INTENSITY = 32841; + + // Field descriptor #544 I + public static final int GL_INTENSITY4 = 32842; + + // Field descriptor #544 I + public static final int GL_INTENSITY8 = 32843; + + // Field descriptor #544 I + public static final int GL_INTENSITY12 = 32844; + + // Field descriptor #544 I + public static final int GL_INTENSITY16 = 32845; + + // Field descriptor #544 I + public static final int GL_R3_G3_B2 = 10768; + + // Field descriptor #544 I + public static final int GL_RGB4 = 32847; + + // Field descriptor #544 I + public static final int GL_RGB5 = 32848; + + // Field descriptor #544 I + public static final int GL_RGB8 = 32849; + + // Field descriptor #544 I + public static final int GL_RGB10 = 32850; + + // Field descriptor #544 I + public static final int GL_RGB12 = 32851; + + // Field descriptor #544 I + public static final int GL_RGB16 = 32852; + + // Field descriptor #544 I + public static final int GL_RGBA2 = 32853; + + // Field descriptor #544 I + public static final int GL_RGBA4 = 32854; + + // Field descriptor #544 I + public static final int GL_RGB5_A1 = 32855; + + // Field descriptor #544 I + public static final int GL_RGBA8 = 32856; + + // Field descriptor #544 I + public static final int GL_RGB10_A2 = 32857; + + // Field descriptor #544 I + public static final int GL_RGBA12 = 32858; + + // Field descriptor #544 I + public static final int GL_RGBA16 = 32859; + + // Field descriptor #544 I + public static final int GL_TEXTURE_RED_SIZE = 32860; + + // Field descriptor #544 I + public static final int GL_TEXTURE_GREEN_SIZE = 32861; + + // Field descriptor #544 I + public static final int GL_TEXTURE_BLUE_SIZE = 32862; + + // Field descriptor #544 I + public static final int GL_TEXTURE_ALPHA_SIZE = 32863; + + // Field descriptor #544 I + public static final int GL_TEXTURE_LUMINANCE_SIZE = 32864; + + // Field descriptor #544 I + public static final int GL_TEXTURE_INTENSITY_SIZE = 32865; + + // Field descriptor #544 I + public static final int GL_PROXY_TEXTURE_1D = 32867; + + // Field descriptor #544 I + public static final int GL_PROXY_TEXTURE_2D = 32868; + + // Field descriptor #544 I + public static final int GL_TEXTURE_PRIORITY = 32870; + + // Field descriptor #544 I + public static final int GL_TEXTURE_RESIDENT = 32871; + + // Field descriptor #544 I + public static final int GL_TEXTURE_BINDING_1D = 32872; + + // Field descriptor #544 I + public static final int GL_TEXTURE_BINDING_2D = 32873; + + // Field descriptor #544 I + public static final int GL_VERTEX_ARRAY = 32884; + + // Field descriptor #544 I + public static final int GL_NORMAL_ARRAY = 32885; + + // Field descriptor #544 I + public static final int GL_COLOR_ARRAY = 32886; + + // Field descriptor #544 I + public static final int GL_INDEX_ARRAY = 32887; + + // Field descriptor #544 I + public static final int GL_TEXTURE_COORD_ARRAY = 32888; + + // Field descriptor #544 I + public static final int GL_EDGE_FLAG_ARRAY = 32889; + + // Field descriptor #544 I + public static final int GL_VERTEX_ARRAY_SIZE = 32890; + + // Field descriptor #544 I + public static final int GL_VERTEX_ARRAY_TYPE = 32891; + + // Field descriptor #544 I + public static final int GL_VERTEX_ARRAY_STRIDE = 32892; + + // Field descriptor #544 I + public static final int GL_NORMAL_ARRAY_TYPE = 32894; + + // Field descriptor #544 I + public static final int GL_NORMAL_ARRAY_STRIDE = 32895; + + // Field descriptor #544 I + public static final int GL_COLOR_ARRAY_SIZE = 32897; + + // Field descriptor #544 I + public static final int GL_COLOR_ARRAY_TYPE = 32898; + + // Field descriptor #544 I + public static final int GL_COLOR_ARRAY_STRIDE = 32899; + + // Field descriptor #544 I + public static final int GL_INDEX_ARRAY_TYPE = 32901; + + // Field descriptor #544 I + public static final int GL_INDEX_ARRAY_STRIDE = 32902; + + // Field descriptor #544 I + public static final int GL_TEXTURE_COORD_ARRAY_SIZE = 32904; + + // Field descriptor #544 I + public static final int GL_TEXTURE_COORD_ARRAY_TYPE = 32905; + + // Field descriptor #544 I + public static final int GL_TEXTURE_COORD_ARRAY_STRIDE = 32906; + + // Field descriptor #544 I + public static final int GL_EDGE_FLAG_ARRAY_STRIDE = 32908; + + // Field descriptor #544 I + public static final int GL_VERTEX_ARRAY_POINTER = 32910; + + // Field descriptor #544 I + public static final int GL_NORMAL_ARRAY_POINTER = 32911; + + // Field descriptor #544 I + public static final int GL_COLOR_ARRAY_POINTER = 32912; + + // Field descriptor #544 I + public static final int GL_INDEX_ARRAY_POINTER = 32913; + + // Field descriptor #544 I + public static final int GL_TEXTURE_COORD_ARRAY_POINTER = 32914; + + // Field descriptor #544 I + public static final int GL_EDGE_FLAG_ARRAY_POINTER = 32915; + + // Field descriptor #544 I + public static final int GL_V2F = 10784; + + // Field descriptor #544 I + public static final int GL_V3F = 10785; + + // Field descriptor #544 I + public static final int GL_C4UB_V2F = 10786; + + // Field descriptor #544 I + public static final int GL_C4UB_V3F = 10787; + + // Field descriptor #544 I + public static final int GL_C3F_V3F = 10788; + + // Field descriptor #544 I + public static final int GL_N3F_V3F = 10789; + + // Field descriptor #544 I + public static final int GL_C4F_N3F_V3F = 10790; + + // Field descriptor #544 I + public static final int GL_T2F_V3F = 10791; + + // Field descriptor #544 I + public static final int GL_T4F_V4F = 10792; + + // Field descriptor #544 I + public static final int GL_T2F_C4UB_V3F = 10793; + + // Field descriptor #544 I + public static final int GL_T2F_C3F_V3F = 10794; + + // Field descriptor #544 I + public static final int GL_T2F_N3F_V3F = 10795; + + // Field descriptor #544 I + public static final int GL_T2F_C4F_N3F_V3F = 10796; + + // Field descriptor #544 I + public static final int GL_T4F_C4F_N3F_V4F = 10797; + + // Field descriptor #544 I + public static final int GL_LOGIC_OP = 3057; + + // Field descriptor #544 I + public static final int GL_TEXTURE_COMPONENTS = 4099; + + // Field descriptor #45 I + public static final int GL_TEXTURE_BINDING_3D = 32874; + + // Field descriptor #45 I + public static final int GL_PACK_SKIP_IMAGES = 32875; + + // Field descriptor #45 I + public static final int GL_PACK_IMAGE_HEIGHT = 32876; + + // Field descriptor #45 I + public static final int GL_UNPACK_SKIP_IMAGES = 32877; + + // Field descriptor #45 I + public static final int GL_UNPACK_IMAGE_HEIGHT = 32878; + + // Field descriptor #45 I + public static final int GL_TEXTURE_3D = 32879; + + // Field descriptor #45 I + public static final int GL_PROXY_TEXTURE_3D = 32880; + + // Field descriptor #45 I + public static final int GL_TEXTURE_DEPTH = 32881; + + // Field descriptor #45 I + public static final int GL_TEXTURE_WRAP_R = 32882; + + // Field descriptor #45 I + public static final int GL_MAX_3D_TEXTURE_SIZE = 32883; + + // Field descriptor #45 I + public static final int GL_BGR = 32992; + + // Field descriptor #45 I + public static final int GL_BGRA = 32993; + + // Field descriptor #45 I + public static final int GL_UNSIGNED_BYTE_3_3_2 = 32818; + + // Field descriptor #45 I + public static final int GL_UNSIGNED_BYTE_2_3_3_REV = 33634; + + // Field descriptor #45 I + public static final int GL_UNSIGNED_SHORT_5_6_5 = 33635; + + // Field descriptor #45 I + public static final int GL_UNSIGNED_SHORT_5_6_5_REV = 33636; + + // Field descriptor #45 I + public static final int GL_UNSIGNED_SHORT_4_4_4_4 = 32819; + + // Field descriptor #45 I + public static final int GL_UNSIGNED_SHORT_4_4_4_4_REV = 33637; + + // Field descriptor #45 I + public static final int GL_UNSIGNED_SHORT_5_5_5_1 = 32820; + + // Field descriptor #45 I + public static final int GL_UNSIGNED_SHORT_1_5_5_5_REV = 33638; + + // Field descriptor #45 I + public static final int GL_UNSIGNED_INT_8_8_8_8 = 32821; + + // Field descriptor #45 I + public static final int GL_UNSIGNED_INT_8_8_8_8_REV = 33639; + + // Field descriptor #45 I + public static final int GL_UNSIGNED_INT_10_10_10_2 = 32822; + + // Field descriptor #45 I + public static final int GL_UNSIGNED_INT_2_10_10_10_REV = 33640; + + // Field descriptor #45 I + public static final int GL_RESCALE_NORMAL = 32826; + + // Field descriptor #45 I + public static final int GL_LIGHT_MODEL_COLOR_CONTROL = 33272; + + // Field descriptor #45 I + public static final int GL_SINGLE_COLOR = 33273; + + // Field descriptor #45 I + public static final int GL_SEPARATE_SPECULAR_COLOR = 33274; + + // Field descriptor #45 I + public static final int GL_CLAMP_TO_EDGE = 33071; + + // Field descriptor #45 I + public static final int GL_TEXTURE_MIN_LOD = 33082; + + // Field descriptor #45 I + public static final int GL_TEXTURE_MAX_LOD = 33083; + + // Field descriptor #45 I + public static final int GL_TEXTURE_BASE_LEVEL = 33084; + + // Field descriptor #45 I + public static final int GL_TEXTURE_MAX_LEVEL = 33085; + + // Field descriptor #45 I + public static final int GL_MAX_ELEMENTS_VERTICES = 33000; + + // Field descriptor #45 I + public static final int GL_MAX_ELEMENTS_INDICES = 33001; + + // Field descriptor #45 I + public static final int GL_ALIASED_POINT_SIZE_RANGE = 33901; + + // Field descriptor #45 I + public static final int GL_ALIASED_LINE_WIDTH_RANGE = 33902; + + // Field descriptor #45 I + public static final int GL_SMOOTH_POINT_SIZE_RANGE = 2834; + + // Field descriptor #45 I + public static final int GL_SMOOTH_POINT_SIZE_GRANULARITY = 2835; + + // Field descriptor #45 I + public static final int GL_SMOOTH_LINE_WIDTH_RANGE = 2850; + + // Field descriptor #45 I + public static final int GL_SMOOTH_LINE_WIDTH_GRANULARITY = 2851; + + // Field descriptor #76 I + public static final int GL_TEXTURE0 = 33984; + + // Field descriptor #76 I + public static final int GL_TEXTURE1 = 33985; + + // Field descriptor #76 I + public static final int GL_TEXTURE2 = 33986; + + // Field descriptor #76 I + public static final int GL_TEXTURE3 = 33987; + + // Field descriptor #76 I + public static final int GL_TEXTURE4 = 33988; + + // Field descriptor #76 I + public static final int GL_TEXTURE5 = 33989; + + // Field descriptor #76 I + public static final int GL_TEXTURE6 = 33990; + + // Field descriptor #76 I + public static final int GL_TEXTURE7 = 33991; + + // Field descriptor #76 I + public static final int GL_TEXTURE8 = 33992; + + // Field descriptor #76 I + public static final int GL_TEXTURE9 = 33993; + + // Field descriptor #76 I + public static final int GL_TEXTURE10 = 33994; + + // Field descriptor #76 I + public static final int GL_TEXTURE11 = 33995; + + // Field descriptor #76 I + public static final int GL_TEXTURE12 = 33996; + + // Field descriptor #76 I + public static final int GL_TEXTURE13 = 33997; + + // Field descriptor #76 I + public static final int GL_TEXTURE14 = 33998; + + // Field descriptor #76 I + public static final int GL_TEXTURE15 = 33999; + + // Field descriptor #76 I + public static final int GL_TEXTURE16 = 34000; + + // Field descriptor #76 I + public static final int GL_TEXTURE17 = 34001; + + // Field descriptor #76 I + public static final int GL_TEXTURE18 = 34002; + + // Field descriptor #76 I + public static final int GL_TEXTURE19 = 34003; + + // Field descriptor #76 I + public static final int GL_TEXTURE20 = 34004; + + // Field descriptor #76 I + public static final int GL_TEXTURE21 = 34005; + + // Field descriptor #76 I + public static final int GL_TEXTURE22 = 34006; + + // Field descriptor #76 I + public static final int GL_TEXTURE23 = 34007; + + // Field descriptor #76 I + public static final int GL_TEXTURE24 = 34008; + + // Field descriptor #76 I + public static final int GL_TEXTURE25 = 34009; + + // Field descriptor #76 I + public static final int GL_TEXTURE26 = 34010; + + // Field descriptor #76 I + public static final int GL_TEXTURE27 = 34011; + + // Field descriptor #76 I + public static final int GL_TEXTURE28 = 34012; + + // Field descriptor #76 I + public static final int GL_TEXTURE29 = 34013; + + // Field descriptor #76 I + public static final int GL_TEXTURE30 = 34014; + + // Field descriptor #76 I + public static final int GL_TEXTURE31 = 34015; + + // Field descriptor #76 I + public static final int GL_ACTIVE_TEXTURE = 34016; + + // Field descriptor #76 I + public static final int GL_CLIENT_ACTIVE_TEXTURE = 34017; + + // Field descriptor #76 I + public static final int GL_MAX_TEXTURE_UNITS = 34018; + + // Field descriptor #76 I + public static final int GL_NORMAL_MAP = 34065; + + // Field descriptor #76 I + public static final int GL_REFLECTION_MAP = 34066; + + // Field descriptor #76 I + public static final int GL_TEXTURE_CUBE_MAP = 34067; + + // Field descriptor #76 I + public static final int GL_TEXTURE_BINDING_CUBE_MAP = 34068; + + // Field descriptor #76 I + public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_X = 34069; + + // Field descriptor #76 I + public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_X = 34070; + + // Field descriptor #76 I + public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Y = 34071; + + // Field descriptor #76 I + public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 34072; + + // Field descriptor #76 I + public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 34073; + + // Field descriptor #76 I + public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 34074; + + // Field descriptor #76 I + public static final int GL_PROXY_TEXTURE_CUBE_MAP = 34075; + + // Field descriptor #76 I + public static final int GL_MAX_CUBE_MAP_TEXTURE_SIZE = 34076; + + // Field descriptor #76 I + public static final int GL_COMPRESSED_ALPHA = 34025; + + // Field descriptor #76 I + public static final int GL_COMPRESSED_LUMINANCE = 34026; + + // Field descriptor #76 I + public static final int GL_COMPRESSED_LUMINANCE_ALPHA = 34027; + + // Field descriptor #76 I + public static final int GL_COMPRESSED_INTENSITY = 34028; + + // Field descriptor #76 I + public static final int GL_COMPRESSED_RGB = 34029; + + // Field descriptor #76 I + public static final int GL_COMPRESSED_RGBA = 34030; + + // Field descriptor #76 I + public static final int GL_TEXTURE_COMPRESSION_HINT = 34031; + + // Field descriptor #76 I + public static final int GL_TEXTURE_COMPRESSED_IMAGE_SIZE = 34464; + + // Field descriptor #76 I + public static final int GL_TEXTURE_COMPRESSED = 34465; + + // Field descriptor #76 I + public static final int GL_NUM_COMPRESSED_TEXTURE_FORMATS = 34466; + + // Field descriptor #76 I + public static final int GL_COMPRESSED_TEXTURE_FORMATS = 34467; + + // Field descriptor #76 I + public static final int GL_MULTISAMPLE = 32925; + + // Field descriptor #76 I + public static final int GL_SAMPLE_ALPHA_TO_COVERAGE = 32926; + + // Field descriptor #76 I + public static final int GL_SAMPLE_ALPHA_TO_ONE = 32927; + + // Field descriptor #76 I + public static final int GL_SAMPLE_COVERAGE = 32928; + + // Field descriptor #76 I + public static final int GL_SAMPLE_BUFFERS = 32936; + + // Field descriptor #76 I + public static final int GL_SAMPLES = 32937; + + // Field descriptor #76 I + public static final int GL_SAMPLE_COVERAGE_VALUE = 32938; + + // Field descriptor #76 I + public static final int GL_SAMPLE_COVERAGE_INVERT = 32939; + + // Field descriptor #76 I + public static final int GL_MULTISAMPLE_BIT = 536870912; + + // Field descriptor #76 I + public static final int GL_TRANSPOSE_MODELVIEW_MATRIX = 34019; + + // Field descriptor #76 I + public static final int GL_TRANSPOSE_PROJECTION_MATRIX = 34020; + + // Field descriptor #76 I + public static final int GL_TRANSPOSE_TEXTURE_MATRIX = 34021; + + // Field descriptor #76 I + public static final int GL_TRANSPOSE_COLOR_MATRIX = 34022; + + // Field descriptor #76 I + public static final int GL_COMBINE = 34160; + + // Field descriptor #76 I + public static final int GL_COMBINE_RGB = 34161; + + // Field descriptor #76 I + public static final int GL_COMBINE_ALPHA = 34162; + + // Field descriptor #76 I + public static final int GL_SOURCE0_RGB = 34176; + + // Field descriptor #76 I + public static final int GL_SOURCE1_RGB = 34177; + + // Field descriptor #76 I + public static final int GL_SOURCE2_RGB = 34178; + + // Field descriptor #76 I + public static final int GL_SOURCE0_ALPHA = 34184; + + // Field descriptor #76 I + public static final int GL_SOURCE1_ALPHA = 34185; + + // Field descriptor #76 I + public static final int GL_SOURCE2_ALPHA = 34186; + + // Field descriptor #76 I + public static final int GL_OPERAND0_RGB = 34192; + + // Field descriptor #76 I + public static final int GL_OPERAND1_RGB = 34193; + + // Field descriptor #76 I + public static final int GL_OPERAND2_RGB = 34194; + + // Field descriptor #76 I + public static final int GL_OPERAND0_ALPHA = 34200; + + // Field descriptor #76 I + public static final int GL_OPERAND1_ALPHA = 34201; + + // Field descriptor #76 I + public static final int GL_OPERAND2_ALPHA = 34202; + + // Field descriptor #76 I + public static final int GL_RGB_SCALE = 34163; + + // Field descriptor #76 I + public static final int GL_ADD_SIGNED = 34164; + + // Field descriptor #76 I + public static final int GL_INTERPOLATE = 34165; + + // Field descriptor #76 I + public static final int GL_SUBTRACT = 34023; + + // Field descriptor #76 I + public static final int GL_CONSTANT = 34166; + + // Field descriptor #76 I + public static final int GL_PRIMARY_COLOR = 34167; + + // Field descriptor #76 I + public static final int GL_PREVIOUS = 34168; + + // Field descriptor #76 I + public static final int GL_DOT3_RGB = 34478; + + // Field descriptor #76 I + public static final int GL_DOT3_RGBA = 34479; + + // Field descriptor #76 I + public static final int GL_CLAMP_TO_BORDER = 33069; + + // Field descriptor #71 I + public static final int GL_ARRAY_BUFFER = 34962; + + // Field descriptor #71 I + public static final int GL_ELEMENT_ARRAY_BUFFER = 34963; + + // Field descriptor #71 I + public static final int GL_ARRAY_BUFFER_BINDING = 34964; + + // Field descriptor #71 I + public static final int GL_ELEMENT_ARRAY_BUFFER_BINDING = 34965; + + // Field descriptor #71 I + public static final int GL_VERTEX_ARRAY_BUFFER_BINDING = 34966; + + // Field descriptor #71 I + public static final int GL_NORMAL_ARRAY_BUFFER_BINDING = 34967; + + // Field descriptor #71 I + public static final int GL_COLOR_ARRAY_BUFFER_BINDING = 34968; + + // Field descriptor #71 I + public static final int GL_INDEX_ARRAY_BUFFER_BINDING = 34969; + + // Field descriptor #71 I + public static final int GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING = 34970; + + // Field descriptor #71 I + public static final int GL_EDGE_FLAG_ARRAY_BUFFER_BINDING = 34971; + + // Field descriptor #71 I + public static final int GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING = 34972; + + // Field descriptor #71 I + public static final int GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING = 34973; + + // Field descriptor #71 I + public static final int GL_WEIGHT_ARRAY_BUFFER_BINDING = 34974; + + // Field descriptor #71 I + public static final int GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 34975; + + // Field descriptor #71 I + public static final int GL_STREAM_DRAW = 35040; + + // Field descriptor #71 I + public static final int GL_STREAM_READ = 35041; + + // Field descriptor #71 I + public static final int GL_STREAM_COPY = 35042; + + // Field descriptor #71 I + public static final int GL_STATIC_DRAW = 35044; + + // Field descriptor #71 I + public static final int GL_STATIC_READ = 35045; + + // Field descriptor #71 I + public static final int GL_STATIC_COPY = 35046; + + // Field descriptor #71 I + public static final int GL_DYNAMIC_DRAW = 35048; + + // Field descriptor #71 I + public static final int GL_DYNAMIC_READ = 35049; + + // Field descriptor #71 I + public static final int GL_DYNAMIC_COPY = 35050; + + // Field descriptor #71 I + public static final int GL_READ_ONLY = 35000; + + // Field descriptor #71 I + public static final int GL_WRITE_ONLY = 35001; + + // Field descriptor #71 I + public static final int GL_READ_WRITE = 35002; + + // Field descriptor #71 I + public static final int GL_BUFFER_SIZE = 34660; + + // Field descriptor #71 I + public static final int GL_BUFFER_USAGE = 34661; + + // Field descriptor #71 I + public static final int GL_BUFFER_ACCESS = 35003; + + // Field descriptor #71 I + public static final int GL_BUFFER_MAPPED = 35004; + + // Field descriptor #71 I + public static final int GL_BUFFER_MAP_POINTER = 35005; + + // Field descriptor #71 I + public static final int GL_FOG_COORD_SRC = 33872; + + // Field descriptor #71 I + public static final int GL_FOG_COORD = 33873; + + // Field descriptor #71 I + public static final int GL_CURRENT_FOG_COORD = 33875; + + // Field descriptor #71 I + public static final int GL_FOG_COORD_ARRAY_TYPE = 33876; + + // Field descriptor #71 I + public static final int GL_FOG_COORD_ARRAY_STRIDE = 33877; + + // Field descriptor #71 I + public static final int GL_FOG_COORD_ARRAY_POINTER = 33878; + + // Field descriptor #71 I + public static final int GL_FOG_COORD_ARRAY = 33879; + + // Field descriptor #71 I + public static final int GL_FOG_COORD_ARRAY_BUFFER_BINDING = 34973; + + // Field descriptor #71 I + public static final int GL_SRC0_RGB = 34176; + + // Field descriptor #71 I + public static final int GL_SRC1_RGB = 34177; + + // Field descriptor #71 I + public static final int GL_SRC2_RGB = 34178; + + // Field descriptor #71 I + public static final int GL_SRC0_ALPHA = 34184; + + // Field descriptor #71 I + public static final int GL_SRC1_ALPHA = 34185; + + // Field descriptor #71 I + public static final int GL_SRC2_ALPHA = 34186; + + // Field descriptor #71 I + public static final int GL_SAMPLES_PASSED = 35092; + + // Field descriptor #71 I + public static final int GL_QUERY_COUNTER_BITS = 34916; + + // Field descriptor #71 I + public static final int GL_CURRENT_QUERY = 34917; + + // Field descriptor #71 I + public static final int GL_QUERY_RESULT = 34918; + + // Field descriptor #71 I + public static final int GL_QUERY_RESULT_AVAILABLE = 34919; + + // Field descriptor #194 I + public static final int GL_SHADING_LANGUAGE_VERSION = 35724; + + // Field descriptor #194 I + public static final int GL_CURRENT_PROGRAM = 35725; + + // Field descriptor #194 I + public static final int GL_SHADER_TYPE = 35663; + + // Field descriptor #194 I + public static final int GL_DELETE_STATUS = 35712; + + // Field descriptor #194 I + public static final int GL_COMPILE_STATUS = 35713; + + // Field descriptor #194 I + public static final int GL_LINK_STATUS = 35714; + + // Field descriptor #194 I + public static final int GL_VALIDATE_STATUS = 35715; + + // Field descriptor #194 I + public static final int GL_INFO_LOG_LENGTH = 35716; + + // Field descriptor #194 I + public static final int GL_ATTACHED_SHADERS = 35717; + + // Field descriptor #194 I + public static final int GL_ACTIVE_UNIFORMS = 35718; + + // Field descriptor #194 I + public static final int GL_ACTIVE_UNIFORM_MAX_LENGTH = 35719; + + // Field descriptor #194 I + public static final int GL_ACTIVE_ATTRIBUTES = 35721; + + // Field descriptor #194 I + public static final int GL_ACTIVE_ATTRIBUTE_MAX_LENGTH = 35722; + + // Field descriptor #194 I + public static final int GL_SHADER_SOURCE_LENGTH = 35720; + + // Field descriptor #194 I + public static final int GL_SHADER_OBJECT = 35656; + + // Field descriptor #194 I + public static final int GL_FLOAT_VEC2 = 35664; + + // Field descriptor #194 I + public static final int GL_FLOAT_VEC3 = 35665; + + // Field descriptor #194 I + public static final int GL_FLOAT_VEC4 = 35666; + + // Field descriptor #194 I + public static final int GL_INT_VEC2 = 35667; + + // Field descriptor #194 I + public static final int GL_INT_VEC3 = 35668; + + // Field descriptor #194 I + public static final int GL_INT_VEC4 = 35669; + + // Field descriptor #194 I + public static final int GL_BOOL = 35670; + + // Field descriptor #194 I + public static final int GL_BOOL_VEC2 = 35671; + + // Field descriptor #194 I + public static final int GL_BOOL_VEC3 = 35672; + + // Field descriptor #194 I + public static final int GL_BOOL_VEC4 = 35673; + + // Field descriptor #194 I + public static final int GL_FLOAT_MAT2 = 35674; + + // Field descriptor #194 I + public static final int GL_FLOAT_MAT3 = 35675; + + // Field descriptor #194 I + public static final int GL_FLOAT_MAT4 = 35676; + + // Field descriptor #194 I + public static final int GL_SAMPLER_1D = 35677; + + // Field descriptor #194 I + public static final int GL_SAMPLER_2D = 35678; + + // Field descriptor #194 I + public static final int GL_SAMPLER_3D = 35679; + + // Field descriptor #194 I + public static final int GL_SAMPLER_CUBE = 35680; + + // Field descriptor #194 I + public static final int GL_SAMPLER_1D_SHADOW = 35681; + + // Field descriptor #194 I + public static final int GL_SAMPLER_2D_SHADOW = 35682; + + // Field descriptor #194 I + public static final int GL_VERTEX_SHADER = 35633; + + // Field descriptor #194 I + public static final int GL_MAX_VERTEX_UNIFORM_COMPONENTS = 35658; + + // Field descriptor #194 I + public static final int GL_MAX_VARYING_FLOATS = 35659; + + // Field descriptor #194 I + public static final int GL_MAX_VERTEX_ATTRIBS = 34921; + + // Field descriptor #194 I + public static final int GL_MAX_TEXTURE_IMAGE_UNITS = 34930; + + // Field descriptor #194 I + public static final int GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 35660; + + // Field descriptor #194 I + public static final int GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = 35661; + + // Field descriptor #194 I + public static final int GL_MAX_TEXTURE_COORDS = 34929; + + // Field descriptor #194 I + public static final int GL_VERTEX_PROGRAM_POINT_SIZE = 34370; + + // Field descriptor #194 I + public static final int GL_VERTEX_PROGRAM_TWO_SIDE = 34371; + + // Field descriptor #194 I + public static final int GL_VERTEX_ATTRIB_ARRAY_ENABLED = 34338; + + // Field descriptor #194 I + public static final int GL_VERTEX_ATTRIB_ARRAY_SIZE = 34339; + + // Field descriptor #194 I + public static final int GL_VERTEX_ATTRIB_ARRAY_STRIDE = 34340; + + // Field descriptor #194 I + public static final int GL_VERTEX_ATTRIB_ARRAY_TYPE = 34341; + + // Field descriptor #194 I + public static final int GL_VERTEX_ATTRIB_ARRAY_NORMALIZED = 34922; + + // Field descriptor #194 I + public static final int GL_CURRENT_VERTEX_ATTRIB = 34342; + + // Field descriptor #194 I + public static final int GL_VERTEX_ATTRIB_ARRAY_POINTER = 34373; + + // Field descriptor #194 I + public static final int GL_FRAGMENT_SHADER = 35632; + + // Field descriptor #194 I + public static final int GL_MAX_FRAGMENT_UNIFORM_COMPONENTS = 35657; + + // Field descriptor #194 I + public static final int GL_FRAGMENT_SHADER_DERIVATIVE_HINT = 35723; + + // Field descriptor #194 I + public static final int GL_MAX_DRAW_BUFFERS = 34852; + + // Field descriptor #194 I + public static final int GL_DRAW_BUFFER0 = 34853; + + // Field descriptor #194 I + public static final int GL_DRAW_BUFFER1 = 34854; + + // Field descriptor #194 I + public static final int GL_DRAW_BUFFER2 = 34855; + + // Field descriptor #194 I + public static final int GL_DRAW_BUFFER3 = 34856; + + // Field descriptor #194 I + public static final int GL_DRAW_BUFFER4 = 34857; + + // Field descriptor #194 I + public static final int GL_DRAW_BUFFER5 = 34858; + + // Field descriptor #194 I + public static final int GL_DRAW_BUFFER6 = 34859; + + // Field descriptor #194 I + public static final int GL_DRAW_BUFFER7 = 34860; + + // Field descriptor #194 I + public static final int GL_DRAW_BUFFER8 = 34861; + + // Field descriptor #194 I + public static final int GL_DRAW_BUFFER9 = 34862; + + // Field descriptor #194 I + public static final int GL_DRAW_BUFFER10 = 34863; + + // Field descriptor #194 I + public static final int GL_DRAW_BUFFER11 = 34864; + + // Field descriptor #194 I + public static final int GL_DRAW_BUFFER12 = 34865; + + // Field descriptor #194 I + public static final int GL_DRAW_BUFFER13 = 34866; + + // Field descriptor #194 I + public static final int GL_DRAW_BUFFER14 = 34867; + + // Field descriptor #194 I + public static final int GL_DRAW_BUFFER15 = 34868; + + // Field descriptor #194 I + public static final int GL_POINT_SPRITE = 34913; + + // Field descriptor #194 I + public static final int GL_COORD_REPLACE = 34914; + + // Field descriptor #194 I + public static final int GL_POINT_SPRITE_COORD_ORIGIN = 36000; + + // Field descriptor #194 I + public static final int GL_LOWER_LEFT = 36001; + + // Field descriptor #194 I + public static final int GL_UPPER_LEFT = 36002; + + // Field descriptor #194 I + public static final int GL_STENCIL_BACK_FUNC = 34816; + + // Field descriptor #194 I + public static final int GL_STENCIL_BACK_FAIL = 34817; + + // Field descriptor #194 I + public static final int GL_STENCIL_BACK_PASS_DEPTH_FAIL = 34818; + + // Field descriptor #194 I + public static final int GL_STENCIL_BACK_PASS_DEPTH_PASS = 34819; + + // Field descriptor #194 I + public static final int GL_STENCIL_BACK_REF = 36003; + + // Field descriptor #194 I + public static final int GL_STENCIL_BACK_VALUE_MASK = 36004; + + // Field descriptor #194 I + public static final int GL_STENCIL_BACK_WRITEMASK = 36005; + + // Field descriptor #194 I + public static final int GL_BLEND_EQUATION_RGB = 32777; + + // Field descriptor #194 I + public static final int GL_BLEND_EQUATION_ALPHA = 34877; + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/StreamBuffer.java b/src/main/java/net/lax1dude/eaglercraft/glemu/StreamBuffer.java new file mode 100644 index 0000000..2896a9a --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/StreamBuffer.java @@ -0,0 +1,189 @@ +package net.lax1dude.eaglercraft.glemu; + +import static net.lax1dude.eaglercraft.EaglerAdapter.*; + +public class StreamBuffer { + + public static final int poolSize = 16; + + public final int initialSize; + public final int initialCount; + public final int maxCount; + + protected static final PoolInstance[] pool = new PoolInstance[poolSize]; + protected static int poolBufferID = 0; + + static { + for(int i = 0; i < poolSize; ++i) { + pool[i] = new PoolInstance(); + } + } + + protected static class PoolInstance { + + protected BufferGL vertexBuffer = null; + protected int vertexBufferSize = 0; + + } + + private static PoolInstance fillPoolInstance() { + PoolInstance ret = pool[poolBufferID++]; + if(poolBufferID > poolSize - 1) { + poolBufferID = 0; + } + return ret; + } + + private static void resizeInstance(PoolInstance instance, int requiredMemory) { + if(instance.vertexBuffer == null) { + instance.vertexBuffer = _wglCreateBuffer(); + } + if(instance.vertexBufferSize < requiredMemory) { + int newSize = (requiredMemory & 0xFFFFF000) + 0x2000; + _wglBindBuffer(_wGL_ARRAY_BUFFER, instance.vertexBuffer); + _wglBufferData00(_wGL_ARRAY_BUFFER, newSize, _wGL_STREAM_DRAW); + instance.vertexBufferSize = newSize; + } + } + + protected StreamBufferInstance[] buffers; + + protected int currentBufferId = 0; + protected int overflowCounter = 0; + + protected final IStreamBufferInitializer initializer; + + public static class StreamBufferInstance { + + protected PoolInstance poolInstance = null; + protected BufferArrayGL vertexArray = null; + + public boolean bindQuad16 = false; + public boolean bindQuad32 = false; + + public BufferArrayGL getVertexArray() { + return vertexArray; + } + + public BufferGL getVertexBuffer() { + return poolInstance.vertexBuffer; + } + + } + + public static interface IStreamBufferInitializer { + void initialize(BufferArrayGL vertexArray, BufferGL vertexBuffer); + } + + public StreamBuffer(int initialSize, int initialCount, int maxCount, IStreamBufferInitializer initializer) { + if(maxCount > poolSize) { + maxCount = poolSize; + } + this.buffers = new StreamBufferInstance[initialCount]; + for(int i = 0; i < this.buffers.length; ++i) { + StreamBufferInstance j = new StreamBufferInstance(); + j.poolInstance = fillPoolInstance(); + this.buffers[i] = j; + } + this.initialSize = initialSize; + this.initialCount = initialCount; + this.maxCount = maxCount; + this.initializer = initializer; + } + + public StreamBufferInstance getBuffer(int requiredMemory) { + StreamBufferInstance next = buffers[(currentBufferId++) % buffers.length]; + resizeInstance(next.poolInstance, requiredMemory); + if(next.vertexArray == null) { + next.vertexArray = _wglCreateVertexArray(); + initializer.initialize(next.vertexArray, next.poolInstance.vertexBuffer); + } + return next; + } + + public void optimize() { + overflowCounter += currentBufferId - buffers.length; + if(overflowCounter < -25) { + int newCount = buffers.length - 1 + ((overflowCounter + 25) / 5); + if(newCount < initialCount) { + newCount = initialCount; + } + if(newCount < buffers.length) { + StreamBufferInstance[] newArray = new StreamBufferInstance[newCount]; + for(int i = 0; i < buffers.length; ++i) { + if(i < newArray.length) { + newArray[i] = buffers[i]; + }else { + if(buffers[i].vertexArray != null) { + _wglDeleteVertexArray(buffers[i].vertexArray); + } + } + } + buffers = newArray; + refill(); + } + overflowCounter = 0; + }else if(overflowCounter > 15) { + int newCount = buffers.length + 1 + ((overflowCounter - 15) / 5); + if(newCount > maxCount) { + newCount = maxCount; + } + if(newCount > buffers.length) { + StreamBufferInstance[] newArray = new StreamBufferInstance[newCount]; + for(int i = 0; i < newArray.length; ++i) { + if(i < buffers.length) { + newArray[i] = buffers[i]; + }else { + newArray[i] = new StreamBufferInstance(); + } + } + buffers = newArray; + refill(); + } + overflowCounter = 0; + } + currentBufferId = 0; + } + + private void refill() { + for(int i = 0; i < buffers.length; ++i) { + PoolInstance j = fillPoolInstance(); + StreamBufferInstance k = buffers[i]; + if(j != k.poolInstance) { + PoolInstance l = k.poolInstance; + k.poolInstance = j; + if(k.vertexArray != null) { + if(j.vertexBuffer == null) { + resizeInstance(j, l.vertexBufferSize); + } + initializer.initialize(k.vertexArray, j.vertexBuffer); + } + } + } + } + + public void destroy() { + for(int i = 0; i < buffers.length; ++i) { + StreamBufferInstance next = buffers[i]; + if(next.vertexArray != null) { + _wglDeleteVertexArray(next.vertexArray); + } + } + buffers = new StreamBufferInstance[initialCount]; + for(int i = 0; i < initialCount; ++i) { + StreamBufferInstance j = new StreamBufferInstance(); + j.poolInstance = fillPoolInstance(); + buffers[i] = j; + } + } + + public static void destroyPool() { + for(int i = 0; i < pool.length; ++i) { + if(pool[i].vertexBuffer != null) { + _wglDeleteBuffer(pool[i].vertexBuffer); + pool[i].vertexBuffer = null; + } + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Matrix.java b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Matrix.java new file mode 100644 index 0000000..d27abab --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Matrix.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2002-2008 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.lax1dude.eaglercraft.glemu.vector; + +import java.io.Serializable; +import java.nio.FloatBuffer; + +/** + * + * Base class for matrices. When a matrix is constructed it will be the identity + * matrix unless otherwise stated. + * + * @author cix_foo + * @version $Revision$ + * $Id$ + */ +public abstract class Matrix implements Serializable { + + /** + * Constructor for Matrix. + */ + protected Matrix() { + super(); + } + + /** + * Set this matrix to be the identity matrix. + * @return this + */ + public abstract Matrix setIdentity(); + + + /** + * Invert this matrix + * @return this + */ + public abstract Matrix invert(); + + + /** + * Load from a float buffer. The buffer stores the matrix in column major + * (OpenGL) order. + * + * @param buf A float buffer to read from + * @return this + */ + public abstract Matrix load(FloatBuffer buf); + + + /** + * Load from a float buffer. The buffer stores the matrix in row major + * (mathematical) order. + * + * @param buf A float buffer to read from + * @return this + */ + public abstract Matrix loadTranspose(FloatBuffer buf); + + + /** + * Negate this matrix + * @return this + */ + public abstract Matrix negate(); + + + /** + * Store this matrix in a float buffer. The matrix is stored in column + * major (openGL) order. + * @param buf The buffer to store this matrix in + * @return this + */ + public abstract Matrix store(FloatBuffer buf); + + + /** + * Store this matrix in a float buffer. The matrix is stored in row + * major (maths) order. + * @param buf The buffer to store this matrix in + * @return this + */ + public abstract Matrix storeTranspose(FloatBuffer buf); + + + /** + * Transpose this matrix + * @return this + */ + public abstract Matrix transpose(); + + + /** + * Set this matrix to 0. + * @return this + */ + public abstract Matrix setZero(); + + + /** + * @return the determinant of the matrix + */ + public abstract float determinant(); + + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Matrix2f.java b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Matrix2f.java new file mode 100644 index 0000000..10598b9 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Matrix2f.java @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2002-2008 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.lax1dude.eaglercraft.glemu.vector; + +import java.io.Serializable; +import java.nio.FloatBuffer; + +/** + * + * Holds a 2x2 matrix + * + * @author cix_foo + * @version $Revision$ + * $Id$ + */ + +public class Matrix2f extends Matrix implements Serializable { + + private static final long serialVersionUID = 1L; + + public float m00, m01, m10, m11; + + /** + * Constructor for Matrix2f. The matrix is initialised to the identity. + */ + public Matrix2f() { + setIdentity(); + } + + /** + * Constructor + */ + public Matrix2f(Matrix2f src) { + load(src); + } + + /** + * Load from another matrix + * @param src The source matrix + * @return this + */ + public Matrix2f load(Matrix2f src) { + return load(src, this); + } + + /** + * Copy the source matrix to the destination matrix. + * @param src The source matrix + * @param dest The destination matrix, or null if a new one should be created. + * @return The copied matrix + */ + public static Matrix2f load(Matrix2f src, Matrix2f dest) { + if (dest == null) + dest = new Matrix2f(); + + dest.m00 = src.m00; + dest.m01 = src.m01; + dest.m10 = src.m10; + dest.m11 = src.m11; + + return dest; + } + + /** + * Load from a float buffer. The buffer stores the matrix in column major + * (OpenGL) order. + * + * @param buf A float buffer to read from + * @return this + */ + public Matrix load(FloatBuffer buf) { + + m00 = buf.get(); + m01 = buf.get(); + m10 = buf.get(); + m11 = buf.get(); + + return this; + } + + /** + * Load from a float buffer. The buffer stores the matrix in row major + * (mathematical) order. + * + * @param buf A float buffer to read from + * @return this + */ + public Matrix loadTranspose(FloatBuffer buf) { + + m00 = buf.get(); + m10 = buf.get(); + m01 = buf.get(); + m11 = buf.get(); + + return this; + } + + /** + * Store this matrix in a float buffer. The matrix is stored in column + * major (openGL) order. + * @param buf The buffer to store this matrix in + */ + public Matrix store(FloatBuffer buf) { + buf.put(m00); + buf.put(m01); + buf.put(m10); + buf.put(m11); + return this; + } + + /** + * Store this matrix in a float buffer. The matrix is stored in row + * major (maths) order. + * @param buf The buffer to store this matrix in + */ + public Matrix storeTranspose(FloatBuffer buf) { + buf.put(m00); + buf.put(m10); + buf.put(m01); + buf.put(m11); + return this; + } + + + + /** + * Add two matrices together and place the result in a third matrix. + * @param left The left source matrix + * @param right The right source matrix + * @param dest The destination matrix, or null if a new one is to be created + * @return the destination matrix + */ + public static Matrix2f add(Matrix2f left, Matrix2f right, Matrix2f dest) { + if (dest == null) + dest = new Matrix2f(); + + dest.m00 = left.m00 + right.m00; + dest.m01 = left.m01 + right.m01; + dest.m10 = left.m10 + right.m10; + dest.m11 = left.m11 + right.m11; + + return dest; + } + + /** + * Subtract the right matrix from the left and place the result in a third matrix. + * @param left The left source matrix + * @param right The right source matrix + * @param dest The destination matrix, or null if a new one is to be created + * @return the destination matrix + */ + public static Matrix2f sub(Matrix2f left, Matrix2f right, Matrix2f dest) { + if (dest == null) + dest = new Matrix2f(); + + dest.m00 = left.m00 - right.m00; + dest.m01 = left.m01 - right.m01; + dest.m10 = left.m10 - right.m10; + dest.m11 = left.m11 - right.m11; + + return dest; + } + + /** + * Multiply the right matrix by the left and place the result in a third matrix. + * @param left The left source matrix + * @param right The right source matrix + * @param dest The destination matrix, or null if a new one is to be created + * @return the destination matrix + */ + public static Matrix2f mul(Matrix2f left, Matrix2f right, Matrix2f dest) { + if (dest == null) + dest = new Matrix2f(); + + float m00 = left.m00 * right.m00 + left.m10 * right.m01; + float m01 = left.m01 * right.m00 + left.m11 * right.m01; + float m10 = left.m00 * right.m10 + left.m10 * right.m11; + float m11 = left.m01 * right.m10 + left.m11 * right.m11; + + dest.m00 = m00; + dest.m01 = m01; + dest.m10 = m10; + dest.m11 = m11; + + return dest; + } + + /** + * Transform a Vector by a matrix and return the result in a destination + * vector. + * @param left The left matrix + * @param right The right vector + * @param dest The destination vector, or null if a new one is to be created + * @return the destination vector + */ + public static Vector2f transform(Matrix2f left, Vector2f right, Vector2f dest) { + if (dest == null) + dest = new Vector2f(); + + float x = left.m00 * right.x + left.m10 * right.y; + float y = left.m01 * right.x + left.m11 * right.y; + + dest.x = x; + dest.y = y; + + return dest; + } + + /** + * Transpose this matrix + * @return this + */ + public Matrix transpose() { + return transpose(this); + } + + /** + * Transpose this matrix and place the result in another matrix. + * @param dest The destination matrix or null if a new matrix is to be created + * @return the transposed matrix + */ + public Matrix2f transpose(Matrix2f dest) { + return transpose(this, dest); + } + + /** + * Transpose the source matrix and place the result in the destination matrix. + * @param src The source matrix or null if a new matrix is to be created + * @param dest The destination matrix or null if a new matrix is to be created + * @return the transposed matrix + */ + public static Matrix2f transpose(Matrix2f src, Matrix2f dest) { + if (dest == null) + dest = new Matrix2f(); + + float m01 = src.m10; + float m10 = src.m01; + + dest.m01 = m01; + dest.m10 = m10; + + return dest; + } + + /** + * Invert this matrix + * @return this if successful, null otherwise + */ + public Matrix invert() { + return invert(this, this); + } + + /** + * Invert the source matrix and place the result in the destination matrix. + * @param src The source matrix to be inverted + * @param dest The destination matrix or null if a new matrix is to be created + * @return The inverted matrix, or null if source can't be reverted. + */ + public static Matrix2f invert(Matrix2f src, Matrix2f dest) { + /* + *inv(A) = 1/det(A) * adj(A); + */ + + float determinant = src.determinant(); + if (determinant != 0) { + if (dest == null) + dest = new Matrix2f(); + float determinant_inv = 1f/determinant; + float t00 = src.m11*determinant_inv; + float t01 = -src.m01*determinant_inv; + float t11 = src.m00*determinant_inv; + float t10 = -src.m10*determinant_inv; + + dest.m00 = t00; + dest.m01 = t01; + dest.m10 = t10; + dest.m11 = t11; + return dest; + } else + return null; + } + + /** + * Returns a string representation of this matrix + */ + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append(m00).append(' ').append(m10).append(' ').append('\n'); + buf.append(m01).append(' ').append(m11).append(' ').append('\n'); + return buf.toString(); + } + + /** + * Negate this matrix + * @return this + */ + public Matrix negate() { + return negate(this); + } + + /** + * Negate this matrix and stash the result in another matrix. + * @param dest The destination matrix, or null if a new matrix is to be created + * @return the negated matrix + */ + public Matrix2f negate(Matrix2f dest) { + return negate(this, dest); + } + + /** + * Negate the source matrix and stash the result in the destination matrix. + * @param src The source matrix to be negated + * @param dest The destination matrix, or null if a new matrix is to be created + * @return the negated matrix + */ + public static Matrix2f negate(Matrix2f src, Matrix2f dest) { + if (dest == null) + dest = new Matrix2f(); + + dest.m00 = -src.m00; + dest.m01 = -src.m01; + dest.m10 = -src.m10; + dest.m11 = -src.m11; + + return dest; + } + + /** + * Set this matrix to be the identity matrix. + * @return this + */ + public Matrix setIdentity() { + return setIdentity(this); + } + + /** + * Set the source matrix to be the identity matrix. + * @param src The matrix to set to the identity. + * @return The source matrix + */ + public static Matrix2f setIdentity(Matrix2f src) { + src.m00 = 1.0f; + src.m01 = 0.0f; + src.m10 = 0.0f; + src.m11 = 1.0f; + return src; + } + + /** + * Set this matrix to 0. + * @return this + */ + public Matrix setZero() { + return setZero(this); + } + + public static Matrix2f setZero(Matrix2f src) { + src.m00 = 0.0f; + src.m01 = 0.0f; + src.m10 = 0.0f; + src.m11 = 0.0f; + return src; + } + + /* (non-Javadoc) + * @see org.lwjgl.vector.Matrix#determinant() + */ + public float determinant() { + return m00 * m11 - m01*m10; + } +} diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Matrix3f.java b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Matrix3f.java new file mode 100644 index 0000000..d743b1d --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Matrix3f.java @@ -0,0 +1,539 @@ +/* + * Copyright (c) 2002-2008 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.lax1dude.eaglercraft.glemu.vector; + +import java.io.Serializable; +import java.nio.FloatBuffer; + +/** + * + * Holds a 3x3 matrix. + * + * @author cix_foo + * @version $Revision$ + * $Id$ + */ + +public class Matrix3f extends Matrix implements Serializable { + + private static final long serialVersionUID = 1L; + + public float m00, + m01, + m02, + m10, + m11, + m12, + m20, + m21, + m22; + + /** + * Constructor for Matrix3f. Matrix is initialised to the identity. + */ + public Matrix3f() { + super(); + setIdentity(); + } + + /** + * Load from another matrix + * @param src The source matrix + * @return this + */ + public Matrix3f load(Matrix3f src) { + return load(src, this); + } + + /** + * Copy source matrix to destination matrix + * @param src The source matrix + * @param dest The destination matrix, or null of a new matrix is to be created + * @return The copied matrix + */ + public static Matrix3f load(Matrix3f src, Matrix3f dest) { + if (dest == null) + dest = new Matrix3f(); + + dest.m00 = src.m00; + dest.m10 = src.m10; + dest.m20 = src.m20; + dest.m01 = src.m01; + dest.m11 = src.m11; + dest.m21 = src.m21; + dest.m02 = src.m02; + dest.m12 = src.m12; + dest.m22 = src.m22; + + return dest; + } + + /** + * Load from a float buffer. The buffer stores the matrix in column major + * (OpenGL) order. + * + * @param buf A float buffer to read from + * @return this + */ + public Matrix load(FloatBuffer buf) { + + m00 = buf.get(); + m01 = buf.get(); + m02 = buf.get(); + m10 = buf.get(); + m11 = buf.get(); + m12 = buf.get(); + m20 = buf.get(); + m21 = buf.get(); + m22 = buf.get(); + + return this; + } + + /** + * Load from a float buffer. The buffer stores the matrix in row major + * (maths) order. + * + * @param buf A float buffer to read from + * @return this + */ + public Matrix loadTranspose(FloatBuffer buf) { + + m00 = buf.get(); + m10 = buf.get(); + m20 = buf.get(); + m01 = buf.get(); + m11 = buf.get(); + m21 = buf.get(); + m02 = buf.get(); + m12 = buf.get(); + m22 = buf.get(); + + return this; + } + + /** + * Store this matrix in a float buffer. The matrix is stored in column + * major (openGL) order. + * @param buf The buffer to store this matrix in + */ + public Matrix store(FloatBuffer buf) { + buf.put(m00); + buf.put(m01); + buf.put(m02); + buf.put(m10); + buf.put(m11); + buf.put(m12); + buf.put(m20); + buf.put(m21); + buf.put(m22); + return this; + } + + public Matrix store(float[] buf) { + buf[0] = m00; + buf[1] = m01; + buf[2] = m02; + buf[3] = m10; + buf[4] = m11; + buf[5] = m12; + buf[6] = m20; + buf[7] = m21; + buf[8] = m22; + return this; + } + + /** + * Store this matrix in a float buffer. The matrix is stored in row + * major (maths) order. + * @param buf The buffer to store this matrix in + */ + public Matrix storeTranspose(FloatBuffer buf) { + buf.put(m00); + buf.put(m10); + buf.put(m20); + buf.put(m01); + buf.put(m11); + buf.put(m21); + buf.put(m02); + buf.put(m12); + buf.put(m22); + return this; + } + + /** + * Add two matrices together and place the result in a third matrix. + * @param left The left source matrix + * @param right The right source matrix + * @param dest The destination matrix, or null if a new one is to be created + * @return the destination matrix + */ + public static Matrix3f add(Matrix3f left, Matrix3f right, Matrix3f dest) { + if (dest == null) + dest = new Matrix3f(); + + dest.m00 = left.m00 + right.m00; + dest.m01 = left.m01 + right.m01; + dest.m02 = left.m02 + right.m02; + dest.m10 = left.m10 + right.m10; + dest.m11 = left.m11 + right.m11; + dest.m12 = left.m12 + right.m12; + dest.m20 = left.m20 + right.m20; + dest.m21 = left.m21 + right.m21; + dest.m22 = left.m22 + right.m22; + + return dest; + } + + /** + * Subtract the right matrix from the left and place the result in a third matrix. + * @param left The left source matrix + * @param right The right source matrix + * @param dest The destination matrix, or null if a new one is to be created + * @return the destination matrix + */ + public static Matrix3f sub(Matrix3f left, Matrix3f right, Matrix3f dest) { + if (dest == null) + dest = new Matrix3f(); + + dest.m00 = left.m00 - right.m00; + dest.m01 = left.m01 - right.m01; + dest.m02 = left.m02 - right.m02; + dest.m10 = left.m10 - right.m10; + dest.m11 = left.m11 - right.m11; + dest.m12 = left.m12 - right.m12; + dest.m20 = left.m20 - right.m20; + dest.m21 = left.m21 - right.m21; + dest.m22 = left.m22 - right.m22; + + return dest; + } + + /** + * Multiply the right matrix by the left and place the result in a third matrix. + * @param left The left source matrix + * @param right The right source matrix + * @param dest The destination matrix, or null if a new one is to be created + * @return the destination matrix + */ + public static Matrix3f mul(Matrix3f left, Matrix3f right, Matrix3f dest) { + if (dest == null) + dest = new Matrix3f(); + + float m00 = + left.m00 * right.m00 + left.m10 * right.m01 + left.m20 * right.m02; + float m01 = + left.m01 * right.m00 + left.m11 * right.m01 + left.m21 * right.m02; + float m02 = + left.m02 * right.m00 + left.m12 * right.m01 + left.m22 * right.m02; + float m10 = + left.m00 * right.m10 + left.m10 * right.m11 + left.m20 * right.m12; + float m11 = + left.m01 * right.m10 + left.m11 * right.m11 + left.m21 * right.m12; + float m12 = + left.m02 * right.m10 + left.m12 * right.m11 + left.m22 * right.m12; + float m20 = + left.m00 * right.m20 + left.m10 * right.m21 + left.m20 * right.m22; + float m21 = + left.m01 * right.m20 + left.m11 * right.m21 + left.m21 * right.m22; + float m22 = + left.m02 * right.m20 + left.m12 * right.m21 + left.m22 * right.m22; + + dest.m00 = m00; + dest.m01 = m01; + dest.m02 = m02; + dest.m10 = m10; + dest.m11 = m11; + dest.m12 = m12; + dest.m20 = m20; + dest.m21 = m21; + dest.m22 = m22; + + return dest; + } + + /** + * Transform a Vector by a matrix and return the result in a destination + * vector. + * @param left The left matrix + * @param right The right vector + * @param dest The destination vector, or null if a new one is to be created + * @return the destination vector + */ + public static Vector3f transform(Matrix3f left, Vector3f right, Vector3f dest) { + if (dest == null) + dest = new Vector3f(); + + float x = left.m00 * right.x + left.m10 * right.y + left.m20 * right.z; + float y = left.m01 * right.x + left.m11 * right.y + left.m21 * right.z; + float z = left.m02 * right.x + left.m12 * right.y + left.m22 * right.z; + + dest.x = x; + dest.y = y; + dest.z = z; + + return dest; + } + + /** + * Transpose this matrix + * @return this + */ + public Matrix transpose() { + return transpose(this, this); + } + + /** + * Transpose this matrix and place the result in another matrix + * @param dest The destination matrix or null if a new matrix is to be created + * @return the transposed matrix + */ + public Matrix3f transpose(Matrix3f dest) { + return transpose(this, dest); + } + + /** + * Transpose the source matrix and place the result into the destination matrix + * @param src The source matrix to be transposed + * @param dest The destination matrix or null if a new matrix is to be created + * @return the transposed matrix + */ + public static Matrix3f transpose(Matrix3f src, Matrix3f dest) { + if (dest == null) + dest = new Matrix3f(); + float m00 = src.m00; + float m01 = src.m10; + float m02 = src.m20; + float m10 = src.m01; + float m11 = src.m11; + float m12 = src.m21; + float m20 = src.m02; + float m21 = src.m12; + float m22 = src.m22; + + dest.m00 = m00; + dest.m01 = m01; + dest.m02 = m02; + dest.m10 = m10; + dest.m11 = m11; + dest.m12 = m12; + dest.m20 = m20; + dest.m21 = m21; + dest.m22 = m22; + return dest; + } + + /** + * @return the determinant of the matrix + */ + public float determinant() { + float f = + m00 * (m11 * m22 - m12 * m21) + + m01 * (m12 * m20 - m10 * m22) + + m02 * (m10 * m21 - m11 * m20); + return f; + } + + /** + * Returns a string representation of this matrix + */ + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append(m00).append(' ').append(m10).append(' ').append(m20).append(' ').append('\n'); + buf.append(m01).append(' ').append(m11).append(' ').append(m21).append(' ').append('\n'); + buf.append(m02).append(' ').append(m12).append(' ').append(m22).append(' ').append('\n'); + return buf.toString(); + } + + /** + * Invert this matrix + * @return this if successful, null otherwise + */ + public Matrix invert() { + return invert(this, this); + } + + /** + * Invert the source matrix and put the result into the destination matrix + * @param src The source matrix to be inverted + * @param dest The destination matrix, or null if a new one is to be created + * @return The inverted matrix if successful, null otherwise + */ + public static Matrix3f invert(Matrix3f src, Matrix3f dest) { + float determinant = src.determinant(); + + if (determinant != 0) { + if (dest == null) + dest = new Matrix3f(); + /* do it the ordinary way + * + * inv(A) = 1/det(A) * adj(T), where adj(T) = transpose(Conjugate Matrix) + * + * m00 m01 m02 + * m10 m11 m12 + * m20 m21 m22 + */ + float determinant_inv = 1f/determinant; + + // get the conjugate matrix + float t00 = src.m11 * src.m22 - src.m12* src.m21; + float t01 = - src.m10 * src.m22 + src.m12 * src.m20; + float t02 = src.m10 * src.m21 - src.m11 * src.m20; + float t10 = - src.m01 * src.m22 + src.m02 * src.m21; + float t11 = src.m00 * src.m22 - src.m02 * src.m20; + float t12 = - src.m00 * src.m21 + src.m01 * src.m20; + float t20 = src.m01 * src.m12 - src.m02 * src.m11; + float t21 = -src.m00 * src.m12 + src.m02 * src.m10; + float t22 = src.m00 * src.m11 - src.m01 * src.m10; + + dest.m00 = t00*determinant_inv; + dest.m11 = t11*determinant_inv; + dest.m22 = t22*determinant_inv; + dest.m01 = t10*determinant_inv; + dest.m10 = t01*determinant_inv; + dest.m20 = t02*determinant_inv; + dest.m02 = t20*determinant_inv; + dest.m12 = t21*determinant_inv; + dest.m21 = t12*determinant_inv; + return dest; + } else + return null; + } + + + /** + * Negate this matrix + * @return this + */ + public Matrix negate() { + return negate(this); + } + + /** + * Negate this matrix and place the result in a destination matrix. + * @param dest The destination matrix, or null if a new matrix is to be created + * @return the negated matrix + */ + public Matrix3f negate(Matrix3f dest) { + return negate(this, dest); + } + + /** + * Negate the source matrix and place the result in the destination matrix. + * @param src The source matrix + * @param dest The destination matrix, or null if a new matrix is to be created + * @return the negated matrix + */ + public static Matrix3f negate(Matrix3f src, Matrix3f dest) { + if (dest == null) + dest = new Matrix3f(); + + dest.m00 = -src.m00; + dest.m01 = -src.m02; + dest.m02 = -src.m01; + dest.m10 = -src.m10; + dest.m11 = -src.m12; + dest.m12 = -src.m11; + dest.m20 = -src.m20; + dest.m21 = -src.m22; + dest.m22 = -src.m21; + return dest; + } + + /** + * Set this matrix to be the identity matrix. + * @return this + */ + public Matrix setIdentity() { + return setIdentity(this); + } + + /** + * Set the matrix to be the identity matrix. + * @param m The matrix to be set to the identity + * @return m + */ + public static Matrix3f setIdentity(Matrix3f m) { + m.m00 = 1.0f; + m.m01 = 0.0f; + m.m02 = 0.0f; + m.m10 = 0.0f; + m.m11 = 1.0f; + m.m12 = 0.0f; + m.m20 = 0.0f; + m.m21 = 0.0f; + m.m22 = 1.0f; + return m; + } + + /** + * Set this matrix to 0. + * @return this + */ + public Matrix setZero() { + return setZero(this); + } + + /** + * Set the matrix matrix to 0. + * @param m The matrix to be set to 0 + * @return m + */ + public static Matrix3f setZero(Matrix3f m) { + m.m00 = 0.0f; + m.m01 = 0.0f; + m.m02 = 0.0f; + m.m10 = 0.0f; + m.m11 = 0.0f; + m.m12 = 0.0f; + m.m20 = 0.0f; + m.m21 = 0.0f; + m.m22 = 0.0f; + return m; + } + + public boolean equals(Object m) { + return (m instanceof Matrix3f) && equal(this, (Matrix3f)m); + } + + public static boolean equal(Matrix3f a, Matrix3f b) { + return a.m00 == b.m00 && + a.m01 == b.m01 && + a.m02 == b.m02 && + a.m10 == b.m10 && + a.m11 == b.m11 && + a.m12 == b.m12 && + a.m20 == b.m20 && + a.m21 == b.m21 && + a.m22 == b.m22; + } +} diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Matrix4f.java b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Matrix4f.java new file mode 100644 index 0000000..d7bd730 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Matrix4f.java @@ -0,0 +1,892 @@ +/* + * Copyright (c) 2002-2008 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.lax1dude.eaglercraft.glemu.vector; + +import java.io.Serializable; +import java.nio.FloatBuffer; + +/** + * Holds a 4x4 float matrix. + * + * @author foo + */ +public class Matrix4f extends Matrix implements Serializable { + private static final long serialVersionUID = 1L; + + public float m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33; + + /** + * Construct a new matrix, initialized to the identity. + */ + public Matrix4f() { + super(); + setIdentity(); + } + + public Matrix4f(final Matrix4f src) { + super(); + load(src); + } + + /** + * Returns a string representation of this matrix + */ + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append(m00).append(' ').append(m10).append(' ').append(m20).append(' ').append(m30).append('\n'); + buf.append(m01).append(' ').append(m11).append(' ').append(m21).append(' ').append(m31).append('\n'); + buf.append(m02).append(' ').append(m12).append(' ').append(m22).append(' ').append(m32).append('\n'); + buf.append(m03).append(' ').append(m13).append(' ').append(m23).append(' ').append(m33).append('\n'); + return buf.toString(); + } + + /** + * Set this matrix to be the identity matrix. + * @return this + */ + public Matrix setIdentity() { + return setIdentity(this); + } + + /** + * Set the given matrix to be the identity matrix. + * @param m The matrix to set to the identity + * @return m + */ + public static Matrix4f setIdentity(Matrix4f m) { + m.m00 = 1.0f; + m.m01 = 0.0f; + m.m02 = 0.0f; + m.m03 = 0.0f; + m.m10 = 0.0f; + m.m11 = 1.0f; + m.m12 = 0.0f; + m.m13 = 0.0f; + m.m20 = 0.0f; + m.m21 = 0.0f; + m.m22 = 1.0f; + m.m23 = 0.0f; + m.m30 = 0.0f; + m.m31 = 0.0f; + m.m32 = 0.0f; + m.m33 = 1.0f; + + return m; + } + + /** + * Set this matrix to 0. + * @return this + */ + public Matrix setZero() { + return setZero(this); + } + + /** + * Set the given matrix to 0. + * @param m The matrix to set to 0 + * @return m + */ + public static Matrix4f setZero(Matrix4f m) { + m.m00 = 0.0f; + m.m01 = 0.0f; + m.m02 = 0.0f; + m.m03 = 0.0f; + m.m10 = 0.0f; + m.m11 = 0.0f; + m.m12 = 0.0f; + m.m13 = 0.0f; + m.m20 = 0.0f; + m.m21 = 0.0f; + m.m22 = 0.0f; + m.m23 = 0.0f; + m.m30 = 0.0f; + m.m31 = 0.0f; + m.m32 = 0.0f; + m.m33 = 0.0f; + + return m; + } + + /** + * Load from another matrix4f + * @param src The source matrix + * @return this + */ + public Matrix4f load(Matrix4f src) { + return load(src, this); + } + + /** + * Copy the source matrix to the destination matrix + * @param src The source matrix + * @param dest The destination matrix, or null of a new one is to be created + * @return The copied matrix + */ + public static Matrix4f load(Matrix4f src, Matrix4f dest) { + if (dest == null) + dest = new Matrix4f(); + dest.m00 = src.m00; + dest.m01 = src.m01; + dest.m02 = src.m02; + dest.m03 = src.m03; + dest.m10 = src.m10; + dest.m11 = src.m11; + dest.m12 = src.m12; + dest.m13 = src.m13; + dest.m20 = src.m20; + dest.m21 = src.m21; + dest.m22 = src.m22; + dest.m23 = src.m23; + dest.m30 = src.m30; + dest.m31 = src.m31; + dest.m32 = src.m32; + dest.m33 = src.m33; + + return dest; + } + + /** + * Load from a float buffer. The buffer stores the matrix in column major + * (OpenGL) order. + * + * @param buf A float buffer to read from + * @return this + */ + public Matrix load(FloatBuffer buf) { + + m00 = buf.get(); + m01 = buf.get(); + m02 = buf.get(); + m03 = buf.get(); + m10 = buf.get(); + m11 = buf.get(); + m12 = buf.get(); + m13 = buf.get(); + m20 = buf.get(); + m21 = buf.get(); + m22 = buf.get(); + m23 = buf.get(); + m30 = buf.get(); + m31 = buf.get(); + m32 = buf.get(); + m33 = buf.get(); + + return this; + } + + /** + * Load from a float buffer. The buffer stores the matrix in row major + * (maths) order. + * + * @param buf A float buffer to read from + * @return this + */ + public Matrix loadTranspose(FloatBuffer buf) { + + m00 = buf.get(); + m10 = buf.get(); + m20 = buf.get(); + m30 = buf.get(); + m01 = buf.get(); + m11 = buf.get(); + m21 = buf.get(); + m31 = buf.get(); + m02 = buf.get(); + m12 = buf.get(); + m22 = buf.get(); + m32 = buf.get(); + m03 = buf.get(); + m13 = buf.get(); + m23 = buf.get(); + m33 = buf.get(); + + return this; + } + + /** + * Store this matrix in a float buffer. The matrix is stored in column + * major (openGL) order. + * @param buf The buffer to store this matrix in + */ + public Matrix store(FloatBuffer buf) { + buf.put(m00); + buf.put(m01); + buf.put(m02); + buf.put(m03); + buf.put(m10); + buf.put(m11); + buf.put(m12); + buf.put(m13); + buf.put(m20); + buf.put(m21); + buf.put(m22); + buf.put(m23); + buf.put(m30); + buf.put(m31); + buf.put(m32); + buf.put(m33); + return this; + } + + public Matrix store(float[] buf) { + buf[0] = m00; + buf[1] = m01; + buf[2] = m02; + buf[3] = m03; + buf[4] = m10; + buf[5] = m11; + buf[6] = m12; + buf[7] = m13; + buf[8] = m20; + buf[9] = m21; + buf[10] = m22; + buf[11] = m23; + buf[12] = m30; + buf[13] = m31; + buf[14] = m32; + buf[15] = m33; + return this; + } + + /** + * Store this matrix in a float buffer. The matrix is stored in row + * major (maths) order. + * @param buf The buffer to store this matrix in + */ + public Matrix storeTranspose(FloatBuffer buf) { + buf.put(m00); + buf.put(m10); + buf.put(m20); + buf.put(m30); + buf.put(m01); + buf.put(m11); + buf.put(m21); + buf.put(m31); + buf.put(m02); + buf.put(m12); + buf.put(m22); + buf.put(m32); + buf.put(m03); + buf.put(m13); + buf.put(m23); + buf.put(m33); + return this; + } + + /** + * Store the rotation portion of this matrix in a float buffer. The matrix is stored in column + * major (openGL) order. + * @param buf The buffer to store this matrix in + */ + public Matrix store3f(FloatBuffer buf) { + buf.put(m00); + buf.put(m01); + buf.put(m02); + buf.put(m10); + buf.put(m11); + buf.put(m12); + buf.put(m20); + buf.put(m21); + buf.put(m22); + return this; + } + + /** + * Add two matrices together and place the result in a third matrix. + * @param left The left source matrix + * @param right The right source matrix + * @param dest The destination matrix, or null if a new one is to be created + * @return the destination matrix + */ + public static Matrix4f add(Matrix4f left, Matrix4f right, Matrix4f dest) { + if (dest == null) + dest = new Matrix4f(); + + dest.m00 = left.m00 + right.m00; + dest.m01 = left.m01 + right.m01; + dest.m02 = left.m02 + right.m02; + dest.m03 = left.m03 + right.m03; + dest.m10 = left.m10 + right.m10; + dest.m11 = left.m11 + right.m11; + dest.m12 = left.m12 + right.m12; + dest.m13 = left.m13 + right.m13; + dest.m20 = left.m20 + right.m20; + dest.m21 = left.m21 + right.m21; + dest.m22 = left.m22 + right.m22; + dest.m23 = left.m23 + right.m23; + dest.m30 = left.m30 + right.m30; + dest.m31 = left.m31 + right.m31; + dest.m32 = left.m32 + right.m32; + dest.m33 = left.m33 + right.m33; + + return dest; + } + + /** + * Subtract the right matrix from the left and place the result in a third matrix. + * @param left The left source matrix + * @param right The right source matrix + * @param dest The destination matrix, or null if a new one is to be created + * @return the destination matrix + */ + public static Matrix4f sub(Matrix4f left, Matrix4f right, Matrix4f dest) { + if (dest == null) + dest = new Matrix4f(); + + dest.m00 = left.m00 - right.m00; + dest.m01 = left.m01 - right.m01; + dest.m02 = left.m02 - right.m02; + dest.m03 = left.m03 - right.m03; + dest.m10 = left.m10 - right.m10; + dest.m11 = left.m11 - right.m11; + dest.m12 = left.m12 - right.m12; + dest.m13 = left.m13 - right.m13; + dest.m20 = left.m20 - right.m20; + dest.m21 = left.m21 - right.m21; + dest.m22 = left.m22 - right.m22; + dest.m23 = left.m23 - right.m23; + dest.m30 = left.m30 - right.m30; + dest.m31 = left.m31 - right.m31; + dest.m32 = left.m32 - right.m32; + dest.m33 = left.m33 - right.m33; + + return dest; + } + + /** + * Multiply the right matrix by the left and place the result in a third matrix. + * @param left The left source matrix + * @param right The right source matrix + * @param dest The destination matrix, or null if a new one is to be created + * @return the destination matrix + */ + public static Matrix4f mul(Matrix4f left, Matrix4f right, Matrix4f dest) { + if (dest == null) + dest = new Matrix4f(); + + float m00 = left.m00 * right.m00 + left.m10 * right.m01 + left.m20 * right.m02 + left.m30 * right.m03; + float m01 = left.m01 * right.m00 + left.m11 * right.m01 + left.m21 * right.m02 + left.m31 * right.m03; + float m02 = left.m02 * right.m00 + left.m12 * right.m01 + left.m22 * right.m02 + left.m32 * right.m03; + float m03 = left.m03 * right.m00 + left.m13 * right.m01 + left.m23 * right.m02 + left.m33 * right.m03; + float m10 = left.m00 * right.m10 + left.m10 * right.m11 + left.m20 * right.m12 + left.m30 * right.m13; + float m11 = left.m01 * right.m10 + left.m11 * right.m11 + left.m21 * right.m12 + left.m31 * right.m13; + float m12 = left.m02 * right.m10 + left.m12 * right.m11 + left.m22 * right.m12 + left.m32 * right.m13; + float m13 = left.m03 * right.m10 + left.m13 * right.m11 + left.m23 * right.m12 + left.m33 * right.m13; + float m20 = left.m00 * right.m20 + left.m10 * right.m21 + left.m20 * right.m22 + left.m30 * right.m23; + float m21 = left.m01 * right.m20 + left.m11 * right.m21 + left.m21 * right.m22 + left.m31 * right.m23; + float m22 = left.m02 * right.m20 + left.m12 * right.m21 + left.m22 * right.m22 + left.m32 * right.m23; + float m23 = left.m03 * right.m20 + left.m13 * right.m21 + left.m23 * right.m22 + left.m33 * right.m23; + float m30 = left.m00 * right.m30 + left.m10 * right.m31 + left.m20 * right.m32 + left.m30 * right.m33; + float m31 = left.m01 * right.m30 + left.m11 * right.m31 + left.m21 * right.m32 + left.m31 * right.m33; + float m32 = left.m02 * right.m30 + left.m12 * right.m31 + left.m22 * right.m32 + left.m32 * right.m33; + float m33 = left.m03 * right.m30 + left.m13 * right.m31 + left.m23 * right.m32 + left.m33 * right.m33; + + dest.m00 = m00; + dest.m01 = m01; + dest.m02 = m02; + dest.m03 = m03; + dest.m10 = m10; + dest.m11 = m11; + dest.m12 = m12; + dest.m13 = m13; + dest.m20 = m20; + dest.m21 = m21; + dest.m22 = m22; + dest.m23 = m23; + dest.m30 = m30; + dest.m31 = m31; + dest.m32 = m32; + dest.m33 = m33; + + return dest; + } + + /** + * Transform a Vector by a matrix and return the result in a destination + * vector. + * @param left The left matrix + * @param right The right vector + * @param dest The destination vector, or null if a new one is to be created + * @return the destination vector + */ + public static Vector4f transform(Matrix4f left, Vector4f right, Vector4f dest) { + if (dest == null) + dest = new Vector4f(); + + float x = left.m00 * right.x + left.m10 * right.y + left.m20 * right.z + left.m30 * right.w; + float y = left.m01 * right.x + left.m11 * right.y + left.m21 * right.z + left.m31 * right.w; + float z = left.m02 * right.x + left.m12 * right.y + left.m22 * right.z + left.m32 * right.w; + float w = left.m03 * right.x + left.m13 * right.y + left.m23 * right.z + left.m33 * right.w; + + dest.x = x; + dest.y = y; + dest.z = z; + dest.w = w; + + return dest; + } + + /** + * Transpose this matrix + * @return this + */ + public Matrix transpose() { + return transpose(this); + } + + /** + * Translate this matrix + * @param vec The vector to translate by + * @return this + */ + public Matrix4f translate(Vector2f vec) { + return translate(vec, this); + } + + /** + * Translate this matrix + * @param vec The vector to translate by + * @return this + */ + public Matrix4f translate(Vector3f vec) { + return translate(vec, this); + } + + /** + * Scales this matrix + * @param vec The vector to scale by + * @return this + */ + public Matrix4f scale(Vector3f vec) { + return scale(vec, this, this); + } + + /** + * Scales the source matrix and put the result in the destination matrix + * @param vec The vector to scale by + * @param src The source matrix + * @param dest The destination matrix, or null if a new matrix is to be created + * @return The scaled matrix + */ + public static Matrix4f scale(Vector3f vec, Matrix4f src, Matrix4f dest) { + if (dest == null) + dest = new Matrix4f(); + dest.m00 = src.m00 * vec.x; + dest.m01 = src.m01 * vec.x; + dest.m02 = src.m02 * vec.x; + dest.m03 = src.m03 * vec.x; + dest.m10 = src.m10 * vec.y; + dest.m11 = src.m11 * vec.y; + dest.m12 = src.m12 * vec.y; + dest.m13 = src.m13 * vec.y; + dest.m20 = src.m20 * vec.z; + dest.m21 = src.m21 * vec.z; + dest.m22 = src.m22 * vec.z; + dest.m23 = src.m23 * vec.z; + return dest; + } + + /** + * Rotates the matrix around the given axis the specified angle + * @param angle the angle, in radians. + * @param axis The vector representing the rotation axis. Must be normalized. + * @return this + */ + public Matrix4f rotate(float angle, Vector3f axis) { + return rotate(angle, axis, this); + } + + /** + * Rotates the matrix around the given axis the specified angle + * @param angle the angle, in radians. + * @param axis The vector representing the rotation axis. Must be normalized. + * @param dest The matrix to put the result, or null if a new matrix is to be created + * @return The rotated matrix + */ + public Matrix4f rotate(float angle, Vector3f axis, Matrix4f dest) { + return rotate(angle, axis, this, dest); + } + + /** + * Rotates the source matrix around the given axis the specified angle and + * put the result in the destination matrix. + * @param angle the angle, in radians. + * @param axis The vector representing the rotation axis. Must be normalized. + * @param src The matrix to rotate + * @param dest The matrix to put the result, or null if a new matrix is to be created + * @return The rotated matrix + */ + public static Matrix4f rotate(float angle, Vector3f axis, Matrix4f src, Matrix4f dest) { + if (dest == null) + dest = new Matrix4f(); + float c = (float) Math.cos(angle); + float s = (float) Math.sin(angle); + float oneminusc = 1.0f - c; + float xy = axis.x*axis.y; + float yz = axis.y*axis.z; + float xz = axis.x*axis.z; + float xs = axis.x*s; + float ys = axis.y*s; + float zs = axis.z*s; + + float f00 = axis.x*axis.x*oneminusc+c; + float f01 = xy*oneminusc+zs; + float f02 = xz*oneminusc-ys; + // n[3] not used + float f10 = xy*oneminusc-zs; + float f11 = axis.y*axis.y*oneminusc+c; + float f12 = yz*oneminusc+xs; + // n[7] not used + float f20 = xz*oneminusc+ys; + float f21 = yz*oneminusc-xs; + float f22 = axis.z*axis.z*oneminusc+c; + + float t00 = src.m00 * f00 + src.m10 * f01 + src.m20 * f02; + float t01 = src.m01 * f00 + src.m11 * f01 + src.m21 * f02; + float t02 = src.m02 * f00 + src.m12 * f01 + src.m22 * f02; + float t03 = src.m03 * f00 + src.m13 * f01 + src.m23 * f02; + float t10 = src.m00 * f10 + src.m10 * f11 + src.m20 * f12; + float t11 = src.m01 * f10 + src.m11 * f11 + src.m21 * f12; + float t12 = src.m02 * f10 + src.m12 * f11 + src.m22 * f12; + float t13 = src.m03 * f10 + src.m13 * f11 + src.m23 * f12; + dest.m20 = src.m00 * f20 + src.m10 * f21 + src.m20 * f22; + dest.m21 = src.m01 * f20 + src.m11 * f21 + src.m21 * f22; + dest.m22 = src.m02 * f20 + src.m12 * f21 + src.m22 * f22; + dest.m23 = src.m03 * f20 + src.m13 * f21 + src.m23 * f22; + dest.m00 = t00; + dest.m01 = t01; + dest.m02 = t02; + dest.m03 = t03; + dest.m10 = t10; + dest.m11 = t11; + dest.m12 = t12; + dest.m13 = t13; + return dest; + } + + /** + * Translate this matrix and stash the result in another matrix + * @param vec The vector to translate by + * @param dest The destination matrix or null if a new matrix is to be created + * @return the translated matrix + */ + public Matrix4f translate(Vector3f vec, Matrix4f dest) { + return translate(vec, this, dest); + } + + /** + * Translate the source matrix and stash the result in the destination matrix + * @param vec The vector to translate by + * @param src The source matrix + * @param dest The destination matrix or null if a new matrix is to be created + * @return The translated matrix + */ + public static Matrix4f translate(Vector3f vec, Matrix4f src, Matrix4f dest) { + if (dest == null) + dest = new Matrix4f(); + + dest.m30 += src.m00 * vec.x + src.m10 * vec.y + src.m20 * vec.z; + dest.m31 += src.m01 * vec.x + src.m11 * vec.y + src.m21 * vec.z; + dest.m32 += src.m02 * vec.x + src.m12 * vec.y + src.m22 * vec.z; + dest.m33 += src.m03 * vec.x + src.m13 * vec.y + src.m23 * vec.z; + + return dest; + } + + /** + * Translate this matrix and stash the result in another matrix + * @param vec The vector to translate by + * @param dest The destination matrix or null if a new matrix is to be created + * @return the translated matrix + */ + public Matrix4f translate(Vector2f vec, Matrix4f dest) { + return translate(vec, this, dest); + } + + /** + * Translate the source matrix and stash the result in the destination matrix + * @param vec The vector to translate by + * @param src The source matrix + * @param dest The destination matrix or null if a new matrix is to be created + * @return The translated matrix + */ + public static Matrix4f translate(Vector2f vec, Matrix4f src, Matrix4f dest) { + if (dest == null) + dest = new Matrix4f(); + + dest.m30 += src.m00 * vec.x + src.m10 * vec.y; + dest.m31 += src.m01 * vec.x + src.m11 * vec.y; + dest.m32 += src.m02 * vec.x + src.m12 * vec.y; + dest.m33 += src.m03 * vec.x + src.m13 * vec.y; + + return dest; + } + + /** + * Transpose this matrix and place the result in another matrix + * @param dest The destination matrix or null if a new matrix is to be created + * @return the transposed matrix + */ + public Matrix4f transpose(Matrix4f dest) { + return transpose(this, dest); + } + + /** + * Transpose the source matrix and place the result in the destination matrix + * @param src The source matrix + * @param dest The destination matrix or null if a new matrix is to be created + * @return the transposed matrix + */ + public static Matrix4f transpose(Matrix4f src, Matrix4f dest) { + if (dest == null) + dest = new Matrix4f(); + float m00 = src.m00; + float m01 = src.m10; + float m02 = src.m20; + float m03 = src.m30; + float m10 = src.m01; + float m11 = src.m11; + float m12 = src.m21; + float m13 = src.m31; + float m20 = src.m02; + float m21 = src.m12; + float m22 = src.m22; + float m23 = src.m32; + float m30 = src.m03; + float m31 = src.m13; + float m32 = src.m23; + float m33 = src.m33; + + dest.m00 = m00; + dest.m01 = m01; + dest.m02 = m02; + dest.m03 = m03; + dest.m10 = m10; + dest.m11 = m11; + dest.m12 = m12; + dest.m13 = m13; + dest.m20 = m20; + dest.m21 = m21; + dest.m22 = m22; + dest.m23 = m23; + dest.m30 = m30; + dest.m31 = m31; + dest.m32 = m32; + dest.m33 = m33; + + return dest; + } + + /** + * @return the determinant of the matrix + */ + public float determinant() { + float f = + m00 + * ((m11 * m22 * m33 + m12 * m23 * m31 + m13 * m21 * m32) + - m13 * m22 * m31 + - m11 * m23 * m32 + - m12 * m21 * m33); + f -= m01 + * ((m10 * m22 * m33 + m12 * m23 * m30 + m13 * m20 * m32) + - m13 * m22 * m30 + - m10 * m23 * m32 + - m12 * m20 * m33); + f += m02 + * ((m10 * m21 * m33 + m11 * m23 * m30 + m13 * m20 * m31) + - m13 * m21 * m30 + - m10 * m23 * m31 + - m11 * m20 * m33); + f -= m03 + * ((m10 * m21 * m32 + m11 * m22 * m30 + m12 * m20 * m31) + - m12 * m21 * m30 + - m10 * m22 * m31 + - m11 * m20 * m32); + return f; + } + + /** + * Calculate the determinant of a 3x3 matrix + * @return result + */ + + private static float determinant3x3(float t00, float t01, float t02, + float t10, float t11, float t12, + float t20, float t21, float t22) + { + return t00 * (t11 * t22 - t12 * t21) + + t01 * (t12 * t20 - t10 * t22) + + t02 * (t10 * t21 - t11 * t20); + } + + /** + * Invert this matrix + * @return this if successful, null otherwise + */ + public Matrix invert() { + return invert(this, this); + } + + /** + * Invert the source matrix and put the result in the destination + * @param src The source matrix + * @param dest The destination matrix, or null if a new matrix is to be created + * @return The inverted matrix if successful, null otherwise + */ + public static Matrix4f invert(Matrix4f src, Matrix4f dest) { + float determinant = src.determinant(); + + if (determinant != 0) { + /* + * m00 m01 m02 m03 + * m10 m11 m12 m13 + * m20 m21 m22 m23 + * m30 m31 m32 m33 + */ + if (dest == null) + dest = new Matrix4f(); + float determinant_inv = 1f/determinant; + + // first row + float t00 = determinant3x3(src.m11, src.m12, src.m13, src.m21, src.m22, src.m23, src.m31, src.m32, src.m33); + float t01 = -determinant3x3(src.m10, src.m12, src.m13, src.m20, src.m22, src.m23, src.m30, src.m32, src.m33); + float t02 = determinant3x3(src.m10, src.m11, src.m13, src.m20, src.m21, src.m23, src.m30, src.m31, src.m33); + float t03 = -determinant3x3(src.m10, src.m11, src.m12, src.m20, src.m21, src.m22, src.m30, src.m31, src.m32); + // second row + float t10 = -determinant3x3(src.m01, src.m02, src.m03, src.m21, src.m22, src.m23, src.m31, src.m32, src.m33); + float t11 = determinant3x3(src.m00, src.m02, src.m03, src.m20, src.m22, src.m23, src.m30, src.m32, src.m33); + float t12 = -determinant3x3(src.m00, src.m01, src.m03, src.m20, src.m21, src.m23, src.m30, src.m31, src.m33); + float t13 = determinant3x3(src.m00, src.m01, src.m02, src.m20, src.m21, src.m22, src.m30, src.m31, src.m32); + // third row + float t20 = determinant3x3(src.m01, src.m02, src.m03, src.m11, src.m12, src.m13, src.m31, src.m32, src.m33); + float t21 = -determinant3x3(src.m00, src.m02, src.m03, src.m10, src.m12, src.m13, src.m30, src.m32, src.m33); + float t22 = determinant3x3(src.m00, src.m01, src.m03, src.m10, src.m11, src.m13, src.m30, src.m31, src.m33); + float t23 = -determinant3x3(src.m00, src.m01, src.m02, src.m10, src.m11, src.m12, src.m30, src.m31, src.m32); + // fourth row + float t30 = -determinant3x3(src.m01, src.m02, src.m03, src.m11, src.m12, src.m13, src.m21, src.m22, src.m23); + float t31 = determinant3x3(src.m00, src.m02, src.m03, src.m10, src.m12, src.m13, src.m20, src.m22, src.m23); + float t32 = -determinant3x3(src.m00, src.m01, src.m03, src.m10, src.m11, src.m13, src.m20, src.m21, src.m23); + float t33 = determinant3x3(src.m00, src.m01, src.m02, src.m10, src.m11, src.m12, src.m20, src.m21, src.m22); + + // transpose and divide by the determinant + dest.m00 = t00*determinant_inv; + dest.m11 = t11*determinant_inv; + dest.m22 = t22*determinant_inv; + dest.m33 = t33*determinant_inv; + dest.m01 = t10*determinant_inv; + dest.m10 = t01*determinant_inv; + dest.m20 = t02*determinant_inv; + dest.m02 = t20*determinant_inv; + dest.m12 = t21*determinant_inv; + dest.m21 = t12*determinant_inv; + dest.m03 = t30*determinant_inv; + dest.m30 = t03*determinant_inv; + dest.m13 = t31*determinant_inv; + dest.m31 = t13*determinant_inv; + dest.m32 = t23*determinant_inv; + dest.m23 = t32*determinant_inv; + return dest; + } else + return null; + } + + /** + * Negate this matrix + * @return this + */ + public Matrix negate() { + return negate(this); + } + + /** + * Negate this matrix and place the result in a destination matrix. + * @param dest The destination matrix, or null if a new matrix is to be created + * @return the negated matrix + */ + public Matrix4f negate(Matrix4f dest) { + return negate(this, dest); + } + + /** + * Negate this matrix and place the result in a destination matrix. + * @param src The source matrix + * @param dest The destination matrix, or null if a new matrix is to be created + * @return The negated matrix + */ + public static Matrix4f negate(Matrix4f src, Matrix4f dest) { + if (dest == null) + dest = new Matrix4f(); + + dest.m00 = -src.m00; + dest.m01 = -src.m01; + dest.m02 = -src.m02; + dest.m03 = -src.m03; + dest.m10 = -src.m10; + dest.m11 = -src.m11; + dest.m12 = -src.m12; + dest.m13 = -src.m13; + dest.m20 = -src.m20; + dest.m21 = -src.m21; + dest.m22 = -src.m22; + dest.m23 = -src.m23; + dest.m30 = -src.m30; + dest.m31 = -src.m31; + dest.m32 = -src.m32; + dest.m33 = -src.m33; + + return dest; + } + + public boolean equals(Object m) { + return (m instanceof Matrix4f) && equal(this, (Matrix4f)m); + } + + public static boolean equal(Matrix4f a, Matrix4f b) { + return a.m00 == b.m00 && + a.m01 == b.m01 && + a.m02 == b.m02 && + a.m03 == b.m03 && + a.m10 == b.m10 && + a.m11 == b.m11 && + a.m12 == b.m12 && + a.m13 == b.m13 && + a.m20 == b.m20 && + a.m21 == b.m21 && + a.m22 == b.m22 && + a.m23 == b.m23 && + a.m30 == b.m30 && + a.m31 == b.m31 && + a.m32 == b.m32 && + a.m33 == b.m33; + } +} diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Quaternion.java b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Quaternion.java new file mode 100644 index 0000000..9a592d2 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Quaternion.java @@ -0,0 +1,530 @@ +/* + * Copyright (c) 2002-2008 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.lax1dude.eaglercraft.glemu.vector; + +/** + * + * Quaternions for LWJGL! + * + * @author fbi + * @version $Revision$ + * $Id$ + */ + +import java.nio.FloatBuffer; + +public class Quaternion extends Vector implements ReadableVector4f { + private static final long serialVersionUID = 1L; + + public float x, y, z, w; + + /** + * C'tor. The quaternion will be initialized to the identity. + */ + public Quaternion() { + super(); + setIdentity(); + } + + /** + * C'tor + * + * @param src + */ + public Quaternion(ReadableVector4f src) { + set(src); + } + + /** + * C'tor + * + */ + public Quaternion(float x, float y, float z, float w) { + set(x, y, z, w); + } + + /* + * (non-Javadoc) + * + * @see org.lwjgl.util.vector.WritableVector2f#set(float, float) + */ + public void set(float x, float y) { + this.x = x; + this.y = y; + } + + /* + * (non-Javadoc) + * + * @see org.lwjgl.util.vector.WritableVector3f#set(float, float, float) + */ + public void set(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + } + + /* + * (non-Javadoc) + * + * @see org.lwjgl.util.vector.WritableVector4f#set(float, float, float, + * float) + */ + public void set(float x, float y, float z, float w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + /** + * Load from another Vector4f + * + * @param src + * The source vector + * @return this + */ + public Quaternion set(ReadableVector4f src) { + x = src.getX(); + y = src.getY(); + z = src.getZ(); + w = src.getW(); + return this; + } + + /** + * Set this quaternion to the multiplication identity. + * @return this + */ + public Quaternion setIdentity() { + return setIdentity(this); + } + + /** + * Set the given quaternion to the multiplication identity. + * @param q The quaternion + * @return q + */ + public static Quaternion setIdentity(Quaternion q) { + q.x = 0; + q.y = 0; + q.z = 0; + q.w = 1; + return q; + } + + /** + * @return the length squared of the quaternion + */ + public float lengthSquared() { + return x * x + y * y + z * z + w * w; + } + + /** + * Normalise the source quaternion and place the result in another quaternion. + * + * @param src + * The source quaternion + * @param dest + * The destination quaternion, or null if a new quaternion is to be + * created + * @return The normalised quaternion + */ + public static Quaternion normalise(Quaternion src, Quaternion dest) { + float inv_l = 1f/src.length(); + + if (dest == null) + dest = new Quaternion(); + + dest.set(src.x * inv_l, src.y * inv_l, src.z * inv_l, src.w * inv_l); + + return dest; + } + + /** + * Normalise this quaternion and place the result in another quaternion. + * + * @param dest + * The destination quaternion, or null if a new quaternion is to be + * created + * @return the normalised quaternion + */ + public Quaternion normalise(Quaternion dest) { + return normalise(this, dest); + } + + /** + * The dot product of two quaternions + * + * @param left + * The LHS quat + * @param right + * The RHS quat + * @return left dot right + */ + public static float dot(Quaternion left, Quaternion right) { + return left.x * right.x + left.y * right.y + left.z * right.z + left.w + * right.w; + } + + /** + * Calculate the conjugate of this quaternion and put it into the given one + * + * @param dest + * The quaternion which should be set to the conjugate of this + * quaternion + */ + public Quaternion negate(Quaternion dest) { + return negate(this, dest); + } + + /** + * Calculate the conjugate of this quaternion and put it into the given one + * + * @param src + * The source quaternion + * @param dest + * The quaternion which should be set to the conjugate of this + * quaternion + */ + public static Quaternion negate(Quaternion src, Quaternion dest) { + if (dest == null) + dest = new Quaternion(); + + dest.x = -src.x; + dest.y = -src.y; + dest.z = -src.z; + dest.w = src.w; + + return dest; + } + + /** + * Calculate the conjugate of this quaternion + */ + public Vector negate() { + return negate(this, this); + } + + /* (non-Javadoc) + * @see org.lwjgl.util.vector.Vector#load(java.nio.FloatBuffer) + */ + public Vector load(FloatBuffer buf) { + x = buf.get(); + y = buf.get(); + z = buf.get(); + w = buf.get(); + return this; + } + + /* + * (non-Javadoc) + * + * @see org.lwjgl.vector.Vector#scale(float) + */ + public Vector scale(float scale) { + return scale(scale, this, this); + } + + /** + * Scale the source quaternion by scale and put the result in the destination + * @param scale The amount to scale by + * @param src The source quaternion + * @param dest The destination quaternion, or null if a new quaternion is to be created + * @return The scaled quaternion + */ + public static Quaternion scale(float scale, Quaternion src, Quaternion dest) { + if (dest == null) + dest = new Quaternion(); + dest.x = src.x * scale; + dest.y = src.y * scale; + dest.z = src.z * scale; + dest.w = src.w * scale; + return dest; + } + + /* (non-Javadoc) + * @see org.lwjgl.util.vector.ReadableVector#store(java.nio.FloatBuffer) + */ + public Vector store(FloatBuffer buf) { + buf.put(x); + buf.put(y); + buf.put(z); + buf.put(w); + + return this; + } + + /** + * @return x + */ + public final float getX() { + return x; + } + + /** + * @return y + */ + public final float getY() { + return y; + } + + /** + * Set X + * + * @param x + */ + public final void setX(float x) { + this.x = x; + } + + /** + * Set Y + * + * @param y + */ + public final void setY(float y) { + this.y = y; + } + + /** + * Set Z + * + * @param z + */ + public void setZ(float z) { + this.z = z; + } + + /* + * (Overrides) + * + * @see org.lwjgl.vector.ReadableVector3f#getZ() + */ + public float getZ() { + return z; + } + + /** + * Set W + * + * @param w + */ + public void setW(float w) { + this.w = w; + } + + /* + * (Overrides) + * + * @see org.lwjgl.vector.ReadableVector3f#getW() + */ + public float getW() { + return w; + } + + public String toString() { + return "Quaternion: " + x + " " + y + " " + z + " " + w; + } + + /** + * Sets the value of this quaternion to the quaternion product of + * quaternions left and right (this = left * right). Note that this is safe + * for aliasing (e.g. this can be left or right). + * + * @param left + * the first quaternion + * @param right + * the second quaternion + */ + public static Quaternion mul(Quaternion left, Quaternion right, + Quaternion dest) { + if (dest == null) + dest = new Quaternion(); + dest.set(left.x * right.w + left.w * right.x + left.y * right.z + - left.z * right.y, left.y * right.w + left.w * right.y + + left.z * right.x - left.x * right.z, left.z * right.w + + left.w * right.z + left.x * right.y - left.y * right.x, + left.w * right.w - left.x * right.x - left.y * right.y + - left.z * right.z); + return dest; + } + + /** + * + * Multiplies quaternion left by the inverse of quaternion right and places + * the value into this quaternion. The value of both argument quaternions is + * preservered (this = left * right^-1). + * + * @param left + * the left quaternion + * @param right + * the right quaternion + */ + public static Quaternion mulInverse(Quaternion left, Quaternion right, + Quaternion dest) { + float n = right.lengthSquared(); + // zero-div may occur. + n = (n == 0.0 ? n : 1 / n); + // store on stack once for aliasing-safty + if (dest == null) + dest = new Quaternion(); + dest + .set((left.x * right.w - left.w * right.x - left.y + * right.z + left.z * right.y) + * n, (left.y * right.w - left.w * right.y - left.z + * right.x + left.x * right.z) + * n, (left.z * right.w - left.w * right.z - left.x + * right.y + left.y * right.x) + * n, (left.w * right.w + left.x * right.x + left.y + * right.y + left.z * right.z) + * n); + + return dest; + } + + /** + * Sets the value of this quaternion to the equivalent rotation of the + * Axis-Angle argument. + * + * @param a1 + * the axis-angle: (x,y,z) is the axis and w is the angle + */ + public final void setFromAxisAngle(Vector4f a1) { + x = a1.x; + y = a1.y; + z = a1.z; + float n = (float) Math.sqrt(x * x + y * y + z * z); + // zero-div may occur. + float s = (float) (Math.sin(0.5 * a1.w) / n); + x *= s; + y *= s; + z *= s; + w = (float) Math.cos(0.5 * a1.w); + } + + /** + * Sets the value of this quaternion using the rotational component of the + * passed matrix. + * + * @param m + * The matrix + * @return this + */ + public final Quaternion setFromMatrix(Matrix4f m) { + return setFromMatrix(m, this); + } + + /** + * Sets the value of the source quaternion using the rotational component of the + * passed matrix. + * + * @param m + * The source matrix + * @param q + * The destination quaternion, or null if a new quaternion is to be created + * @return q + */ + public static Quaternion setFromMatrix(Matrix4f m, Quaternion q) { + return q.setFromMat(m.m00, m.m01, m.m02, m.m10, m.m11, m.m12, m.m20, + m.m21, m.m22); + } + + /** + * Sets the value of this quaternion using the rotational component of the + * passed matrix. + * + * @param m + * The source matrix + */ + public final Quaternion setFromMatrix(Matrix3f m) { + return setFromMatrix(m, this); + } + + /** + * Sets the value of the source quaternion using the rotational component of the + * passed matrix. + * + * @param m + * The source matrix + * @param q + * The destination quaternion, or null if a new quaternion is to be created + * @return q + */ + public static Quaternion setFromMatrix(Matrix3f m, Quaternion q) { + return q.setFromMat(m.m00, m.m01, m.m02, m.m10, m.m11, m.m12, m.m20, + m.m21, m.m22); + } + + /** + * Private method to perform the matrix-to-quaternion conversion + */ + private Quaternion setFromMat(float m00, float m01, float m02, float m10, + float m11, float m12, float m20, float m21, float m22) { + + float s; + float tr = m00 + m11 + m22; + if (tr >= 0.0) { + s = (float) Math.sqrt(tr + 1.0); + w = s * 0.5f; + s = 0.5f / s; + x = (m21 - m12) * s; + y = (m02 - m20) * s; + z = (m10 - m01) * s; + } else { + float max = Math.max(Math.max(m00, m11), m22); + if (max == m00) { + s = (float) Math.sqrt(m00 - (m11 + m22) + 1.0); + x = s * 0.5f; + s = 0.5f / s; + y = (m01 + m10) * s; + z = (m20 + m02) * s; + w = (m21 - m12) * s; + } else if (max == m11) { + s = (float) Math.sqrt(m11 - (m22 + m00) + 1.0); + y = s * 0.5f; + s = 0.5f / s; + z = (m12 + m21) * s; + x = (m01 + m10) * s; + w = (m02 - m20) * s; + } else { + s = (float) Math.sqrt(m22 - (m00 + m11) + 1.0); + z = s * 0.5f; + s = 0.5f / s; + x = (m20 + m02) * s; + y = (m12 + m21) * s; + w = (m10 - m01) * s; + } + } + return this; + } +} diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/vector/ReadableVector.java b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/ReadableVector.java new file mode 100644 index 0000000..6ae8f63 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/ReadableVector.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2002-2008 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.lax1dude.eaglercraft.glemu.vector; + +import java.nio.FloatBuffer; + +/** + * @author foo + */ +public interface ReadableVector { + /** + * @return the length of the vector + */ + float length(); + /** + * @return the length squared of the vector + */ + float lengthSquared(); + /** + * Store this vector in a FloatBuffer + * @param buf The buffer to store it in, at the current position + * @return this + */ + Vector store(FloatBuffer buf); +} \ No newline at end of file diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/vector/ReadableVector2f.java b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/ReadableVector2f.java new file mode 100644 index 0000000..1d0eb4f --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/ReadableVector2f.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2002-2008 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.lax1dude.eaglercraft.glemu.vector; + +/** + * @author foo + */ +public interface ReadableVector2f extends ReadableVector { + /** + * @return x + */ + float getX(); + /** + * @return y + */ + float getY(); +} \ No newline at end of file diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/vector/ReadableVector3f.java b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/ReadableVector3f.java new file mode 100644 index 0000000..216e1dc --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/ReadableVector3f.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2002-2008 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.lax1dude.eaglercraft.glemu.vector; + +/** + * @author foo + */ +public interface ReadableVector3f extends ReadableVector2f { + /** + * @return z + */ + float getZ(); +} \ No newline at end of file diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/vector/ReadableVector4f.java b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/ReadableVector4f.java new file mode 100644 index 0000000..81ca284 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/ReadableVector4f.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2002-2008 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.lax1dude.eaglercraft.glemu.vector; + +/** + * @author foo + */ +public interface ReadableVector4f extends ReadableVector3f { + + /** + * @return w + */ + float getW(); + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Vector.java b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Vector.java new file mode 100644 index 0000000..6d226e6 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Vector.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2002-2008 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.lax1dude.eaglercraft.glemu.vector; + +import java.io.Serializable; +import java.nio.FloatBuffer; + +/** + * + * Base class for vectors. + * + * @author cix_foo + * @version $Revision$ + * $Id$ + */ +public abstract class Vector implements Serializable, ReadableVector { + + /** + * Constructor for Vector. + */ + protected Vector() { + super(); + } + + /** + * @return the length of the vector + */ + public final float length() { + return (float) Math.sqrt(lengthSquared()); + } + + + /** + * @return the length squared of the vector + */ + public abstract float lengthSquared(); + + /** + * Load this vector from a FloatBuffer + * @param buf The buffer to load it from, at the current position + * @return this + */ + public abstract Vector load(FloatBuffer buf); + + /** + * Negate a vector + * @return this + */ + public abstract Vector negate(); + + + /** + * Normalise this vector + * @return this + */ + public final Vector normalise() { + float len = length(); + if (len != 0.0f) { + float l = 1.0f / len; + return scale(l); + } else + throw new IllegalStateException("Zero length vector"); + } + + + /** + * Store this vector in a FloatBuffer + * @param buf The buffer to store it in, at the current position + * @return this + */ + public abstract Vector store(FloatBuffer buf); + + + /** + * Scale this vector + * @param scale The scale factor + * @return this + */ + public abstract Vector scale(float scale); + + + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Vector2f.java b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Vector2f.java new file mode 100644 index 0000000..6b77ceb --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Vector2f.java @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2002-2008 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.lax1dude.eaglercraft.glemu.vector; + +import java.io.Serializable; +import java.nio.FloatBuffer; + +/** + * + * Holds a 2-tuple vector. + * + * @author cix_foo + * @version $Revision$ + * $Id$ + */ + +public class Vector2f extends Vector implements Serializable, ReadableVector2f, WritableVector2f { + + private static final long serialVersionUID = 1L; + + public float x, y; + + /** + * Constructor for Vector2f. + */ + public Vector2f() { + super(); + } + + /** + * Constructor. + */ + public Vector2f(ReadableVector2f src) { + set(src); + } + + /** + * Constructor. + */ + public Vector2f(float x, float y) { + set(x, y); + } + + /* (non-Javadoc) + * @see org.lwjgl.util.vector.WritableVector2f#set(float, float) + */ + public void set(float x, float y) { + this.x = x; + this.y = y; + } + + /** + * Load from another Vector2f + * @param src The source vector + * @return this + */ + public Vector2f set(ReadableVector2f src) { + x = src.getX(); + y = src.getY(); + return this; + } + + /** + * @return the length squared of the vector + */ + public float lengthSquared() { + return x * x + y * y; + } + + /** + * Translate a vector + * @param x The translation in x + * @param y the translation in y + * @return this + */ + public Vector2f translate(float x, float y) { + this.x += x; + this.y += y; + return this; + } + + /** + * Negate a vector + * @return this + */ + public Vector negate() { + x = -x; + y = -y; + return this; + } + + /** + * Negate a vector and place the result in a destination vector. + * @param dest The destination vector or null if a new vector is to be created + * @return the negated vector + */ + public Vector2f negate(Vector2f dest) { + if (dest == null) + dest = new Vector2f(); + dest.x = -x; + dest.y = -y; + return dest; + } + + + /** + * Normalise this vector and place the result in another vector. + * @param dest The destination vector, or null if a new vector is to be created + * @return the normalised vector + */ + public Vector2f normalise(Vector2f dest) { + float l = length(); + + if (dest == null) + dest = new Vector2f(x / l, y / l); + else + dest.set(x / l, y / l); + + return dest; + } + + /** + * The dot product of two vectors is calculated as + * v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + * @param left The LHS vector + * @param right The RHS vector + * @return left dot right + */ + public static float dot(Vector2f left, Vector2f right) { + return left.x * right.x + left.y * right.y; + } + + + + /** + * Calculate the angle between two vectors, in radians + * @param a A vector + * @param b The other vector + * @return the angle between the two vectors, in radians + */ + public static float angle(Vector2f a, Vector2f b) { + float dls = dot(a, b) / (a.length() * b.length()); + if (dls < -1f) + dls = -1f; + else if (dls > 1.0f) + dls = 1.0f; + return (float)Math.acos(dls); + } + + /** + * Add a vector to another vector and place the result in a destination + * vector. + * @param left The LHS vector + * @param right The RHS vector + * @param dest The destination vector, or null if a new vector is to be created + * @return the sum of left and right in dest + */ + public static Vector2f add(Vector2f left, Vector2f right, Vector2f dest) { + if (dest == null) + return new Vector2f(left.x + right.x, left.y + right.y); + else { + dest.set(left.x + right.x, left.y + right.y); + return dest; + } + } + + /** + * Subtract a vector from another vector and place the result in a destination + * vector. + * @param left The LHS vector + * @param right The RHS vector + * @param dest The destination vector, or null if a new vector is to be created + * @return left minus right in dest + */ + public static Vector2f sub(Vector2f left, Vector2f right, Vector2f dest) { + if (dest == null) + return new Vector2f(left.x - right.x, left.y - right.y); + else { + dest.set(left.x - right.x, left.y - right.y); + return dest; + } + } + + /** + * Store this vector in a FloatBuffer + * @param buf The buffer to store it in, at the current position + * @return this + */ + public Vector store(FloatBuffer buf) { + buf.put(x); + buf.put(y); + return this; + } + + /** + * Load this vector from a FloatBuffer + * @param buf The buffer to load it from, at the current position + * @return this + */ + public Vector load(FloatBuffer buf) { + x = buf.get(); + y = buf.get(); + return this; + } + + /* (non-Javadoc) + * @see org.lwjgl.vector.Vector#scale(float) + */ + public Vector scale(float scale) { + + x *= scale; + y *= scale; + + return this; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + StringBuilder sb = new StringBuilder(64); + + sb.append("Vector2f["); + sb.append(x); + sb.append(", "); + sb.append(y); + sb.append(']'); + return sb.toString(); + } + + /** + * @return x + */ + public final float getX() { + return x; + } + + /** + * @return y + */ + public final float getY() { + return y; + } + + /** + * Set X + * @param x + */ + public final void setX(float x) { + this.x = x; + } + + /** + * Set Y + * @param y + */ + public final void setY(float y) { + this.y = y; + } + + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + Vector2f other = (Vector2f)obj; + + if (x == other.x && y == other.y) return true; + + return false; + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Vector3f.java b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Vector3f.java new file mode 100644 index 0000000..b56617f --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Vector3f.java @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2002-2008 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.lax1dude.eaglercraft.glemu.vector; + +import java.io.Serializable; +import java.nio.FloatBuffer; + +/** + * + * Holds a 3-tuple vector. + * + * @author cix_foo + * @version $Revision$ + * $Id$ + */ + +public class Vector3f extends Vector implements Serializable, ReadableVector3f, WritableVector3f { + + private static final long serialVersionUID = 1L; + + public float x, y, z; + + /** + * Constructor for Vector3f. + */ + public Vector3f() { + super(); + } + + /** + * Constructor + */ + public Vector3f(ReadableVector3f src) { + set(src); + } + + /** + * Constructor + */ + public Vector3f(float x, float y, float z) { + set(x, y, z); + } + + /* (non-Javadoc) + * @see org.lwjgl.util.vector.WritableVector2f#set(float, float) + */ + public void set(float x, float y) { + this.x = x; + this.y = y; + } + + /* (non-Javadoc) + * @see org.lwjgl.util.vector.WritableVector3f#set(float, float, float) + */ + public void set(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + } + + /** + * Load from another Vector3f + * @param src The source vector + * @return this + */ + public Vector3f set(ReadableVector3f src) { + x = src.getX(); + y = src.getY(); + z = src.getZ(); + return this; + } + + /** + * @return the length squared of the vector + */ + public float lengthSquared() { + return x * x + y * y + z * z; + } + + /** + * Translate a vector + * @param x The translation in x + * @param y the translation in y + * @return this + */ + public Vector3f translate(float x, float y, float z) { + this.x += x; + this.y += y; + this.z += z; + return this; + } + + /** + * Add a vector to another vector and place the result in a destination + * vector. + * @param left The LHS vector + * @param right The RHS vector + * @param dest The destination vector, or null if a new vector is to be created + * @return the sum of left and right in dest + */ + public static Vector3f add(Vector3f left, Vector3f right, Vector3f dest) { + if (dest == null) + return new Vector3f(left.x + right.x, left.y + right.y, left.z + right.z); + else { + dest.set(left.x + right.x, left.y + right.y, left.z + right.z); + return dest; + } + } + + /** + * Subtract a vector from another vector and place the result in a destination + * vector. + * @param left The LHS vector + * @param right The RHS vector + * @param dest The destination vector, or null if a new vector is to be created + * @return left minus right in dest + */ + public static Vector3f sub(Vector3f left, Vector3f right, Vector3f dest) { + if (dest == null) + return new Vector3f(left.x - right.x, left.y - right.y, left.z - right.z); + else { + dest.set(left.x - right.x, left.y - right.y, left.z - right.z); + return dest; + } + } + + /** + * The cross product of two vectors. + * + * @param left The LHS vector + * @param right The RHS vector + * @param dest The destination result, or null if a new vector is to be created + * @return left cross right + */ + public static Vector3f cross( + Vector3f left, + Vector3f right, + Vector3f dest) + { + + if (dest == null) + dest = new Vector3f(); + + dest.set( + left.y * right.z - left.z * right.y, + right.x * left.z - right.z * left.x, + left.x * right.y - left.y * right.x + ); + + return dest; + } + + + + /** + * Negate a vector + * @return this + */ + public Vector negate() { + x = -x; + y = -y; + z = -z; + return this; + } + + /** + * Negate a vector and place the result in a destination vector. + * @param dest The destination vector or null if a new vector is to be created + * @return the negated vector + */ + public Vector3f negate(Vector3f dest) { + if (dest == null) + dest = new Vector3f(); + dest.x = -x; + dest.y = -y; + dest.z = -z; + return dest; + } + + + /** + * Normalise this vector and place the result in another vector. + * @param dest The destination vector, or null if a new vector is to be created + * @return the normalised vector + */ + public Vector3f normalise(Vector3f dest) { + float l = length(); + + if (dest == null) + dest = new Vector3f(x / l, y / l, z / l); + else + dest.set(x / l, y / l, z / l); + + return dest; + } + + /** + * The dot product of two vectors is calculated as + * v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + * @param left The LHS vector + * @param right The RHS vector + * @return left dot right + */ + public static float dot(Vector3f left, Vector3f right) { + return left.x * right.x + left.y * right.y + left.z * right.z; + } + + /** + * Calculate the angle between two vectors, in radians + * @param a A vector + * @param b The other vector + * @return the angle between the two vectors, in radians + */ + public static float angle(Vector3f a, Vector3f b) { + float dls = dot(a, b) / (a.length() * b.length()); + if (dls < -1f) + dls = -1f; + else if (dls > 1.0f) + dls = 1.0f; + return (float)Math.acos(dls); + } + + /* (non-Javadoc) + * @see org.lwjgl.vector.Vector#load(FloatBuffer) + */ + public Vector load(FloatBuffer buf) { + x = buf.get(); + y = buf.get(); + z = buf.get(); + return this; + } + + /* (non-Javadoc) + * @see org.lwjgl.vector.Vector#scale(float) + */ + public Vector scale(float scale) { + + x *= scale; + y *= scale; + z *= scale; + + return this; + + } + + /* (non-Javadoc) + * @see org.lwjgl.vector.Vector#store(FloatBuffer) + */ + public Vector store(FloatBuffer buf) { + + buf.put(x); + buf.put(y); + buf.put(z); + + return this; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + StringBuilder sb = new StringBuilder(64); + + sb.append("Vector3f["); + sb.append(x); + sb.append(", "); + sb.append(y); + sb.append(", "); + sb.append(z); + sb.append(']'); + return sb.toString(); + } + + /** + * @return x + */ + public final float getX() { + return x; + } + + /** + * @return y + */ + public final float getY() { + return y; + } + + /** + * Set X + * @param x + */ + public final void setX(float x) { + this.x = x; + } + + /** + * Set Y + * @param y + */ + public final void setY(float y) { + this.y = y; + } + + /** + * Set Z + * @param z + */ + public void setZ(float z) { + this.z = z; + } + + /* (Overrides) + * @see org.lwjgl.vector.ReadableVector3f#getZ() + */ + public float getZ() { + return z; + } + + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + Vector3f other = (Vector3f)obj; + + if (x == other.x && y == other.y && z == other.z) return true; + + return false; + } +} diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Vector4f.java b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Vector4f.java new file mode 100644 index 0000000..95b4ea2 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/Vector4f.java @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2002-2008 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.lax1dude.eaglercraft.glemu.vector; + +import java.io.Serializable; +import java.nio.FloatBuffer; + +/** + * + * Holds a 4-tuple vector. + * + * @author cix_foo + * @version $Revision$ + * $Id$ + */ + +public class Vector4f extends Vector implements Serializable, ReadableVector4f, WritableVector4f { + + private static final long serialVersionUID = 1L; + + public float x, y, z, w; + + /** + * Constructor for Vector4f. + */ + public Vector4f() { + super(); + } + + /** + * Constructor + */ + public Vector4f(ReadableVector4f src) { + set(src); + } + + /** + * Constructor + */ + public Vector4f(float x, float y, float z, float w) { + set(x, y, z, w); + } + + /* (non-Javadoc) + * @see org.lwjgl.util.vector.WritableVector2f#set(float, float) + */ + public void set(float x, float y) { + this.x = x; + this.y = y; + } + + /* (non-Javadoc) + * @see org.lwjgl.util.vector.WritableVector3f#set(float, float, float) + */ + public void set(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + } + + /* (non-Javadoc) + * @see org.lwjgl.util.vector.WritableVector4f#set(float, float, float, float) + */ + public void set(float x, float y, float z, float w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + /** + * Load from another Vector4f + * @param src The source vector + * @return this + */ + public Vector4f set(ReadableVector4f src) { + x = src.getX(); + y = src.getY(); + z = src.getZ(); + w = src.getW(); + return this; + } + + /** + * @return the length squared of the vector + */ + public float lengthSquared() { + return x * x + y * y + z * z + w * w; + } + + /** + * Translate a vector + * @param x The translation in x + * @param y the translation in y + * @return this + */ + public Vector4f translate(float x, float y, float z, float w) { + this.x += x; + this.y += y; + this.z += z; + this.w += w; + return this; + } + + /** + * Add a vector to another vector and place the result in a destination + * vector. + * @param left The LHS vector + * @param right The RHS vector + * @param dest The destination vector, or null if a new vector is to be created + * @return the sum of left and right in dest + */ + public static Vector4f add(Vector4f left, Vector4f right, Vector4f dest) { + if (dest == null) + return new Vector4f(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w); + else { + dest.set(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w); + return dest; + } + } + + /** + * Subtract a vector from another vector and place the result in a destination + * vector. + * @param left The LHS vector + * @param right The RHS vector + * @param dest The destination vector, or null if a new vector is to be created + * @return left minus right in dest + */ + public static Vector4f sub(Vector4f left, Vector4f right, Vector4f dest) { + if (dest == null) + return new Vector4f(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w); + else { + dest.set(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w); + return dest; + } + } + + + /** + * Negate a vector + * @return this + */ + public Vector negate() { + x = -x; + y = -y; + z = -z; + w = -w; + return this; + } + + /** + * Negate a vector and place the result in a destination vector. + * @param dest The destination vector or null if a new vector is to be created + * @return the negated vector + */ + public Vector4f negate(Vector4f dest) { + if (dest == null) + dest = new Vector4f(); + dest.x = -x; + dest.y = -y; + dest.z = -z; + dest.w = -w; + return dest; + } + + + /** + * Normalise this vector and place the result in another vector. + * @param dest The destination vector, or null if a new vector is to be created + * @return the normalised vector + */ + public Vector4f normalise(Vector4f dest) { + float l = length(); + + if (dest == null) + dest = new Vector4f(x / l, y / l, z / l, w / l); + else + dest.set(x / l, y / l, z / l, w / l); + + return dest; + } + + /** + * The dot product of two vectors is calculated as + * v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w + * @param left The LHS vector + * @param right The RHS vector + * @return left dot right + */ + public static float dot(Vector4f left, Vector4f right) { + return left.x * right.x + left.y * right.y + left.z * right.z + left.w * right.w; + } + + /** + * Calculate the angle between two vectors, in radians + * @param a A vector + * @param b The other vector + * @return the angle between the two vectors, in radians + */ + public static float angle(Vector4f a, Vector4f b) { + float dls = dot(a, b) / (a.length() * b.length()); + if (dls < -1f) + dls = -1f; + else if (dls > 1.0f) + dls = 1.0f; + return (float)Math.acos(dls); + } + + /* (non-Javadoc) + * @see org.lwjgl.vector.Vector#load(FloatBuffer) + */ + public Vector load(FloatBuffer buf) { + x = buf.get(); + y = buf.get(); + z = buf.get(); + w = buf.get(); + return this; + } + + /* (non-Javadoc) + * @see org.lwjgl.vector.Vector#scale(float) + */ + public Vector scale(float scale) { + x *= scale; + y *= scale; + z *= scale; + w *= scale; + return this; + } + + /* (non-Javadoc) + * @see org.lwjgl.vector.Vector#store(FloatBuffer) + */ + public Vector store(FloatBuffer buf) { + + buf.put(x); + buf.put(y); + buf.put(z); + buf.put(w); + + return this; + } + + public String toString() { + return "Vector4f: " + x + " " + y + " " + z + " " + w; + } + + /** + * @return x + */ + public final float getX() { + return x; + } + + /** + * @return y + */ + public final float getY() { + return y; + } + + /** + * Set X + * @param x + */ + public final void setX(float x) { + this.x = x; + } + + /** + * Set Y + * @param y + */ + public final void setY(float y) { + this.y = y; + } + + /** + * Set Z + * @param z + */ + public void setZ(float z) { + this.z = z; + } + + + /* (Overrides) + * @see org.lwjgl.vector.ReadableVector3f#getZ() + */ + public float getZ() { + return z; + } + + /** + * Set W + * @param w + */ + public void setW(float w) { + this.w = w; + } + + /* (Overrides) + * @see org.lwjgl.vector.ReadableVector3f#getZ() + */ + public float getW() { + return w; + } + + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + Vector4f other = (Vector4f)obj; + + if (x == other.x && y == other.y && z == other.z && w == other.w) return true; + + return false; + } +} diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/vector/WritableVector2f.java b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/WritableVector2f.java new file mode 100644 index 0000000..e4b478a --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/WritableVector2f.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2002-2008 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.lax1dude.eaglercraft.glemu.vector; + +/** + * Writable interface to Vector2fs + * @author $author$ + * @version $revision$ + * $Id$ + */ +public interface WritableVector2f { + + /** + * Set the X value + * @param x + */ + void setX(float x); + + /** + * Set the Y value + * @param y + */ + void setY(float y); + + /** + * Set the X,Y values + * @param x + * @param y + */ + void set(float x, float y); + +} \ No newline at end of file diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/vector/WritableVector3f.java b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/WritableVector3f.java new file mode 100644 index 0000000..2ed00d0 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/WritableVector3f.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2002-2008 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.lax1dude.eaglercraft.glemu.vector; + +/** + * Writable interface to Vector3fs + * @author $author$ + * @version $revision$ + * $Id$ + */ +public interface WritableVector3f extends WritableVector2f { + + /** + * Set the Z value + * @param z + */ + void setZ(float z); + + /** + * Set the X,Y,Z values + * @param x + * @param y + * @param z + */ + void set(float x, float y, float z); + +} \ No newline at end of file diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/vector/WritableVector4f.java b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/WritableVector4f.java new file mode 100644 index 0000000..7288c97 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/vector/WritableVector4f.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2002-2008 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.lax1dude.eaglercraft.glemu.vector; + +/** + * Writable interface to Vector4fs + * @author $author$ + * @version $revision$ + * $Id$ + */ +public interface WritableVector4f extends WritableVector3f { + + /** + * Set the W value + * @param w + */ + void setW(float w); + + /** + * Set the X,Y,Z,W values + * @param x + * @param y + * @param z + * @param w + */ + void set(float x, float y, float z, float w); + +} \ No newline at end of file diff --git a/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/ICEServerSet.java b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/ICEServerSet.java new file mode 100644 index 0000000..f03ab58 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/ICEServerSet.java @@ -0,0 +1,40 @@ +package net.lax1dude.eaglercraft.sp.relay.pkt; + +public class ICEServerSet { + + public static enum RelayType { + STUN, TURN; + } + + public static class RelayServer { + + public final RelayType type; + public final String address; + public final String username; + public final String password; + + protected RelayServer(RelayType type, String address, String username, String password) { + this.type = type; + this.address = address; + this.username = username; + this.password = password; + } + + protected RelayServer(RelayType type, String address) { + this.type = type; + this.address = address; + this.username = null; + this.password = null; + } + + public String getICEString() { + if(username == null) { + return address; + }else { + return address + ";" + username + ";" + password; + } + } + + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket.java b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket.java new file mode 100644 index 0000000..d58e45c --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket.java @@ -0,0 +1,144 @@ +package net.lax1dude.eaglercraft.sp.relay.pkt; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; + +public class IPacket { + + private static final Map> definedPacketClasses = new HashMap<>(); + private static final Map,Integer> definedPacketIds = new HashMap<>(); + + private static void register(int id, Class clazz) { + definedPacketClasses.put(id, clazz); + definedPacketIds.put(clazz, id); + } + + static { + register(0x00, IPacket00Handshake.class); + register(0x01, IPacket01ICEServers.class); + register(0x02, IPacket02NewClient.class); + register(0x03, IPacket03ICECandidate.class); + register(0x04, IPacket04Description.class); + register(0x05, IPacket05ClientSuccess.class); + register(0x06, IPacket06ClientFailure.class); + register(0x07, IPacket07LocalWorlds.class); + register(0x69, IPacket69Pong.class); + register(0xFE, IPacketFEDisconnectClient.class); + register(0xFF, IPacketFFErrorCode.class); + } + + public static IPacket readPacket(DataInputStream input) throws IOException { + int i = input.read(); + try { + Class clazz = definedPacketClasses.get(i); + if(clazz == null) { + throw new IOException("Unknown packet type: " + i); + } + IPacket pkt = clazz.newInstance(); + pkt.read(input); + return pkt; + } catch (InstantiationException | IllegalAccessException e) { + throw new IOException("Unknown packet type: " + i); + } + } + + public static byte[] writePacket(IPacket packet) throws IOException { + Integer i = definedPacketIds.get(packet.getClass()); + if(i != null) { + int len = packet.packetLength(); + ByteArrayOutputStream bao = len == -1 ? new ByteArrayOutputStream() : + new ByteArrayOutputStream(len + 1); + bao.write(i); + packet.write(new DataOutputStream(bao)); + byte[] ret = bao.toByteArray(); + if(len != -1 && ret.length != len + 1) { + System.err.println("writePacket buffer for packet " + packet.getClass().getSimpleName() + " " + + (len + 1 < ret.length ? "overflowed" : "underflowed") + " by " + (len + 1 < ret.length ? + ret.length - len - 1 : len + 1 - ret.length) + " bytes"); + } + return ret; + }else { + throw new IOException("Unknown packet type: " + packet.getClass().getSimpleName()); + } + } + + public void read(DataInputStream input) throws IOException { + } + + public void write(DataOutputStream output) throws IOException { + } + + public int packetLength() { + return -1; + } + + public static String readASCII(InputStream is, int len) throws IOException { + char[] ret = new char[len]; + for(int i = 0; i < len; ++i) { + int j = is.read(); + if(j < 0) { + return null; + } + ret[i] = (char)j; + } + return new String(ret); + } + + public static void writeASCII(OutputStream is, String txt) throws IOException { + for(int i = 0, l = txt.length(); i < l; ++i) { + is.write((int)txt.charAt(i)); + } + } + + public static String readASCII8(InputStream is) throws IOException { + int i = is.read(); + if(i < 0) { + return null; + }else { + return readASCII(is, i); + } + } + + public static void writeASCII8(OutputStream is, String txt) throws IOException { + if(txt == null) { + is.write(0); + }else { + int l = txt.length(); + is.write(l); + for(int i = 0; i < l; ++i) { + is.write((int)txt.charAt(i)); + } + } + } + + public static String readASCII16(InputStream is) throws IOException { + int hi = is.read(); + int lo = is.read(); + if(hi < 0 || lo < 0) { + return null; + }else { + return readASCII(is, (hi << 8) | lo); + } + } + + public static void writeASCII16(OutputStream is, String txt) throws IOException { + if(txt == null) { + is.write(0); + is.write(0); + }else { + int l = txt.length(); + is.write((l >> 8) & 0xFF); + is.write(l & 0xFF); + for(int i = 0; i < l; ++i) { + is.write((int)txt.charAt(i)); + } + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket00Handshake.java b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket00Handshake.java new file mode 100644 index 0000000..268c7f9 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket00Handshake.java @@ -0,0 +1,42 @@ +package net.lax1dude.eaglercraft.sp.relay.pkt; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class IPacket00Handshake extends IPacket { + + public int connectionType = 0; + public int connectionVersion = 1; + public String connectionCode = null; + + public IPacket00Handshake() { + } + + public IPacket00Handshake(int connectionType, int connectionVersion, + String connectionCode) { + this.connectionType = connectionType; + this.connectionVersion = connectionVersion; + this.connectionCode = connectionCode; + } + + @Override + public void read(DataInputStream input) throws IOException { + connectionType = input.read(); + connectionVersion = input.read(); + connectionCode = IPacket.readASCII8(input); + } + + @Override + public void write(DataOutputStream output) throws IOException { + output.write(connectionType); + output.write(connectionVersion); + IPacket.writeASCII8(output, connectionCode); + } + + @Override + public int packetLength() { + return 1 + 1 + (connectionCode != null ? 1 + connectionCode.length() : 0); + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket01ICEServers.java b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket01ICEServers.java new file mode 100644 index 0000000..c96cf53 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket01ICEServers.java @@ -0,0 +1,38 @@ +package net.lax1dude.eaglercraft.sp.relay.pkt; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; + +public class IPacket01ICEServers extends IPacket { + + public final Collection servers; + + public IPacket01ICEServers() { + servers = new ArrayList<>(); + } + + public void read(DataInputStream input) throws IOException { + servers.clear(); + int l = input.readUnsignedShort(); + for(int i = 0; i < l; ++i) { + char type = (char)input.read(); + ICEServerSet.RelayType typeEnum; + if(type == 'S') { + typeEnum = ICEServerSet.RelayType.STUN; + }else if(type == 'T') { + typeEnum = ICEServerSet.RelayType.TURN; + }else { + throw new IOException("Unknown/Unsupported Relay Type: '" + type + "'"); + } + servers.add(new ICEServerSet.RelayServer( + typeEnum, + readASCII16(input), + readASCII8(input), + readASCII8(input) + )); + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket02NewClient.java b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket02NewClient.java new file mode 100644 index 0000000..b6d2d05 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket02NewClient.java @@ -0,0 +1,21 @@ +package net.lax1dude.eaglercraft.sp.relay.pkt; + +import java.io.DataInputStream; +import java.io.IOException; + +public class IPacket02NewClient extends IPacket { + + public String clientId; + + public IPacket02NewClient(String clientId) { + this.clientId = clientId; + } + + public IPacket02NewClient() { + } + + public void read(DataInputStream input) throws IOException { + clientId = readASCII8(input); + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket03ICECandidate.java b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket03ICECandidate.java new file mode 100644 index 0000000..239a27f --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket03ICECandidate.java @@ -0,0 +1,34 @@ +package net.lax1dude.eaglercraft.sp.relay.pkt; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class IPacket03ICECandidate extends IPacket { + + public String peerId; + public String candidate; + + public IPacket03ICECandidate(String peerId, String desc) { + this.peerId = peerId; + this.candidate = desc; + } + + public IPacket03ICECandidate() { + } + + public void read(DataInputStream input) throws IOException { + peerId = readASCII8(input); + candidate = readASCII16(input); + } + + public void write(DataOutputStream output) throws IOException { + writeASCII8(output, peerId); + writeASCII16(output, candidate); + } + + public int packetLength() { + return 1 + peerId.length() + 2 + candidate.length(); + } + +} \ No newline at end of file diff --git a/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket04Description.java b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket04Description.java new file mode 100644 index 0000000..8693c7b --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket04Description.java @@ -0,0 +1,34 @@ +package net.lax1dude.eaglercraft.sp.relay.pkt; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class IPacket04Description extends IPacket { + + public String peerId; + public String description; + + public IPacket04Description(String peerId, String desc) { + this.peerId = peerId; + this.description = desc; + } + + public IPacket04Description() { + } + + public void read(DataInputStream input) throws IOException { + peerId = readASCII8(input); + description = readASCII16(input); + } + + public void write(DataOutputStream output) throws IOException { + writeASCII8(output, peerId); + writeASCII16(output, description); + } + + public int packetLength() { + return 1 + peerId.length() + 2 + description.length(); + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket05ClientSuccess.java b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket05ClientSuccess.java new file mode 100644 index 0000000..a215a1a --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket05ClientSuccess.java @@ -0,0 +1,30 @@ +package net.lax1dude.eaglercraft.sp.relay.pkt; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class IPacket05ClientSuccess extends IPacket { + + public String clientId; + + public IPacket05ClientSuccess() { + } + + public IPacket05ClientSuccess(String clientId) { + this.clientId = clientId; + } + + public void read(DataInputStream input) throws IOException { + clientId = readASCII8(input); + } + + public void write(DataOutputStream output) throws IOException { + writeASCII8(output, clientId); + } + + public int packetLength() { + return 1 + clientId.length(); + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket06ClientFailure.java b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket06ClientFailure.java new file mode 100644 index 0000000..fceae93 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket06ClientFailure.java @@ -0,0 +1,30 @@ +package net.lax1dude.eaglercraft.sp.relay.pkt; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class IPacket06ClientFailure extends IPacket { + + public String clientId; + + public IPacket06ClientFailure() { + } + + public IPacket06ClientFailure(String clientId) { + this.clientId = clientId; + } + + public void read(DataInputStream input) throws IOException { + clientId = readASCII8(input); + } + + public void write(DataOutputStream output) throws IOException { + writeASCII8(output, clientId); + } + + public int packetLength() { + return 1 + clientId.length(); + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket07LocalWorlds.java b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket07LocalWorlds.java new file mode 100644 index 0000000..769c188 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket07LocalWorlds.java @@ -0,0 +1,35 @@ +package net.lax1dude.eaglercraft.sp.relay.pkt; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class IPacket07LocalWorlds extends IPacket { + + public static class LocalWorld { + + public final String worldName; + public final String worldCode; + + public LocalWorld(String worldName, String worldCode) { + this.worldName = worldName; + this.worldCode = worldCode; + } + + } + + public final List worldsList; + + public IPacket07LocalWorlds() { + this.worldsList = new ArrayList<>(); + } + + public void read(DataInputStream input) throws IOException { + int l = input.read(); + for(int i = 0; i < l; ++i) { + worldsList.add(new LocalWorld(readASCII8(input), readASCII8(input))); + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket69Pong.java b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket69Pong.java new file mode 100644 index 0000000..8f6cb56 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket69Pong.java @@ -0,0 +1,30 @@ +package net.lax1dude.eaglercraft.sp.relay.pkt; + +import java.io.DataInputStream; +import java.io.IOException; + +public class IPacket69Pong extends IPacket { + + public int protcolVersion; + public String comment; + public String brand; + + public IPacket69Pong(int protcolVersion, String comment, String brand) { + if(comment.length() > 255) { + comment = comment.substring(0, 256); + } + this.protcolVersion = protcolVersion; + this.comment = comment; + this.brand = brand; + } + + public IPacket69Pong() { + } + + public void read(DataInputStream output) throws IOException { + protcolVersion = output.read(); + comment = readASCII8(output); + brand = readASCII8(output); + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacketFEDisconnectClient.java b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacketFEDisconnectClient.java new file mode 100644 index 0000000..d67894a --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacketFEDisconnectClient.java @@ -0,0 +1,52 @@ +package net.lax1dude.eaglercraft.sp.relay.pkt; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; + +public class IPacketFEDisconnectClient extends IPacket { + + public static final int TYPE_FINISHED_SUCCESS = 0x00; + public static final int TYPE_FINISHED_FAILED = 0x01; + public static final int TYPE_TIMEOUT = 0x02; + public static final int TYPE_INVALID_OPERATION = 0x03; + public static final int TYPE_INTERNAL_ERROR = 0x04; + public static final int TYPE_SERVER_DISCONNECT = 0x05; + public static final int TYPE_UNKNOWN = 0xFF; + + public String clientId; + public int code; + public String reason; + + public IPacketFEDisconnectClient() { + } + + public IPacketFEDisconnectClient(String clientId, int code, String reason) { + this.clientId = clientId; + this.code = code; + this.reason = reason; + } + + public void read(DataInputStream input) throws IOException { + clientId = readASCII8(input); + code = input.read(); + reason = readASCII16(input); + } + + public void write(DataOutputStream output) throws IOException { + writeASCII8(output, clientId); + output.write(code); + writeASCII16(output, reason); + } + + public int packetLength() { + return -1; + } + + public static final ByteBuffer ratelimitPacketTooMany = ByteBuffer.wrap(new byte[] { (byte)0xFC, (byte)0x00 }); + public static final ByteBuffer ratelimitPacketBlock = ByteBuffer.wrap(new byte[] { (byte)0xFC, (byte)0x01 }); + public static final ByteBuffer ratelimitPacketBlockLock = ByteBuffer.wrap(new byte[] { (byte)0xFC, (byte)0x02 }); + public static final ByteBuffer ratelimitPacketLocked = ByteBuffer.wrap(new byte[] { (byte)0xFC, (byte)0x03 }); + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacketFFErrorCode.java b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacketFFErrorCode.java new file mode 100644 index 0000000..b9f2617 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacketFFErrorCode.java @@ -0,0 +1,67 @@ +package net.lax1dude.eaglercraft.sp.relay.pkt; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class IPacketFFErrorCode extends IPacket { + + public static final int TYPE_INTERNAL_ERROR = 0x00; + public static final int TYPE_PROTOCOL_VERSION = 0x01; + public static final int TYPE_INVALID_PACKET = 0x02; + public static final int TYPE_ILLEGAL_OPERATION = 0x03; + public static final int TYPE_CODE_LENGTH = 0x04; + public static final int TYPE_INCORRECT_CODE = 0x05; + public static final int TYPE_SERVER_DISCONNECTED = 0x06; + public static final int TYPE_UNKNOWN_CLIENT = 0x07; + + public static final String[] packetTypes = new String[0x08]; + + static { + packetTypes[TYPE_INTERNAL_ERROR] = "TYPE_INTERNAL_ERROR"; + packetTypes[TYPE_PROTOCOL_VERSION] = "TYPE_PROTOCOL_VERSION"; + packetTypes[TYPE_INVALID_PACKET] = "TYPE_INVALID_PACKET"; + packetTypes[TYPE_ILLEGAL_OPERATION] = "TYPE_ILLEGAL_OPERATION"; + packetTypes[TYPE_CODE_LENGTH] = "TYPE_CODE_LENGTH"; + packetTypes[TYPE_INCORRECT_CODE] = "TYPE_INCORRECT_CODE"; + packetTypes[TYPE_SERVER_DISCONNECTED] = "TYPE_SERVER_DISCONNECTED"; + packetTypes[TYPE_UNKNOWN_CLIENT] = "TYPE_UNKNOWN_CLIENT"; + } + + public static String code2string(int i) { + if(i >= 0 || i < packetTypes.length) { + return packetTypes[i]; + }else { + return "UNKNOWN"; + } + } + + public int code; + public String desc; + + public IPacketFFErrorCode() { + } + + public IPacketFFErrorCode(int code, String desc) { + this.code = code; + this.desc = desc; + } + + @Override + public void read(DataInputStream input) throws IOException { + code = input.read(); + desc = readASCII16(input); + } + + @Override + public void write(DataOutputStream input) throws IOException { + input.write(code); + writeASCII16(input, desc); + } + + @Override + public int packetLength() { + return 1 + 2 + desc.length(); + } + +} diff --git a/src/main/java/net/minecraft/client/main/Main.java b/src/main/java/net/minecraft/client/main/Main.java deleted file mode 100644 index 30a30b3..0000000 --- a/src/main/java/net/minecraft/client/main/Main.java +++ /dev/null @@ -1,99 +0,0 @@ -package net.minecraft.client.main; - -import java.io.File; -import java.net.Authenticator; -import java.net.InetSocketAddress; -import java.net.Proxy; -import java.net.Proxy.Type; -import java.util.List; -import joptsimple.ArgumentAcceptingOptionSpec; -import joptsimple.NonOptionArgumentSpec; -import joptsimple.OptionParser; -import joptsimple.OptionSet; -import net.minecraft.src.MainProxyAuthenticator; -import net.minecraft.src.MainShutdownHook; -import net.minecraft.src.Minecraft; -import net.minecraft.src.Session; - -public class Main -{ - public static void main(String[] par0ArrayOfStr) - { - System.setProperty("java.net.preferIPv4Stack", "true"); - OptionParser var1 = new OptionParser(); - var1.allowsUnrecognizedOptions(); - var1.accepts("demo"); - var1.accepts("fullscreen"); - ArgumentAcceptingOptionSpec var2 = var1.accepts("server").withRequiredArg(); - ArgumentAcceptingOptionSpec var3 = var1.accepts("port").withRequiredArg().ofType(Integer.class).defaultsTo(Integer.valueOf(25565), new Integer[0]); - ArgumentAcceptingOptionSpec var4 = var1.accepts("gameDir").withRequiredArg().ofType(File.class).defaultsTo(new File("."), new File[0]); - ArgumentAcceptingOptionSpec var5 = var1.accepts("assetsDir").withRequiredArg().ofType(File.class).defaultsTo(new File("lwjgl-rundir/resources/assets"), new File[0]); - ArgumentAcceptingOptionSpec var6 = var1.accepts("resourcePackDir").withRequiredArg().ofType(File.class); - ArgumentAcceptingOptionSpec var7 = var1.accepts("proxyHost").withRequiredArg(); - ArgumentAcceptingOptionSpec var8 = var1.accepts("proxyPort").withRequiredArg().defaultsTo("8080", new String[0]).ofType(Integer.class); - ArgumentAcceptingOptionSpec var9 = var1.accepts("proxyUser").withRequiredArg(); - ArgumentAcceptingOptionSpec var10 = var1.accepts("proxyPass").withRequiredArg(); - ArgumentAcceptingOptionSpec var11 = var1.accepts("username").withRequiredArg().defaultsTo("DefaultClientTest"); - ArgumentAcceptingOptionSpec var12 = var1.accepts("session").withRequiredArg(); - ArgumentAcceptingOptionSpec var13 = var1.accepts("version").withRequiredArg().defaultsTo("1.6.4"); - ArgumentAcceptingOptionSpec var14 = var1.accepts("width").withRequiredArg().ofType(Integer.class).defaultsTo(Integer.valueOf(854), new Integer[0]); - ArgumentAcceptingOptionSpec var15 = var1.accepts("height").withRequiredArg().ofType(Integer.class).defaultsTo(Integer.valueOf(480), new Integer[0]); - NonOptionArgumentSpec var16 = var1.nonOptions(); - OptionSet var17 = var1.parse(par0ArrayOfStr); - List var18 = var17.valuesOf(var16); - String var19 = (String)var17.valueOf(var7); - Proxy var20 = Proxy.NO_PROXY; - - if (var19 != null) - { - try - { - var20 = new Proxy(Type.SOCKS, new InetSocketAddress(var19, ((Integer)var17.valueOf(var8)).intValue())); - } - catch (Exception var34) - { - ; - } - } - - String var21 = (String)var17.valueOf(var9); - String var22 = (String)var17.valueOf(var10); - - if (!var20.equals(Proxy.NO_PROXY) && func_110121_a(var21) && func_110121_a(var22)) - { - Authenticator.setDefault(new MainProxyAuthenticator(var21, var22)); - } - - int var23 = ((Integer)var17.valueOf(var14)).intValue(); - int var24 = ((Integer)var17.valueOf(var15)).intValue(); - boolean var25 = var17.has("fullscreen"); - boolean var26 = var17.has("demo"); - String var27 = (String)var17.valueOf(var13); - File var28 = (File)var17.valueOf(var4); - File var29 = var17.has(var5) ? (File)var17.valueOf(var5) : new File(var28, "assets/"); - File var30 = var17.has(var6) ? (File)var17.valueOf(var6) : new File(var28, "resourcepacks/"); - Session var31 = new Session((String)var11.value(var17), (String)var12.value(var17)); - Minecraft var32 = new Minecraft(var31, var23, var24, var25, var26, var28, var29, var30, var20, var27); - String var33 = (String)var17.valueOf(var2); - - if (var33 != null) - { - var32.setServer(var33, ((Integer)var17.valueOf(var3)).intValue()); - } - - Runtime.getRuntime().addShutdownHook(new MainShutdownHook()); - - if (!var18.isEmpty()) - { - System.out.println("Completely ignored arguments: " + var18); - } - - Thread.currentThread().setName("Minecraft main thread"); - var32.run(); - } - - private static boolean func_110121_a(String par0Str) - { - return par0Str != null && !par0Str.isEmpty(); - } -} diff --git a/src/main/java/net/minecraft/src/GameSettings.java b/src/main/java/net/minecraft/src/GameSettings.java index e595efc..f7fee02 100644 --- a/src/main/java/net/minecraft/src/GameSettings.java +++ b/src/main/java/net/minecraft/src/GameSettings.java @@ -124,6 +124,30 @@ public class GameSettings /** Game settings language */ public String language; + + /** Eagler settings */ + public boolean showSkinJacket = true; + public boolean showSkinHat = true; + public boolean showSkinLeftArm = true; + public boolean showSkinRightArm = true; + public boolean showSkinLeftLeg = true; + public boolean showSkinRightLeg = true; + + public boolean allowFNAWSkins = true; + public boolean showOtherCapes = true; + + public int chunkUpdatePerFrame = 0; + + public int voiceListenRadius = 16; + public float voiceListenVolume = 0.5f; + public float voiceSpeakVolume = 0.5f; + public int voicePTTKey = 47; + + public boolean hideJoinCode = false; + public int relayTimeout = 4; + + public boolean adderall = false; + public GameSettings(Minecraft par1Minecraft, File par2File) { this.keyBindings = new KeyBinding[] {this.keyBindAttack, this.keyBindUseItem, this.keyBindForward, this.keyBindLeft, this.keyBindBack, this.keyBindRight, this.keyBindJump, this.keyBindSneak, this.keyBindDrop, this.keyBindInventory, this.keyBindChat, this.keyBindPlayerList, this.keyBindPickBlock, this.keyBindCommand}; diff --git a/src/main/java/net/minecraft/src/Minecraft.java b/src/main/java/net/minecraft/src/Minecraft.java index be32aa1..c5b7f11 100644 --- a/src/main/java/net/minecraft/src/Minecraft.java +++ b/src/main/java/net/minecraft/src/Minecraft.java @@ -1,5 +1,19 @@ package net.minecraft.src; +import net.lax1dude.eaglercraft.DefaultSkinRenderer; +import net.lax1dude.eaglercraft.EaglerAdapter; +import net.lax1dude.eaglercraft.EaglerProfile; +import net.lax1dude.eaglercraft.GuiScreenEditProfile; +import net.lax1dude.eaglercraft.GuiScreenSingleplayerConnecting; +import net.lax1dude.eaglercraft.GuiScreenSingleplayerLoading; +import net.lax1dude.eaglercraft.GuiScreenVSyncWarning; +import net.lax1dude.eaglercraft.GuiVoiceOverlay; +import net.lax1dude.eaglercraft.IntegratedServer; +import net.lax1dude.eaglercraft.IntegratedServerLAN; +import net.lax1dude.eaglercraft.Voice; +import net.lax1dude.eaglercraft.WorkerNetworkManager; +import net.lax1dude.eaglercraft.adapter.Tessellator; +import net.lax1dude.eaglercraft.glemu.FixedFunctionShader; import com.google.common.collect.Lists; import java.awt.image.BufferedImage; import java.io.File; @@ -43,7 +57,7 @@ public class Minecraft implements IPlayerUsage private ServerData currentServerData; /** The RenderEngine instance used by Minecraft */ - private TextureManager renderEngine; + public RenderEngine renderEngine; /** * Set to 'this' in Minecraft constructor; used by some settings get methods @@ -186,29 +200,16 @@ public class Minecraft implements IPlayerUsage /** Profiler currently displayed in the debug screen pie chart */ private String debugProfilerName = "root"; - public Minecraft(Session par1Session, int par2, int par3, boolean par4, boolean par5, File par6File, File par7File, File par8File, Proxy par9Proxy, String par10Str) + public Minecraft() { - theMinecraft = this; - this.mcLogAgent = new LogAgent("Minecraft-Client", " [CLIENT]", null); - this.mcDataDir = par6File; - this.fileAssets = par7File; - this.fileResourcepacks = par8File; - this.launchedVersion = par10Str; - this.mcDefaultResourcePack = new DefaultResourcePack(this.fileAssets); - this.addDefaultResourcePack(); - this.proxy = par9Proxy; - this.startTimerHackThread(); - this.session = par1Session; - this.mcLogAgent.logInfo("Setting user: " + par1Session.getUsername()); - this.mcLogAgent.logInfo("(Session ID is " + par1Session.getSessionID() + ")"); - this.isDemo = par5; - this.displayWidth = par2; - this.displayHeight = par3; - this.tempDisplayWidth = par2; - this.tempDisplayHeight = par3; - this.fullscreen = par4; - ImageIO.setUseCache(false); - //StatList.nopInit(); + this.tempDisplayHeight = 480; + this.fullscreen = false; + Packet3Chat.maxChatLength = 32767; + this.startTimerHackThread(); + this.displayWidth = 854; + this.displayHeight = 480; + this.fullscreen = false; + theMinecraft = this; } private void startTimerHackThread() diff --git a/src/main/java/net/minecraft/src/StringTranslate.java b/src/main/java/net/minecraft/src/StringTranslate.java index 6101a0e..6956ad6 100644 --- a/src/main/java/net/minecraft/src/StringTranslate.java +++ b/src/main/java/net/minecraft/src/StringTranslate.java @@ -54,7 +54,7 @@ public class StringTranslate /** * Return the StringTranslate singleton instance */ - static StringTranslate getInstance() + public static StringTranslate getInstance() { return instance; } diff --git a/src/main/java/org/json/CDL.java b/src/main/java/org/json/CDL.java new file mode 100644 index 0000000..f12cfc0 --- /dev/null +++ b/src/main/java/org/json/CDL.java @@ -0,0 +1,287 @@ +package org.json; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ + +/** + * This provides static methods to convert comma delimited text into a + * JSONArray, and to convert a JSONArray into comma delimited text. Comma + * delimited text is a very popular format for data interchange. It is + * understood by most database, spreadsheet, and organizer programs. + *

+ * Each row of text represents a row in a table or a data record. Each row + * ends with a NEWLINE character. Each row contains one or more values. + * Values are separated by commas. A value can contain any character except + * for comma, unless is is wrapped in single quotes or double quotes. + *

+ * The first row usually contains the names of the columns. + *

+ * A comma delimited list can be converted into a JSONArray of JSONObjects. + * The names for the elements in the JSONObjects can be taken from the names + * in the first row. + * @author JSON.org + * @version 2016-05-01 + */ +public class CDL { + + /** + * Get the next value. The value can be wrapped in quotes. The value can + * be empty. + * @param x A JSONTokener of the source text. + * @return The value string, or null if empty. + * @throws JSONException if the quoted string is badly formed. + */ + private static String getValue(JSONTokener x) throws JSONException { + char c; + char q; + StringBuilder sb; + do { + c = x.next(); + } while (c == ' ' || c == '\t'); + switch (c) { + case 0: + return null; + case '"': + case '\'': + q = c; + sb = new StringBuilder(); + for (;;) { + c = x.next(); + if (c == q) { + //Handle escaped double-quote + char nextC = x.next(); + if(nextC != '\"') { + // if our quote was the end of the file, don't step + if(nextC > 0) { + x.back(); + } + break; + } + } + if (c == 0 || c == '\n' || c == '\r') { + throw x.syntaxError("Missing close quote '" + q + "'."); + } + sb.append(c); + } + return sb.toString(); + case ',': + x.back(); + return ""; + default: + x.back(); + return x.nextTo(','); + } + } + + /** + * Produce a JSONArray of strings from a row of comma delimited values. + * @param x A JSONTokener of the source text. + * @return A JSONArray of strings. + * @throws JSONException if a called function fails + */ + public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException { + JSONArray ja = new JSONArray(); + for (;;) { + String value = getValue(x); + char c = x.next(); + if (value == null || + (ja.length() == 0 && value.length() == 0 && c != ',')) { + return null; + } + ja.put(value); + for (;;) { + if (c == ',') { + break; + } + if (c != ' ') { + if (c == '\n' || c == '\r' || c == 0) { + return ja; + } + throw x.syntaxError("Bad character '" + c + "' (" + + (int)c + ")."); + } + c = x.next(); + } + } + } + + /** + * Produce a JSONObject from a row of comma delimited text, using a + * parallel JSONArray of strings to provides the names of the elements. + * @param names A JSONArray of names. This is commonly obtained from the + * first row of a comma delimited text file using the rowToJSONArray + * method. + * @param x A JSONTokener of the source text. + * @return A JSONObject combining the names and values. + * @throws JSONException if a called function fails + */ + public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x) + throws JSONException { + JSONArray ja = rowToJSONArray(x); + return ja != null ? ja.toJSONObject(names) : null; + } + + /** + * Produce a comma delimited text row from a JSONArray. Values containing + * the comma character will be quoted. Troublesome characters may be + * removed. + * @param ja A JSONArray of strings. + * @return A string ending in NEWLINE. + */ + public static String rowToString(JSONArray ja) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < ja.length(); i += 1) { + if (i > 0) { + sb.append(','); + } + Object object = ja.opt(i); + if (object != null) { + String string = object.toString(); + if (string.length() > 0 && (string.indexOf(',') >= 0 || + string.indexOf('\n') >= 0 || string.indexOf('\r') >= 0 || + string.indexOf(0) >= 0 || string.charAt(0) == '"')) { + sb.append('"'); + int length = string.length(); + for (int j = 0; j < length; j += 1) { + char c = string.charAt(j); + if (c >= ' ' && c != '"') { + sb.append(c); + } + } + sb.append('"'); + } else { + sb.append(string); + } + } + } + sb.append('\n'); + return sb.toString(); + } + + /** + * Produce a JSONArray of JSONObjects from a comma delimited text string, + * using the first row as a source of names. + * @param string The comma delimited text. + * @return A JSONArray of JSONObjects. + * @throws JSONException if a called function fails + */ + public static JSONArray toJSONArray(String string) throws JSONException { + return toJSONArray(new JSONTokener(string)); + } + + /** + * Produce a JSONArray of JSONObjects from a comma delimited text string, + * using the first row as a source of names. + * @param x The JSONTokener containing the comma delimited text. + * @return A JSONArray of JSONObjects. + * @throws JSONException if a called function fails + */ + public static JSONArray toJSONArray(JSONTokener x) throws JSONException { + return toJSONArray(rowToJSONArray(x), x); + } + + /** + * Produce a JSONArray of JSONObjects from a comma delimited text string + * using a supplied JSONArray as the source of element names. + * @param names A JSONArray of strings. + * @param string The comma delimited text. + * @return A JSONArray of JSONObjects. + * @throws JSONException if a called function fails + */ + public static JSONArray toJSONArray(JSONArray names, String string) + throws JSONException { + return toJSONArray(names, new JSONTokener(string)); + } + + /** + * Produce a JSONArray of JSONObjects from a comma delimited text string + * using a supplied JSONArray as the source of element names. + * @param names A JSONArray of strings. + * @param x A JSONTokener of the source text. + * @return A JSONArray of JSONObjects. + * @throws JSONException if a called function fails + */ + public static JSONArray toJSONArray(JSONArray names, JSONTokener x) + throws JSONException { + if (names == null || names.length() == 0) { + return null; + } + JSONArray ja = new JSONArray(); + for (;;) { + JSONObject jo = rowToJSONObject(names, x); + if (jo == null) { + break; + } + ja.put(jo); + } + if (ja.length() == 0) { + return null; + } + return ja; + } + + + /** + * Produce a comma delimited text from a JSONArray of JSONObjects. The + * first row will be a list of names obtained by inspecting the first + * JSONObject. + * @param ja A JSONArray of JSONObjects. + * @return A comma delimited text. + * @throws JSONException if a called function fails + */ + public static String toString(JSONArray ja) throws JSONException { + JSONObject jo = ja.optJSONObject(0); + if (jo != null) { + JSONArray names = jo.names(); + if (names != null) { + return rowToString(names) + toString(names, ja); + } + } + return null; + } + + /** + * Produce a comma delimited text from a JSONArray of JSONObjects using + * a provided list of names. The list of names is not included in the + * output. + * @param names A JSONArray of strings. + * @param ja A JSONArray of JSONObjects. + * @return A comma delimited text. + * @throws JSONException if a called function fails + */ + public static String toString(JSONArray names, JSONArray ja) + throws JSONException { + if (names == null || names.length() == 0) { + return null; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < ja.length(); i += 1) { + JSONObject jo = ja.optJSONObject(i); + if (jo != null) { + sb.append(rowToString(jo.toJSONArray(names))); + } + } + return sb.toString(); + } +} diff --git a/src/main/java/org/json/Cookie.java b/src/main/java/org/json/Cookie.java new file mode 100644 index 0000000..1c5fb78 --- /dev/null +++ b/src/main/java/org/json/Cookie.java @@ -0,0 +1,224 @@ +package org.json; + +import java.util.Locale; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +/** + * Convert a web browser cookie specification to a JSONObject and back. + * JSON and Cookies are both notations for name/value pairs. + * See also: https://tools.ietf.org/html/rfc6265 + * @author JSON.org + * @version 2015-12-09 + */ +public class Cookie { + + /** + * Produce a copy of a string in which the characters '+', '%', '=', ';' + * and control characters are replaced with "%hh". This is a gentle form + * of URL encoding, attempting to cause as little distortion to the + * string as possible. The characters '=' and ';' are meta characters in + * cookies. By convention, they are escaped using the URL-encoding. This is + * only a convention, not a standard. Often, cookies are expected to have + * encoded values. We encode '=' and ';' because we must. We encode '%' and + * '+' because they are meta characters in URL encoding. + * @param string The source string. + * @return The escaped result. + */ + public static String escape(String string) { + char c; + String s = string.trim(); + int length = s.length(); + StringBuilder sb = new StringBuilder(length); + for (int i = 0; i < length; i += 1) { + c = s.charAt(i); + if (c < ' ' || c == '+' || c == '%' || c == '=' || c == ';') { + sb.append('%'); + sb.append(Character.forDigit((char)((c >>> 4) & 0x0f), 16)); + sb.append(Character.forDigit((char)(c & 0x0f), 16)); + } else { + sb.append(c); + } + } + return sb.toString(); + } + + + /** + * Convert a cookie specification string into a JSONObject. The string + * must contain a name value pair separated by '='. The name and the value + * will be unescaped, possibly converting '+' and '%' sequences. The + * cookie properties may follow, separated by ';', also represented as + * name=value (except the Attribute properties like "Secure" or "HttpOnly", + * which do not have a value. The value {@link Boolean#TRUE} will be used for these). + * The name will be stored under the key "name", and the value will be + * stored under the key "value". This method does not do checking or + * validation of the parameters. It only converts the cookie string into + * a JSONObject. All attribute names are converted to lower case keys in the + * JSONObject (HttpOnly => httponly). If an attribute is specified more than + * once, only the value found closer to the end of the cookie-string is kept. + * @param string The cookie specification string. + * @return A JSONObject containing "name", "value", and possibly other + * members. + * @throws JSONException If there is an error parsing the Cookie String. + * Cookie strings must have at least one '=' character and the 'name' + * portion of the cookie must not be blank. + */ + public static JSONObject toJSONObject(String string) { + final JSONObject jo = new JSONObject(); + String name; + Object value; + + + JSONTokener x = new JSONTokener(string); + + name = unescape(x.nextTo('=').trim()); + //per RFC6265, if the name is blank, the cookie should be ignored. + if("".equals(name)) { + throw new JSONException("Cookies must have a 'name'"); + } + jo.put("name", name); + // per RFC6265, if there is no '=', the cookie should be ignored. + // the 'next' call here throws an exception if the '=' is not found. + x.next('='); + jo.put("value", unescape(x.nextTo(';')).trim()); + // discard the ';' + x.next(); + // parse the remaining cookie attributes + while (x.more()) { + name = unescape(x.nextTo("=;")).trim().toLowerCase(Locale.ROOT); + // don't allow a cookies attributes to overwrite its name or value. + if("name".equalsIgnoreCase(name)) { + throw new JSONException("Illegal attribute name: 'name'"); + } + if("value".equalsIgnoreCase(name)) { + throw new JSONException("Illegal attribute name: 'value'"); + } + // check to see if it's a flag property + if (x.next() != '=') { + value = Boolean.TRUE; + } else { + value = unescape(x.nextTo(';')).trim(); + x.next(); + } + // only store non-blank attributes + if(!"".equals(name) && !"".equals(value)) { + jo.put(name, value); + } + } + return jo; + } + + + /** + * Convert a JSONObject into a cookie specification string. The JSONObject + * must contain "name" and "value" members (case insensitive). + * If the JSONObject contains other members, they will be appended to the cookie + * specification string. User-Agents are instructed to ignore unknown attributes, + * so ensure your JSONObject is using only known attributes. + * See also: https://tools.ietf.org/html/rfc6265 + * @param jo A JSONObject + * @return A cookie specification string + * @throws JSONException thrown if the cookie has no name. + */ + public static String toString(JSONObject jo) throws JSONException { + StringBuilder sb = new StringBuilder(); + + String name = null; + Object value = null; + for(String key : jo.keySet()){ + if("name".equalsIgnoreCase(key)) { + name = jo.getString(key).trim(); + } + if("value".equalsIgnoreCase(key)) { + value=jo.getString(key).trim(); + } + if(name != null && value != null) { + break; + } + } + + if(name == null || "".equals(name.trim())) { + throw new JSONException("Cookie does not have a name"); + } + if(value == null) { + value = ""; + } + + sb.append(escape(name)); + sb.append("="); + sb.append(escape((String)value)); + + for(String key : jo.keySet()){ + if("name".equalsIgnoreCase(key) + || "value".equalsIgnoreCase(key)) { + // already processed above + continue; + } + value = jo.opt(key); + if(value instanceof Boolean) { + if(Boolean.TRUE.equals(value)) { + sb.append(';').append(escape(key)); + } + // don't emit false values + } else { + sb.append(';') + .append(escape(key)) + .append('=') + .append(escape(value.toString())); + } + } + + return sb.toString(); + } + + /** + * Convert %hh sequences to single characters, and + * convert plus to space. + * @param string A string that may contain + * + (plus) and + * %hh sequences. + * @return The unescaped string. + */ + public static String unescape(String string) { + int length = string.length(); + StringBuilder sb = new StringBuilder(length); + for (int i = 0; i < length; ++i) { + char c = string.charAt(i); + if (c == '+') { + c = ' '; + } else if (c == '%' && i + 2 < length) { + int d = JSONTokener.dehexchar(string.charAt(i + 1)); + int e = JSONTokener.dehexchar(string.charAt(i + 2)); + if (d >= 0 && e >= 0) { + c = (char)(d * 16 + e); + i += 2; + } + } + sb.append(c); + } + return sb.toString(); + } +} diff --git a/src/main/java/org/json/CookieList.java b/src/main/java/org/json/CookieList.java new file mode 100644 index 0000000..83b2630 --- /dev/null +++ b/src/main/java/org/json/CookieList.java @@ -0,0 +1,86 @@ +package org.json; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ + +/** + * Convert a web browser cookie list string to a JSONObject and back. + * @author JSON.org + * @version 2015-12-09 + */ +public class CookieList { + + /** + * Convert a cookie list into a JSONObject. A cookie list is a sequence + * of name/value pairs. The names are separated from the values by '='. + * The pairs are separated by ';'. The names and the values + * will be unescaped, possibly converting '+' and '%' sequences. + * + * To add a cookie to a cookie list, + * cookielistJSONObject.put(cookieJSONObject.getString("name"), + * cookieJSONObject.getString("value")); + * @param string A cookie list string + * @return A JSONObject + * @throws JSONException if a called function fails + */ + public static JSONObject toJSONObject(String string) throws JSONException { + JSONObject jo = new JSONObject(); + JSONTokener x = new JSONTokener(string); + while (x.more()) { + String name = Cookie.unescape(x.nextTo('=')); + x.next('='); + jo.put(name, Cookie.unescape(x.nextTo(';'))); + x.next(); + } + return jo; + } + + /** + * Convert a JSONObject into a cookie list. A cookie list is a sequence + * of name/value pairs. The names are separated from the values by '='. + * The pairs are separated by ';'. The characters '%', '+', '=', and ';' + * in the names and values are replaced by "%hh". + * @param jo A JSONObject + * @return A cookie list string + * @throws JSONException if a called function fails + */ + public static String toString(JSONObject jo) throws JSONException { + boolean b = false; + final StringBuilder sb = new StringBuilder(); + // Don't use the new entrySet API to maintain Android support + for (final String key : jo.keySet()) { + final Object value = jo.opt(key); + if (!JSONObject.NULL.equals(value)) { + if (b) { + sb.append(';'); + } + sb.append(Cookie.escape(key)); + sb.append("="); + sb.append(Cookie.escape(value.toString())); + b = true; + } + } + return sb.toString(); + } +} diff --git a/src/main/java/org/json/HTTP.java b/src/main/java/org/json/HTTP.java new file mode 100644 index 0000000..cc01167 --- /dev/null +++ b/src/main/java/org/json/HTTP.java @@ -0,0 +1,162 @@ +package org.json; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +import java.util.Locale; + +/** + * Convert an HTTP header to a JSONObject and back. + * @author JSON.org + * @version 2015-12-09 + */ +public class HTTP { + + /** Carriage return/line feed. */ + public static final String CRLF = "\r\n"; + + /** + * Convert an HTTP header string into a JSONObject. It can be a request + * header or a response header. A request header will contain + *

{
+     *    Method: "POST" (for example),
+     *    "Request-URI": "/" (for example),
+     *    "HTTP-Version": "HTTP/1.1" (for example)
+     * }
+ * A response header will contain + *
{
+     *    "HTTP-Version": "HTTP/1.1" (for example),
+     *    "Status-Code": "200" (for example),
+     *    "Reason-Phrase": "OK" (for example)
+     * }
+ * In addition, the other parameters in the header will be captured, using + * the HTTP field names as JSON names, so that
{@code
+     *    Date: Sun, 26 May 2002 18:06:04 GMT
+     *    Cookie: Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s
+     *    Cache-Control: no-cache}
+ * become + *
{@code
+     *    Date: "Sun, 26 May 2002 18:06:04 GMT",
+     *    Cookie: "Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s",
+     *    "Cache-Control": "no-cache",
+     * ...}
+ * It does no further checking or conversion. It does not parse dates. + * It does not do '%' transforms on URLs. + * @param string An HTTP header string. + * @return A JSONObject containing the elements and attributes + * of the XML string. + * @throws JSONException if a called function fails + */ + public static JSONObject toJSONObject(String string) throws JSONException { + JSONObject jo = new JSONObject(); + HTTPTokener x = new HTTPTokener(string); + String token; + + token = x.nextToken(); + if (token.toUpperCase(Locale.ROOT).startsWith("HTTP")) { + +// Response + + jo.put("HTTP-Version", token); + jo.put("Status-Code", x.nextToken()); + jo.put("Reason-Phrase", x.nextTo('\0')); + x.next(); + + } else { + +// Request + + jo.put("Method", token); + jo.put("Request-URI", x.nextToken()); + jo.put("HTTP-Version", x.nextToken()); + } + +// Fields + + while (x.more()) { + String name = x.nextTo(':'); + x.next(':'); + jo.put(name, x.nextTo('\0')); + x.next(); + } + return jo; + } + + + /** + * Convert a JSONObject into an HTTP header. A request header must contain + *
{
+     *    Method: "POST" (for example),
+     *    "Request-URI": "/" (for example),
+     *    "HTTP-Version": "HTTP/1.1" (for example)
+     * }
+ * A response header must contain + *
{
+     *    "HTTP-Version": "HTTP/1.1" (for example),
+     *    "Status-Code": "200" (for example),
+     *    "Reason-Phrase": "OK" (for example)
+     * }
+ * Any other members of the JSONObject will be output as HTTP fields. + * The result will end with two CRLF pairs. + * @param jo A JSONObject + * @return An HTTP header string. + * @throws JSONException if the object does not contain enough + * information. + */ + public static String toString(JSONObject jo) throws JSONException { + StringBuilder sb = new StringBuilder(); + if (jo.has("Status-Code") && jo.has("Reason-Phrase")) { + sb.append(jo.getString("HTTP-Version")); + sb.append(' '); + sb.append(jo.getString("Status-Code")); + sb.append(' '); + sb.append(jo.getString("Reason-Phrase")); + } else if (jo.has("Method") && jo.has("Request-URI")) { + sb.append(jo.getString("Method")); + sb.append(' '); + sb.append('"'); + sb.append(jo.getString("Request-URI")); + sb.append('"'); + sb.append(' '); + sb.append(jo.getString("HTTP-Version")); + } else { + throw new JSONException("Not enough material for an HTTP header."); + } + sb.append(CRLF); + // Don't use the new entrySet API to maintain Android support + for (final String key : jo.keySet()) { + String value = jo.optString(key); + if (!"HTTP-Version".equals(key) && !"Status-Code".equals(key) && + !"Reason-Phrase".equals(key) && !"Method".equals(key) && + !"Request-URI".equals(key) && !JSONObject.NULL.equals(value)) { + sb.append(key); + sb.append(": "); + sb.append(jo.optString(key)); + sb.append(CRLF); + } + } + sb.append(CRLF); + return sb.toString(); + } +} diff --git a/src/main/java/org/json/HTTPTokener.java b/src/main/java/org/json/HTTPTokener.java new file mode 100644 index 0000000..16c7081 --- /dev/null +++ b/src/main/java/org/json/HTTPTokener.java @@ -0,0 +1,77 @@ +package org.json; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +/** + * The HTTPTokener extends the JSONTokener to provide additional methods + * for the parsing of HTTP headers. + * @author JSON.org + * @version 2015-12-09 + */ +public class HTTPTokener extends JSONTokener { + + /** + * Construct an HTTPTokener from a string. + * @param string A source string. + */ + public HTTPTokener(String string) { + super(string); + } + + + /** + * Get the next token or string. This is used in parsing HTTP headers. + * @return A String. + * @throws JSONException if a syntax error occurs + */ + public String nextToken() throws JSONException { + char c; + char q; + StringBuilder sb = new StringBuilder(); + do { + c = next(); + } while (Character.isWhitespace(c)); + if (c == '"' || c == '\'') { + q = c; + for (;;) { + c = next(); + if (c < ' ') { + throw syntaxError("Unterminated string."); + } + if (c == q) { + return sb.toString(); + } + sb.append(c); + } + } + for (;;) { + if (c == 0 || Character.isWhitespace(c)) { + return sb.toString(); + } + sb.append(c); + c = next(); + } + } +} diff --git a/src/main/java/org/json/JSONArray.java b/src/main/java/org/json/JSONArray.java new file mode 100644 index 0000000..7e95a96 --- /dev/null +++ b/src/main/java/org/json/JSONArray.java @@ -0,0 +1,1716 @@ +package org.json; + +/* + Copyright (c) 2002 JSON.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + The Software shall be used for Good, not Evil. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.reflect.Array; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + + +/** + * A JSONArray is an ordered sequence of values. Its external text form is a + * string wrapped in square brackets with commas separating the values. The + * internal form is an object having get and opt + * methods for accessing the values by index, and put methods for + * adding or replacing values. The values can be any of these types: + * Boolean, JSONArray, JSONObject, + * Number, String, or the + * JSONObject.NULL object. + *

+ * The constructor can convert a JSON text into a Java object. The + * toString method converts to JSON text. + *

+ * A get method returns a value if one can be found, and throws an + * exception if one cannot be found. An opt method returns a + * default value instead of throwing an exception, and so is useful for + * obtaining optional values. + *

+ * The generic get() and opt() methods return an + * object which you can cast or query for type. There are also typed + * get and opt methods that do type checking and type + * coercion for you. + *

+ * The texts produced by the toString methods strictly conform to + * JSON syntax rules. The constructors are more forgiving in the texts they will + * accept: + *

    + *
  • An extra , (comma) may appear just + * before the closing bracket.
  • + *
  • The null value will be inserted when there is , + *  (comma) elision.
  • + *
  • Strings may be quoted with ' (single + * quote).
  • + *
  • Strings do not need to be quoted at all if they do not begin with a quote + * or single quote, and if they do not contain leading or trailing spaces, and + * if they do not contain any of these characters: + * { } [ ] / \ : , # and if they do not look like numbers and + * if they are not the reserved words true, false, or + * null.
  • + *
+ * + * @author JSON.org + * @version 2016-08/15 + */ +public class JSONArray implements Iterable { + + /** + * The arrayList where the JSONArray's properties are kept. + */ + private final ArrayList myArrayList; + + /** + * Construct an empty JSONArray. + */ + public JSONArray() { + this.myArrayList = new ArrayList(); + } + + /** + * Construct a JSONArray from a JSONTokener. + * + * @param x + * A JSONTokener + * @throws JSONException + * If there is a syntax error. + */ + public JSONArray(JSONTokener x) throws JSONException { + this(); + if (x.nextClean() != '[') { + throw x.syntaxError("A JSONArray text must start with '['"); + } + + char nextChar = x.nextClean(); + if (nextChar == 0) { + // array is unclosed. No ']' found, instead EOF + throw x.syntaxError("Expected a ',' or ']'"); + } + if (nextChar != ']') { + x.back(); + for (;;) { + if (x.nextClean() == ',') { + x.back(); + this.myArrayList.add(JSONObject.NULL); + } else { + x.back(); + this.myArrayList.add(x.nextValue()); + } + switch (x.nextClean()) { + case 0: + // array is unclosed. No ']' found, instead EOF + throw x.syntaxError("Expected a ',' or ']'"); + case ',': + nextChar = x.nextClean(); + if (nextChar == 0) { + // array is unclosed. No ']' found, instead EOF + throw x.syntaxError("Expected a ',' or ']'"); + } + if (nextChar == ']') { + return; + } + x.back(); + break; + case ']': + return; + default: + throw x.syntaxError("Expected a ',' or ']'"); + } + } + } + } + + /** + * Construct a JSONArray from a source JSON text. + * + * @param source + * A string that begins with [ (left + * bracket) and ends with ] + *  (right bracket). + * @throws JSONException + * If there is a syntax error. + */ + public JSONArray(String source) throws JSONException { + this(new JSONTokener(source)); + } + + /** + * Construct a JSONArray from a Collection. + * + * @param collection + * A Collection. + */ + public JSONArray(Collection collection) { + if (collection == null) { + this.myArrayList = new ArrayList(); + } else { + this.myArrayList = new ArrayList(collection.size()); + this.addAll(collection, true); + } + } + + /** + * Construct a JSONArray from an Iterable. This is a shallow copy. + * + * @param iter + * A Iterable collection. + */ + public JSONArray(Iterable iter) { + this(); + if (iter == null) { + return; + } + this.addAll(iter, true); + } + + /** + * Construct a JSONArray from another JSONArray. This is a shallow copy. + * + * @param array + * A array. + */ + public JSONArray(JSONArray array) { + if (array == null) { + this.myArrayList = new ArrayList(); + } else { + // shallow copy directly the internal array lists as any wrapping + // should have been done already in the original JSONArray + this.myArrayList = new ArrayList(array.myArrayList); + } + } + + /** + * Construct a JSONArray from an array. + * + * @param array + * Array. If the parameter passed is null, or not an array, an + * exception will be thrown. + * + * @throws JSONException + * If not an array or if an array value is non-finite number. + * @throws NullPointerException + * Thrown if the array parameter is null. + */ + public JSONArray(Object array) throws JSONException { + this(); + if (!array.getClass().isArray()) { + throw new JSONException( + "JSONArray initial value should be a string or collection or array."); + } + this.addAll(array, true); + } + + /** + * Construct a JSONArray with the specified initial capacity. + * + * @param initialCapacity + * the initial capacity of the JSONArray. + * @throws JSONException + * If the initial capacity is negative. + */ + public JSONArray(int initialCapacity) throws JSONException { + if (initialCapacity < 0) { + throw new JSONException( + "JSONArray initial capacity cannot be negative."); + } + this.myArrayList = new ArrayList(initialCapacity); + } + + @Override + public Iterator iterator() { + return this.myArrayList.iterator(); + } + + /** + * Get the object value associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return An object value. + * @throws JSONException + * If there is no value for the index. + */ + public Object get(int index) throws JSONException { + Object object = this.opt(index); + if (object == null) { + throw new JSONException("JSONArray[" + index + "] not found."); + } + return object; + } + + /** + * Get the boolean value associated with an index. The string values "true" + * and "false" are converted to boolean. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The truth. + * @throws JSONException + * If there is no value for the index or if the value is not + * convertible to boolean. + */ + public boolean getBoolean(int index) throws JSONException { + Object object = this.get(index); + if (object.equals(Boolean.FALSE) + || (object instanceof String && ((String) object) + .equalsIgnoreCase("false"))) { + return false; + } else if (object.equals(Boolean.TRUE) + || (object instanceof String && ((String) object) + .equalsIgnoreCase("true"))) { + return true; + } + throw wrongValueFormatException(index, "boolean", null); + } + + /** + * Get the double value associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + * @throws JSONException + * If the key is not found or if the value cannot be converted + * to a number. + */ + public double getDouble(int index) throws JSONException { + final Object object = this.get(index); + if(object instanceof Number) { + return ((Number)object).doubleValue(); + } + try { + return Double.parseDouble(object.toString()); + } catch (Exception e) { + throw wrongValueFormatException(index, "double", e); + } + } + + /** + * Get the float value associated with a key. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The numeric value. + * @throws JSONException + * if the key is not found or if the value is not a Number + * object and cannot be converted to a number. + */ + public float getFloat(int index) throws JSONException { + final Object object = this.get(index); + if(object instanceof Number) { + return ((Number)object).floatValue(); + } + try { + return Float.parseFloat(object.toString()); + } catch (Exception e) { + throw wrongValueFormatException(index, "float", e); + } + } + + /** + * Get the Number value associated with a key. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The numeric value. + * @throws JSONException + * if the key is not found or if the value is not a Number + * object and cannot be converted to a number. + */ + public Number getNumber(int index) throws JSONException { + Object object = this.get(index); + try { + if (object instanceof Number) { + return (Number)object; + } + return JSONObject.stringToNumber(object.toString()); + } catch (Exception e) { + throw wrongValueFormatException(index, "number", e); + } + } + + /** + * Get the enum value associated with an index. + * + * @param + * Enum Type + * @param clazz + * The type of enum to retrieve. + * @param index + * The index must be between 0 and length() - 1. + * @return The enum value at the index location + * @throws JSONException + * if the key is not found or if the value cannot be converted + * to an enum. + */ + public > E getEnum(Class clazz, int index) throws JSONException { + E val = optEnum(clazz, index); + if(val==null) { + // JSONException should really take a throwable argument. + // If it did, I would re-implement this with the Enum.valueOf + // method and place any thrown exception in the JSONException + throw wrongValueFormatException(index, "enum of type " + + JSONObject.quote(clazz.getSimpleName()), null); + } + return val; + } + + /** + * Get the BigDecimal value associated with an index. If the value is float + * or double, the {@link BigDecimal#BigDecimal(double)} constructor + * will be used. See notes on the constructor for conversion issues that + * may arise. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + * @throws JSONException + * If the key is not found or if the value cannot be converted + * to a BigDecimal. + */ + public BigDecimal getBigDecimal (int index) throws JSONException { + Object object = this.get(index); + BigDecimal val = JSONObject.objectToBigDecimal(object, null); + if(val == null) { + throw wrongValueFormatException(index, "BigDecimal", object, null); + } + return val; + } + + /** + * Get the BigInteger value associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + * @throws JSONException + * If the key is not found or if the value cannot be converted + * to a BigInteger. + */ + public BigInteger getBigInteger (int index) throws JSONException { + Object object = this.get(index); + BigInteger val = JSONObject.objectToBigInteger(object, null); + if(val == null) { + throw wrongValueFormatException(index, "BigInteger", object, null); + } + return val; + } + + /** + * Get the int value associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + * @throws JSONException + * If the key is not found or if the value is not a number. + */ + public int getInt(int index) throws JSONException { + final Object object = this.get(index); + if(object instanceof Number) { + return ((Number)object).intValue(); + } + try { + return Integer.parseInt(object.toString()); + } catch (Exception e) { + throw wrongValueFormatException(index, "int", e); + } + } + + /** + * Get the JSONArray associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return A JSONArray value. + * @throws JSONException + * If there is no value for the index. or if the value is not a + * JSONArray + */ + public JSONArray getJSONArray(int index) throws JSONException { + Object object = this.get(index); + if (object instanceof JSONArray) { + return (JSONArray) object; + } + throw wrongValueFormatException(index, "JSONArray", null); + } + + /** + * Get the JSONObject associated with an index. + * + * @param index + * subscript + * @return A JSONObject value. + * @throws JSONException + * If there is no value for the index or if the value is not a + * JSONObject + */ + public JSONObject getJSONObject(int index) throws JSONException { + Object object = this.get(index); + if (object instanceof JSONObject) { + return (JSONObject) object; + } + throw wrongValueFormatException(index, "JSONObject", null); + } + + /** + * Get the long value associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + * @throws JSONException + * If the key is not found or if the value cannot be converted + * to a number. + */ + public long getLong(int index) throws JSONException { + final Object object = this.get(index); + if(object instanceof Number) { + return ((Number)object).longValue(); + } + try { + return Long.parseLong(object.toString()); + } catch (Exception e) { + throw wrongValueFormatException(index, "long", e); + } + } + + /** + * Get the string associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return A string value. + * @throws JSONException + * If there is no string value for the index. + */ + public String getString(int index) throws JSONException { + Object object = this.get(index); + if (object instanceof String) { + return (String) object; + } + throw wrongValueFormatException(index, "String", null); + } + + /** + * Determine if the value is null. + * + * @param index + * The index must be between 0 and length() - 1. + * @return true if the value at the index is null, or if there is no value. + */ + public boolean isNull(int index) { + return JSONObject.NULL.equals(this.opt(index)); + } + + /** + * Make a string from the contents of this JSONArray. The + * separator string is inserted between each element. Warning: + * This method assumes that the data structure is acyclical. + * + * @param separator + * A string that will be inserted between the elements. + * @return a string. + * @throws JSONException + * If the array contains an invalid number. + */ + public String join(String separator) throws JSONException { + int len = this.length(); + if (len == 0) { + return ""; + } + + StringBuilder sb = new StringBuilder( + JSONObject.valueToString(this.myArrayList.get(0))); + + for (int i = 1; i < len; i++) { + sb.append(separator) + .append(JSONObject.valueToString(this.myArrayList.get(i))); + } + return sb.toString(); + } + + /** + * Get the number of elements in the JSONArray, included nulls. + * + * @return The length (or size). + */ + public int length() { + return this.myArrayList.size(); + } + + /** + * Removes all of the elements from this JSONArray. + * The JSONArray will be empty after this call returns. + */ + public void clear() { + this.myArrayList.clear(); + } + + /** + * Get the optional object value associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. If not, null is returned. + * @return An object value, or null if there is no object at that index. + */ + public Object opt(int index) { + return (index < 0 || index >= this.length()) ? null : this.myArrayList + .get(index); + } + + /** + * Get the optional boolean value associated with an index. It returns false + * if there is no value at that index, or if the value is not Boolean.TRUE + * or the String "true". + * + * @param index + * The index must be between 0 and length() - 1. + * @return The truth. + */ + public boolean optBoolean(int index) { + return this.optBoolean(index, false); + } + + /** + * Get the optional boolean value associated with an index. It returns the + * defaultValue if there is no value at that index or if it is not a Boolean + * or the String "true" or "false" (case insensitive). + * + * @param index + * The index must be between 0 and length() - 1. + * @param defaultValue + * A boolean default. + * @return The truth. + */ + public boolean optBoolean(int index, boolean defaultValue) { + try { + return this.getBoolean(index); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get the optional double value associated with an index. NaN is returned + * if there is no value for the index, or if the value is not a number and + * cannot be converted to a number. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + */ + public double optDouble(int index) { + return this.optDouble(index, Double.NaN); + } + + /** + * Get the optional double value associated with an index. The defaultValue + * is returned if there is no value for the index, or if the value is not a + * number and cannot be converted to a number. + * + * @param index + * subscript + * @param defaultValue + * The default value. + * @return The value. + */ + public double optDouble(int index, double defaultValue) { + final Number val = this.optNumber(index, null); + if (val == null) { + return defaultValue; + } + final double doubleValue = val.doubleValue(); + // if (Double.isNaN(doubleValue) || Double.isInfinite(doubleValue)) { + // return defaultValue; + // } + return doubleValue; + } + + /** + * Get the optional float value associated with an index. NaN is returned + * if there is no value for the index, or if the value is not a number and + * cannot be converted to a number. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + */ + public float optFloat(int index) { + return this.optFloat(index, Float.NaN); + } + + /** + * Get the optional float value associated with an index. The defaultValue + * is returned if there is no value for the index, or if the value is not a + * number and cannot be converted to a number. + * + * @param index + * subscript + * @param defaultValue + * The default value. + * @return The value. + */ + public float optFloat(int index, float defaultValue) { + final Number val = this.optNumber(index, null); + if (val == null) { + return defaultValue; + } + final float floatValue = val.floatValue(); + // if (Float.isNaN(floatValue) || Float.isInfinite(floatValue)) { + // return floatValue; + // } + return floatValue; + } + + /** + * Get the optional int value associated with an index. Zero is returned if + * there is no value for the index, or if the value is not a number and + * cannot be converted to a number. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + */ + public int optInt(int index) { + return this.optInt(index, 0); + } + + /** + * Get the optional int value associated with an index. The defaultValue is + * returned if there is no value for the index, or if the value is not a + * number and cannot be converted to a number. + * + * @param index + * The index must be between 0 and length() - 1. + * @param defaultValue + * The default value. + * @return The value. + */ + public int optInt(int index, int defaultValue) { + final Number val = this.optNumber(index, null); + if (val == null) { + return defaultValue; + } + return val.intValue(); + } + + /** + * Get the enum value associated with a key. + * + * @param + * Enum Type + * @param clazz + * The type of enum to retrieve. + * @param index + * The index must be between 0 and length() - 1. + * @return The enum value at the index location or null if not found + */ + public > E optEnum(Class clazz, int index) { + return this.optEnum(clazz, index, null); + } + + /** + * Get the enum value associated with a key. + * + * @param + * Enum Type + * @param clazz + * The type of enum to retrieve. + * @param index + * The index must be between 0 and length() - 1. + * @param defaultValue + * The default in case the value is not found + * @return The enum value at the index location or defaultValue if + * the value is not found or cannot be assigned to clazz + */ + public > E optEnum(Class clazz, int index, E defaultValue) { + try { + Object val = this.opt(index); + if (JSONObject.NULL.equals(val)) { + return defaultValue; + } + if (clazz.isAssignableFrom(val.getClass())) { + // we just checked it! + @SuppressWarnings("unchecked") + E myE = (E) val; + return myE; + } + return Enum.valueOf(clazz, val.toString()); + } catch (IllegalArgumentException e) { + return defaultValue; + } catch (NullPointerException e) { + return defaultValue; + } + } + + /** + * Get the optional BigInteger value associated with an index. The + * defaultValue is returned if there is no value for the index, or if the + * value is not a number and cannot be converted to a number. + * + * @param index + * The index must be between 0 and length() - 1. + * @param defaultValue + * The default value. + * @return The value. + */ + public BigInteger optBigInteger(int index, BigInteger defaultValue) { + Object val = this.opt(index); + return JSONObject.objectToBigInteger(val, defaultValue); + } + + /** + * Get the optional BigDecimal value associated with an index. The + * defaultValue is returned if there is no value for the index, or if the + * value is not a number and cannot be converted to a number. If the value + * is float or double, the {@link BigDecimal#BigDecimal(double)} + * constructor will be used. See notes on the constructor for conversion + * issues that may arise. + * + * @param index + * The index must be between 0 and length() - 1. + * @param defaultValue + * The default value. + * @return The value. + */ + public BigDecimal optBigDecimal(int index, BigDecimal defaultValue) { + Object val = this.opt(index); + return JSONObject.objectToBigDecimal(val, defaultValue); + } + + /** + * Get the optional JSONArray associated with an index. + * + * @param index + * subscript + * @return A JSONArray value, or null if the index has no value, or if the + * value is not a JSONArray. + */ + public JSONArray optJSONArray(int index) { + Object o = this.opt(index); + return o instanceof JSONArray ? (JSONArray) o : null; + } + + /** + * Get the optional JSONObject associated with an index. Null is returned if + * the key is not found, or null if the index has no value, or if the value + * is not a JSONObject. + * + * @param index + * The index must be between 0 and length() - 1. + * @return A JSONObject value. + */ + public JSONObject optJSONObject(int index) { + Object o = this.opt(index); + return o instanceof JSONObject ? (JSONObject) o : null; + } + + /** + * Get the optional long value associated with an index. Zero is returned if + * there is no value for the index, or if the value is not a number and + * cannot be converted to a number. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + */ + public long optLong(int index) { + return this.optLong(index, 0); + } + + /** + * Get the optional long value associated with an index. The defaultValue is + * returned if there is no value for the index, or if the value is not a + * number and cannot be converted to a number. + * + * @param index + * The index must be between 0 and length() - 1. + * @param defaultValue + * The default value. + * @return The value. + */ + public long optLong(int index, long defaultValue) { + final Number val = this.optNumber(index, null); + if (val == null) { + return defaultValue; + } + return val.longValue(); + } + + /** + * Get an optional {@link Number} value associated with a key, or null + * if there is no such key or if the value is not a number. If the value is a string, + * an attempt will be made to evaluate it as a number ({@link BigDecimal}). This method + * would be used in cases where type coercion of the number value is unwanted. + * + * @param index + * The index must be between 0 and length() - 1. + * @return An object which is the value. + */ + public Number optNumber(int index) { + return this.optNumber(index, null); + } + + /** + * Get an optional {@link Number} value associated with a key, or the default if there + * is no such key or if the value is not a number. If the value is a string, + * an attempt will be made to evaluate it as a number ({@link BigDecimal}). This method + * would be used in cases where type coercion of the number value is unwanted. + * + * @param index + * The index must be between 0 and length() - 1. + * @param defaultValue + * The default. + * @return An object which is the value. + */ + public Number optNumber(int index, Number defaultValue) { + Object val = this.opt(index); + if (JSONObject.NULL.equals(val)) { + return defaultValue; + } + if (val instanceof Number){ + return (Number) val; + } + + if (val instanceof String) { + try { + return JSONObject.stringToNumber((String) val); + } catch (Exception e) { + return defaultValue; + } + } + return defaultValue; + } + + /** + * Get the optional string value associated with an index. It returns an + * empty string if there is no value at that index. If the value is not a + * string and is not null, then it is converted to a string. + * + * @param index + * The index must be between 0 and length() - 1. + * @return A String value. + */ + public String optString(int index) { + return this.optString(index, ""); + } + + /** + * Get the optional string associated with an index. The defaultValue is + * returned if the key is not found. + * + * @param index + * The index must be between 0 and length() - 1. + * @param defaultValue + * The default value. + * @return A String value. + */ + public String optString(int index, String defaultValue) { + Object object = this.opt(index); + return JSONObject.NULL.equals(object) ? defaultValue : object + .toString(); + } + + /** + * Append a boolean value. This increases the array's length by one. + * + * @param value + * A boolean value. + * @return this. + */ + public JSONArray put(boolean value) { + return this.put(value ? Boolean.TRUE : Boolean.FALSE); + } + + /** + * Put a value in the JSONArray, where the value will be a JSONArray which + * is produced from a Collection. + * + * @param value + * A Collection value. + * @return this. + * @throws JSONException + * If the value is non-finite number. + */ + public JSONArray put(Collection value) { + return this.put(new JSONArray(value)); + } + + /** + * Append a double value. This increases the array's length by one. + * + * @param value + * A double value. + * @return this. + * @throws JSONException + * if the value is not finite. + */ + public JSONArray put(double value) throws JSONException { + return this.put(Double.valueOf(value)); + } + + /** + * Append a float value. This increases the array's length by one. + * + * @param value + * A float value. + * @return this. + * @throws JSONException + * if the value is not finite. + */ + public JSONArray put(float value) throws JSONException { + return this.put(Float.valueOf(value)); + } + + /** + * Append an int value. This increases the array's length by one. + * + * @param value + * An int value. + * @return this. + */ + public JSONArray put(int value) { + return this.put(Integer.valueOf(value)); + } + + /** + * Append an long value. This increases the array's length by one. + * + * @param value + * A long value. + * @return this. + */ + public JSONArray put(long value) { + return this.put(Long.valueOf(value)); + } + + /** + * Put a value in the JSONArray, where the value will be a JSONObject which + * is produced from a Map. + * + * @param value + * A Map value. + * @return this. + * @throws JSONException + * If a value in the map is non-finite number. + * @throws NullPointerException + * If a key in the map is null + */ + public JSONArray put(Map value) { + return this.put(new JSONObject(value)); + } + + /** + * Append an object value. This increases the array's length by one. + * + * @param value + * An object value. The value should be a Boolean, Double, + * Integer, JSONArray, JSONObject, Long, or String, or the + * JSONObject.NULL object. + * @return this. + * @throws JSONException + * If the value is non-finite number. + */ + public JSONArray put(Object value) { + JSONObject.testValidity(value); + this.myArrayList.add(value); + return this; + } + + /** + * Put or replace a boolean value in the JSONArray. If the index is greater + * than the length of the JSONArray, then null elements will be added as + * necessary to pad it out. + * + * @param index + * The subscript. + * @param value + * A boolean value. + * @return this. + * @throws JSONException + * If the index is negative. + */ + public JSONArray put(int index, boolean value) throws JSONException { + return this.put(index, value ? Boolean.TRUE : Boolean.FALSE); + } + + /** + * Put a value in the JSONArray, where the value will be a JSONArray which + * is produced from a Collection. + * + * @param index + * The subscript. + * @param value + * A Collection value. + * @return this. + * @throws JSONException + * If the index is negative or if the value is non-finite. + */ + public JSONArray put(int index, Collection value) throws JSONException { + return this.put(index, new JSONArray(value)); + } + + /** + * Put or replace a double value. If the index is greater than the length of + * the JSONArray, then null elements will be added as necessary to pad it + * out. + * + * @param index + * The subscript. + * @param value + * A double value. + * @return this. + * @throws JSONException + * If the index is negative or if the value is non-finite. + */ + public JSONArray put(int index, double value) throws JSONException { + return this.put(index, Double.valueOf(value)); + } + + /** + * Put or replace a float value. If the index is greater than the length of + * the JSONArray, then null elements will be added as necessary to pad it + * out. + * + * @param index + * The subscript. + * @param value + * A float value. + * @return this. + * @throws JSONException + * If the index is negative or if the value is non-finite. + */ + public JSONArray put(int index, float value) throws JSONException { + return this.put(index, Float.valueOf(value)); + } + + /** + * Put or replace an int value. If the index is greater than the length of + * the JSONArray, then null elements will be added as necessary to pad it + * out. + * + * @param index + * The subscript. + * @param value + * An int value. + * @return this. + * @throws JSONException + * If the index is negative. + */ + public JSONArray put(int index, int value) throws JSONException { + return this.put(index, Integer.valueOf(value)); + } + + /** + * Put or replace a long value. If the index is greater than the length of + * the JSONArray, then null elements will be added as necessary to pad it + * out. + * + * @param index + * The subscript. + * @param value + * A long value. + * @return this. + * @throws JSONException + * If the index is negative. + */ + public JSONArray put(int index, long value) throws JSONException { + return this.put(index, Long.valueOf(value)); + } + + /** + * Put a value in the JSONArray, where the value will be a JSONObject that + * is produced from a Map. + * + * @param index + * The subscript. + * @param value + * The Map value. + * @return this. + * @throws JSONException + * If the index is negative or if the value is an invalid + * number. + * @throws NullPointerException + * If a key in the map is null + */ + public JSONArray put(int index, Map value) throws JSONException { + this.put(index, new JSONObject(value)); + return this; + } + + /** + * Put or replace an object value in the JSONArray. If the index is greater + * than the length of the JSONArray, then null elements will be added as + * necessary to pad it out. + * + * @param index + * The subscript. + * @param value + * The value to put into the array. The value should be a + * Boolean, Double, Integer, JSONArray, JSONObject, Long, or + * String, or the JSONObject.NULL object. + * @return this. + * @throws JSONException + * If the index is negative or if the value is an invalid + * number. + */ + public JSONArray put(int index, Object value) throws JSONException { + if (index < 0) { + throw new JSONException("JSONArray[" + index + "] not found."); + } + if (index < this.length()) { + JSONObject.testValidity(value); + this.myArrayList.set(index, value); + return this; + } + if(index == this.length()){ + // simple append + return this.put(value); + } + // if we are inserting past the length, we want to grow the array all at once + // instead of incrementally. + this.myArrayList.ensureCapacity(index + 1); + while (index != this.length()) { + // we don't need to test validity of NULL objects + this.myArrayList.add(JSONObject.NULL); + } + return this.put(value); + } + + /** + * Put a collection's elements in to the JSONArray. + * + * @param collection + * A Collection. + * @return this. + */ + public JSONArray putAll(Collection collection) { + this.addAll(collection, false); + return this; + } + + /** + * Put an Iterable's elements in to the JSONArray. + * + * @param iter + * An Iterable. + * @return this. + */ + public JSONArray putAll(Iterable iter) { + this.addAll(iter, false); + return this; + } + + /** + * Put a JSONArray's elements in to the JSONArray. + * + * @param array + * A JSONArray. + * @return this. + */ + public JSONArray putAll(JSONArray array) { + // directly copy the elements from the source array to this one + // as all wrapping should have been done already in the source. + this.myArrayList.addAll(array.myArrayList); + return this; + } + + /** + * Put an array's elements in to the JSONArray. + * + * @param array + * Array. If the parameter passed is null, or not an array or Iterable, an + * exception will be thrown. + * @return this. + * + * @throws JSONException + * If not an array, JSONArray, Iterable or if an value is non-finite number. + * @throws NullPointerException + * Thrown if the array parameter is null. + */ + public JSONArray putAll(Object array) throws JSONException { + this.addAll(array, false); + return this; + } + + /** + * Creates a JSONPointer using an initialization string and tries to + * match it to an item within this JSONArray. For example, given a + * JSONArray initialized with this document: + *
+     * [
+     *     {"b":"c"}
+     * ]
+     * 
+ * and this JSONPointer string: + *
+     * "/0/b"
+     * 
+ * Then this method will return the String "c" + * A JSONPointerException may be thrown from code called by this method. + * + * @param jsonPointer string that can be used to create a JSONPointer + * @return the item matched by the JSONPointer, otherwise null + */ + public Object query(String jsonPointer) { + return query(new JSONPointer(jsonPointer)); + } + + /** + * Uses a user initialized JSONPointer and tries to + * match it to an item within this JSONArray. For example, given a + * JSONArray initialized with this document: + *
+     * [
+     *     {"b":"c"}
+     * ]
+     * 
+ * and this JSONPointer: + *
+     * "/0/b"
+     * 
+ * Then this method will return the String "c" + * A JSONPointerException may be thrown from code called by this method. + * + * @param jsonPointer string that can be used to create a JSONPointer + * @return the item matched by the JSONPointer, otherwise null + */ + public Object query(JSONPointer jsonPointer) { + return jsonPointer.queryFrom(this); + } + + /** + * Queries and returns a value from this object using {@code jsonPointer}, or + * returns null if the query fails due to a missing key. + * + * @param jsonPointer the string representation of the JSON pointer + * @return the queried value or {@code null} + * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax + */ + public Object optQuery(String jsonPointer) { + return optQuery(new JSONPointer(jsonPointer)); + } + + /** + * Queries and returns a value from this object using {@code jsonPointer}, or + * returns null if the query fails due to a missing key. + * + * @param jsonPointer The JSON pointer + * @return the queried value or {@code null} + * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax + */ + public Object optQuery(JSONPointer jsonPointer) { + try { + return jsonPointer.queryFrom(this); + } catch (JSONPointerException e) { + return null; + } + } + + /** + * Remove an index and close the hole. + * + * @param index + * The index of the element to be removed. + * @return The value that was associated with the index, or null if there + * was no value. + */ + public Object remove(int index) { + return index >= 0 && index < this.length() + ? this.myArrayList.remove(index) + : null; + } + + /** + * Determine if two JSONArrays are similar. + * They must contain similar sequences. + * + * @param other The other JSONArray + * @return true if they are equal + */ + public boolean similar(Object other) { + if (!(other instanceof JSONArray)) { + return false; + } + int len = this.length(); + if (len != ((JSONArray)other).length()) { + return false; + } + for (int i = 0; i < len; i += 1) { + Object valueThis = this.myArrayList.get(i); + Object valueOther = ((JSONArray)other).myArrayList.get(i); + if(valueThis == valueOther) { + continue; + } + if(valueThis == null) { + return false; + } + if (valueThis instanceof JSONObject) { + if (!((JSONObject)valueThis).similar(valueOther)) { + return false; + } + } else if (valueThis instanceof JSONArray) { + if (!((JSONArray)valueThis).similar(valueOther)) { + return false; + } + } else if (valueThis instanceof Number && valueOther instanceof Number) { + if (!JSONObject.isNumberSimilar((Number)valueThis, (Number)valueOther)) { + return false; + } + } else if (!valueThis.equals(valueOther)) { + return false; + } + } + return true; + } + + /** + * Produce a JSONObject by combining a JSONArray of names with the values of + * this JSONArray. + * + * @param names + * A JSONArray containing a list of key strings. These will be + * paired with the values. + * @return A JSONObject, or null if there are no names or if this JSONArray + * has no values. + * @throws JSONException + * If any of the names are null. + */ + public JSONObject toJSONObject(JSONArray names) throws JSONException { + if (names == null || names.isEmpty() || this.isEmpty()) { + return null; + } + JSONObject jo = new JSONObject(names.length()); + for (int i = 0; i < names.length(); i += 1) { + jo.put(names.getString(i), this.opt(i)); + } + return jo; + } + + /** + * Make a JSON text of this JSONArray. For compactness, no unnecessary + * whitespace is added. If it is not possible to produce a syntactically + * correct JSON text then null will be returned instead. This could occur if + * the array contains an invalid number. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * + * @return a printable, displayable, transmittable representation of the + * array. + */ + @Override + public String toString() { + try { + return this.toString(0); + } catch (Exception e) { + return null; + } + } + + /** + * Make a pretty-printed JSON text of this JSONArray. + * + *

If

 {@code indentFactor > 0}
and the {@link JSONArray} has only + * one element, then the array will be output on a single line: + *
{@code [1]}
+ * + *

If an array has 2 or more elements, then it will be output across + * multiple lines:

{@code
+     * [
+     * 1,
+     * "value 2",
+     * 3
+     * ]
+     * }
+ *

+ * Warning: This method assumes that the data structure is acyclical. + * + * + * @param indentFactor + * The number of spaces to add to each level of indentation. + * @return a printable, displayable, transmittable representation of the + * object, beginning with [ (left + * bracket) and ending with ] + *  (right bracket). + * @throws JSONException if a called function fails + */ + public String toString(int indentFactor) throws JSONException { + StringWriter sw = new StringWriter(); + synchronized (sw.getBuffer()) { + return this.write(sw, indentFactor, 0).toString(); + } + } + + /** + * Write the contents of the JSONArray as JSON text to a writer. For + * compactness, no whitespace is added. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @param writer the writer object + * @return The writer. + * @throws JSONException if a called function fails + */ + public Writer write(Writer writer) throws JSONException { + return this.write(writer, 0, 0); + } + + /** + * Write the contents of the JSONArray as JSON text to a writer. + * + *

If

{@code indentFactor > 0}
and the {@link JSONArray} has only + * one element, then the array will be output on a single line: + *
{@code [1]}
+ * + *

If an array has 2 or more elements, then it will be output across + * multiple lines:

{@code
+     * [
+     * 1,
+     * "value 2",
+     * 3
+     * ]
+     * }
+ *

+ * Warning: This method assumes that the data structure is acyclical. + * + * + * @param writer + * Writes the serialized JSON + * @param indentFactor + * The number of spaces to add to each level of indentation. + * @param indent + * The indentation of the top level. + * @return The writer. + * @throws JSONException if a called function fails or unable to write + */ + public Writer write(Writer writer, int indentFactor, int indent) + throws JSONException { + try { + boolean needsComma = false; + int length = this.length(); + writer.write('['); + + if (length == 1) { + try { + JSONObject.writeValue(writer, this.myArrayList.get(0), + indentFactor, indent); + } catch (Exception e) { + throw new JSONException("Unable to write JSONArray value at index: 0", e); + } + } else if (length != 0) { + final int newIndent = indent + indentFactor; + + for (int i = 0; i < length; i += 1) { + if (needsComma) { + writer.write(','); + } + if (indentFactor > 0) { + writer.write('\n'); + } + JSONObject.indent(writer, newIndent); + try { + JSONObject.writeValue(writer, this.myArrayList.get(i), + indentFactor, newIndent); + } catch (Exception e) { + throw new JSONException("Unable to write JSONArray value at index: " + i, e); + } + needsComma = true; + } + if (indentFactor > 0) { + writer.write('\n'); + } + JSONObject.indent(writer, indent); + } + writer.write(']'); + return writer; + } catch (IOException e) { + throw new JSONException(e); + } + } + + /** + * Returns a java.util.List containing all of the elements in this array. + * If an element in the array is a JSONArray or JSONObject it will also + * be converted to a List and a Map respectively. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @return a java.util.List containing the elements of this array + */ + public List toList() { + List results = new ArrayList(this.myArrayList.size()); + for (Object element : this.myArrayList) { + if (element == null || JSONObject.NULL.equals(element)) { + results.add(null); + } else if (element instanceof JSONArray) { + results.add(((JSONArray) element).toList()); + } else if (element instanceof JSONObject) { + results.add(((JSONObject) element).toMap()); + } else { + results.add(element); + } + } + return results; + } + + /** + * Check if JSONArray is empty. + * + * @return true if JSONArray is empty, otherwise false. + */ + public boolean isEmpty() { + return this.myArrayList.isEmpty(); + } + + /** + * Add a collection's elements to the JSONArray. + * + * @param collection + * A Collection. + * @param wrap + * {@code true} to call {@link JSONObject#wrap(Object)} for each item, + * {@code false} to add the items directly + * + */ + private void addAll(Collection collection, boolean wrap) { + this.myArrayList.ensureCapacity(this.myArrayList.size() + collection.size()); + if (wrap) { + for (Object o: collection){ + this.put(JSONObject.wrap(o)); + } + } else { + for (Object o: collection){ + this.put(o); + } + } + } + + /** + * Add an Iterable's elements to the JSONArray. + * + * @param iter + * An Iterable. + * @param wrap + * {@code true} to call {@link JSONObject#wrap(Object)} for each item, + * {@code false} to add the items directly + */ + private void addAll(Iterable iter, boolean wrap) { + if (wrap) { + for (Object o: iter){ + this.put(JSONObject.wrap(o)); + } + } else { + for (Object o: iter){ + this.put(o); + } + } + } + + /** + * Add an array's elements to the JSONArray. + * + * @param array + * Array. If the parameter passed is null, or not an array, + * JSONArray, Collection, or Iterable, an exception will be + * thrown. + * @param wrap + * {@code true} to call {@link JSONObject#wrap(Object)} for each item, + * {@code false} to add the items directly + * + * @throws JSONException + * If not an array or if an array value is non-finite number. + * @throws NullPointerException + * Thrown if the array parameter is null. + */ + private void addAll(Object array, boolean wrap) throws JSONException { + if (array.getClass().isArray()) { + int length = Array.getLength(array); + this.myArrayList.ensureCapacity(this.myArrayList.size() + length); + if (wrap) { + for (int i = 0; i < length; i += 1) { + this.put(JSONObject.wrap(Array.get(array, i))); + } + } else { + for (int i = 0; i < length; i += 1) { + this.put(Array.get(array, i)); + } + } + } else if (array instanceof JSONArray) { + // use the built in array list `addAll` as all object + // wrapping should have been completed in the original + // JSONArray + this.myArrayList.addAll(((JSONArray)array).myArrayList); + } else if (array instanceof Collection) { + this.addAll((Collection)array, wrap); + } else if (array instanceof Iterable) { + this.addAll((Iterable)array, wrap); + } else { + throw new JSONException( + "JSONArray initial value should be a string or collection or array."); + } + } + + /** + * Create a new JSONException in a common format for incorrect conversions. + * @param idx index of the item + * @param valueType the type of value being coerced to + * @param cause optional cause of the coercion failure + * @return JSONException that can be thrown. + */ + private static JSONException wrongValueFormatException( + int idx, + String valueType, + Throwable cause) { + return new JSONException( + "JSONArray[" + idx + "] is not a " + valueType + "." + , cause); + } + + /** + * Create a new JSONException in a common format for incorrect conversions. + * @param idx index of the item + * @param valueType the type of value being coerced to + * @param cause optional cause of the coercion failure + * @return JSONException that can be thrown. + */ + private static JSONException wrongValueFormatException( + int idx, + String valueType, + Object value, + Throwable cause) { + return new JSONException( + "JSONArray[" + idx + "] is not a " + valueType + " (" + value + ")." + , cause); + } + +} diff --git a/src/main/java/org/json/JSONException.java b/src/main/java/org/json/JSONException.java new file mode 100644 index 0000000..ab7ff77 --- /dev/null +++ b/src/main/java/org/json/JSONException.java @@ -0,0 +1,69 @@ +package org.json; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ + +/** + * The JSONException is thrown by the JSON.org classes when things are amiss. + * + * @author JSON.org + * @version 2015-12-09 + */ +public class JSONException extends RuntimeException { + /** Serialization ID */ + private static final long serialVersionUID = 0; + + /** + * Constructs a JSONException with an explanatory message. + * + * @param message + * Detail about the reason for the exception. + */ + public JSONException(final String message) { + super(message); + } + + /** + * Constructs a JSONException with an explanatory message and cause. + * + * @param message + * Detail about the reason for the exception. + * @param cause + * The cause. + */ + public JSONException(final String message, final Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new JSONException with the specified cause. + * + * @param cause + * The cause. + */ + public JSONException(final Throwable cause) { + super(cause.getMessage(), cause); + } + +} diff --git a/src/main/java/org/json/JSONML.java b/src/main/java/org/json/JSONML.java new file mode 100644 index 0000000..aafdf72 --- /dev/null +++ b/src/main/java/org/json/JSONML.java @@ -0,0 +1,542 @@ +package org.json; + +/* +Copyright (c) 2008 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +/** + * This provides static methods to convert an XML text into a JSONArray or + * JSONObject, and to covert a JSONArray or JSONObject into an XML text using + * the JsonML transform. + * + * @author JSON.org + * @version 2016-01-30 + */ +public class JSONML { + /** + * Parse XML values and store them in a JSONArray. + * @param x The XMLTokener containing the source string. + * @param arrayForm true if array form, false if object form. + * @param ja The JSONArray that is containing the current tag or null + * if we are at the outermost level. + * @param keepStrings Don't type-convert text nodes and attribute values + * @return A JSONArray if the value is the outermost tag, otherwise null. + * @throws JSONException if a parsing error occurs + */ + private static Object parse( + XMLTokener x, + boolean arrayForm, + JSONArray ja, + boolean keepStrings + ) throws JSONException { + String attribute; + char c; + String closeTag = null; + int i; + JSONArray newja = null; + JSONObject newjo = null; + Object token; + String tagName = null; + +// Test for and skip past these forms: +// +// +// +// + + while (true) { + if (!x.more()) { + throw x.syntaxError("Bad XML"); + } + token = x.nextContent(); + if (token == XML.LT) { + token = x.nextToken(); + if (token instanceof Character) { + if (token == XML.SLASH) { + +// Close tag "); + } else { + x.back(); + } + } else if (c == '[') { + token = x.nextToken(); + if (token.equals("CDATA") && x.next() == '[') { + if (ja != null) { + ja.put(x.nextCDATA()); + } + } else { + throw x.syntaxError("Expected 'CDATA['"); + } + } else { + i = 1; + do { + token = x.nextMeta(); + if (token == null) { + throw x.syntaxError("Missing '>' after ' 0); + } + } else if (token == XML.QUEST) { + +// "); + } else { + throw x.syntaxError("Misshaped tag"); + } + +// Open tag < + + } else { + if (!(token instanceof String)) { + throw x.syntaxError("Bad tagName '" + token + "'."); + } + tagName = (String)token; + newja = new JSONArray(); + newjo = new JSONObject(); + if (arrayForm) { + newja.put(tagName); + if (ja != null) { + ja.put(newja); + } + } else { + newjo.put("tagName", tagName); + if (ja != null) { + ja.put(newjo); + } + } + token = null; + for (;;) { + if (token == null) { + token = x.nextToken(); + } + if (token == null) { + throw x.syntaxError("Misshaped tag"); + } + if (!(token instanceof String)) { + break; + } + +// attribute = value + + attribute = (String)token; + if (!arrayForm && ("tagName".equals(attribute) || "childNode".equals(attribute))) { + throw x.syntaxError("Reserved attribute."); + } + token = x.nextToken(); + if (token == XML.EQ) { + token = x.nextToken(); + if (!(token instanceof String)) { + throw x.syntaxError("Missing value"); + } + newjo.accumulate(attribute, keepStrings ? ((String)token) :XML.stringToValue((String)token)); + token = null; + } else { + newjo.accumulate(attribute, ""); + } + } + if (arrayForm && newjo.length() > 0) { + newja.put(newjo); + } + +// Empty tag <.../> + + if (token == XML.SLASH) { + if (x.nextToken() != XML.GT) { + throw x.syntaxError("Misshaped tag"); + } + if (ja == null) { + if (arrayForm) { + return newja; + } + return newjo; + } + +// Content, between <...> and + + } else { + if (token != XML.GT) { + throw x.syntaxError("Misshaped tag"); + } + closeTag = (String)parse(x, arrayForm, newja, keepStrings); + if (closeTag != null) { + if (!closeTag.equals(tagName)) { + throw x.syntaxError("Mismatched '" + tagName + + "' and '" + closeTag + "'"); + } + tagName = null; + if (!arrayForm && newja.length() > 0) { + newjo.put("childNodes", newja); + } + if (ja == null) { + if (arrayForm) { + return newja; + } + return newjo; + } + } + } + } + } else { + if (ja != null) { + ja.put(token instanceof String + ? keepStrings ? XML.unescape((String)token) :XML.stringToValue((String)token) + : token); + } + } + } + } + + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONArray using the JsonML transform. Each XML tag is represented as + * a JSONArray in which the first element is the tag name. If the tag has + * attributes, then the second element will be JSONObject containing the + * name/value pairs. If the tag contains children, then strings and + * JSONArrays will represent the child tags. + * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. + * @param string The source string. + * @return A JSONArray containing the structured data from the XML string. + * @throws JSONException Thrown on error converting to a JSONArray + */ + public static JSONArray toJSONArray(String string) throws JSONException { + return (JSONArray)parse(new XMLTokener(string), true, null, false); + } + + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONArray using the JsonML transform. Each XML tag is represented as + * a JSONArray in which the first element is the tag name. If the tag has + * attributes, then the second element will be JSONObject containing the + * name/value pairs. If the tag contains children, then strings and + * JSONArrays will represent the child tags. + * As opposed to toJSONArray this method does not attempt to convert + * any text node or attribute value to any type + * but just leaves it as a string. + * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. + * @param string The source string. + * @param keepStrings If true, then values will not be coerced into boolean + * or numeric values and will instead be left as strings + * @return A JSONArray containing the structured data from the XML string. + * @throws JSONException Thrown on error converting to a JSONArray + */ + public static JSONArray toJSONArray(String string, boolean keepStrings) throws JSONException { + return (JSONArray)parse(new XMLTokener(string), true, null, keepStrings); + } + + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONArray using the JsonML transform. Each XML tag is represented as + * a JSONArray in which the first element is the tag name. If the tag has + * attributes, then the second element will be JSONObject containing the + * name/value pairs. If the tag contains children, then strings and + * JSONArrays will represent the child content and tags. + * As opposed to toJSONArray this method does not attempt to convert + * any text node or attribute value to any type + * but just leaves it as a string. + * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. + * @param x An XMLTokener. + * @param keepStrings If true, then values will not be coerced into boolean + * or numeric values and will instead be left as strings + * @return A JSONArray containing the structured data from the XML string. + * @throws JSONException Thrown on error converting to a JSONArray + */ + public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JSONException { + return (JSONArray)parse(x, true, null, keepStrings); + } + + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONArray using the JsonML transform. Each XML tag is represented as + * a JSONArray in which the first element is the tag name. If the tag has + * attributes, then the second element will be JSONObject containing the + * name/value pairs. If the tag contains children, then strings and + * JSONArrays will represent the child content and tags. + * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. + * @param x An XMLTokener. + * @return A JSONArray containing the structured data from the XML string. + * @throws JSONException Thrown on error converting to a JSONArray + */ + public static JSONArray toJSONArray(XMLTokener x) throws JSONException { + return (JSONArray)parse(x, true, null, false); + } + + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONObject using the JsonML transform. Each XML tag is represented as + * a JSONObject with a "tagName" property. If the tag has attributes, then + * the attributes will be in the JSONObject as properties. If the tag + * contains children, the object will have a "childNodes" property which + * will be an array of strings and JsonML JSONObjects. + + * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. + * @param string The XML source text. + * @return A JSONObject containing the structured data from the XML string. + * @throws JSONException Thrown on error converting to a JSONObject + */ + public static JSONObject toJSONObject(String string) throws JSONException { + return (JSONObject)parse(new XMLTokener(string), false, null, false); + } + + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONObject using the JsonML transform. Each XML tag is represented as + * a JSONObject with a "tagName" property. If the tag has attributes, then + * the attributes will be in the JSONObject as properties. If the tag + * contains children, the object will have a "childNodes" property which + * will be an array of strings and JsonML JSONObjects. + + * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. + * @param string The XML source text. + * @param keepStrings If true, then values will not be coerced into boolean + * or numeric values and will instead be left as strings + * @return A JSONObject containing the structured data from the XML string. + * @throws JSONException Thrown on error converting to a JSONObject + */ + public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { + return (JSONObject)parse(new XMLTokener(string), false, null, keepStrings); + } + + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONObject using the JsonML transform. Each XML tag is represented as + * a JSONObject with a "tagName" property. If the tag has attributes, then + * the attributes will be in the JSONObject as properties. If the tag + * contains children, the object will have a "childNodes" property which + * will be an array of strings and JsonML JSONObjects. + + * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. + * @param x An XMLTokener of the XML source text. + * @return A JSONObject containing the structured data from the XML string. + * @throws JSONException Thrown on error converting to a JSONObject + */ + public static JSONObject toJSONObject(XMLTokener x) throws JSONException { + return (JSONObject)parse(x, false, null, false); + } + + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONObject using the JsonML transform. Each XML tag is represented as + * a JSONObject with a "tagName" property. If the tag has attributes, then + * the attributes will be in the JSONObject as properties. If the tag + * contains children, the object will have a "childNodes" property which + * will be an array of strings and JsonML JSONObjects. + + * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. + * @param x An XMLTokener of the XML source text. + * @param keepStrings If true, then values will not be coerced into boolean + * or numeric values and will instead be left as strings + * @return A JSONObject containing the structured data from the XML string. + * @throws JSONException Thrown on error converting to a JSONObject + */ + public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws JSONException { + return (JSONObject)parse(x, false, null, keepStrings); + } + + + /** + * Reverse the JSONML transformation, making an XML text from a JSONArray. + * @param ja A JSONArray. + * @return An XML string. + * @throws JSONException Thrown on error converting to a string + */ + public static String toString(JSONArray ja) throws JSONException { + int i; + JSONObject jo; + int length; + Object object; + StringBuilder sb = new StringBuilder(); + String tagName; + +// Emit = length) { + sb.append('/'); + sb.append('>'); + } else { + sb.append('>'); + do { + object = ja.get(i); + i += 1; + if (object != null) { + if (object instanceof String) { + sb.append(XML.escape(object.toString())); + } else if (object instanceof JSONObject) { + sb.append(toString((JSONObject)object)); + } else if (object instanceof JSONArray) { + sb.append(toString((JSONArray)object)); + } else { + sb.append(object.toString()); + } + } + } while (i < length); + sb.append('<'); + sb.append('/'); + sb.append(tagName); + sb.append('>'); + } + return sb.toString(); + } + + /** + * Reverse the JSONML transformation, making an XML text from a JSONObject. + * The JSONObject must contain a "tagName" property. If it has children, + * then it must have a "childNodes" property containing an array of objects. + * The other properties are attributes with string values. + * @param jo A JSONObject. + * @return An XML string. + * @throws JSONException Thrown on error converting to a string + */ + public static String toString(JSONObject jo) throws JSONException { + StringBuilder sb = new StringBuilder(); + int i; + JSONArray ja; + int length; + Object object; + String tagName; + Object value; + +//Emit '); + } else { + sb.append('>'); + length = ja.length(); + for (i = 0; i < length; i += 1) { + object = ja.get(i); + if (object != null) { + if (object instanceof String) { + sb.append(XML.escape(object.toString())); + } else if (object instanceof JSONObject) { + sb.append(toString((JSONObject)object)); + } else if (object instanceof JSONArray) { + sb.append(toString((JSONArray)object)); + } else { + sb.append(object.toString()); + } + } + } + sb.append('<'); + sb.append('/'); + sb.append(tagName); + sb.append('>'); + } + return sb.toString(); + } +} diff --git a/src/main/java/org/json/JSONObject.java b/src/main/java/org/json/JSONObject.java new file mode 100644 index 0000000..5c37249 --- /dev/null +++ b/src/main/java/org/json/JSONObject.java @@ -0,0 +1,2732 @@ +package org.json; + +import java.io.Closeable; + +/* + Copyright (c) 2002 JSON.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + The Software shall be used for Good, not Evil. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.regex.Pattern; + +/** + * A JSONObject is an unordered collection of name/value pairs. Its external + * form is a string wrapped in curly braces with colons between the names and + * values, and commas between the values and names. The internal form is an + * object having get and opt methods for accessing + * the values by name, and put methods for adding or replacing + * values by name. The values can be any of these types: Boolean, + * JSONArray, JSONObject, Number, + * String, or the JSONObject.NULL object. A + * JSONObject constructor can be used to convert an external form JSON text + * into an internal form whose values can be retrieved with the + * get and opt methods, or to convert values into a + * JSON text using the put and toString methods. A + * get method returns a value if one can be found, and throws an + * exception if one cannot be found. An opt method returns a + * default value instead of throwing an exception, and so is useful for + * obtaining optional values. + *

+ * The generic get() and opt() methods return an + * object, which you can cast or query for type. There are also typed + * get and opt methods that do type checking and type + * coercion for you. The opt methods differ from the get methods in that they + * do not throw. Instead, they return a specified value, such as null. + *

+ * The put methods add or replace values in an object. For + * example, + * + *

+ * myString = new JSONObject()
+ *         .put("JSON", "Hello, World!").toString();
+ * 
+ * + * produces the string {"JSON": "Hello, World"}. + *

+ * The texts produced by the toString methods strictly conform to + * the JSON syntax rules. The constructors are more forgiving in the texts they + * will accept: + *

    + *
  • An extra , (comma) may appear just + * before the closing brace.
  • + *
  • Strings may be quoted with ' (single + * quote).
  • + *
  • Strings do not need to be quoted at all if they do not begin with a + * quote or single quote, and if they do not contain leading or trailing + * spaces, and if they do not contain any of these characters: + * { } [ ] / \ : , # and if they do not look like numbers and + * if they are not the reserved words true, false, + * or null.
  • + *
+ * + * @author JSON.org + * @version 2016-08-15 + */ +public class JSONObject { + /** + * JSONObject.NULL is equivalent to the value that JavaScript calls null, + * whilst Java's null is equivalent to the value that JavaScript calls + * undefined. + */ + private static final class Null { + + /** + * There is only intended to be a single instance of the NULL object, + * so the clone method returns itself. + * + * @return NULL. + */ + @Override + protected final Object clone() { + return this; + } + + /** + * A Null object is equal to the null value and to itself. + * + * @param object + * An object to test for nullness. + * @return true if the object parameter is the JSONObject.NULL object or + * null. + */ + @Override + @SuppressWarnings("lgtm[java/unchecked-cast-in-equals]") + public boolean equals(Object object) { + return object == null || object == this; + } + /** + * A Null object is equal to the null value and to itself. + * + * @return always returns 0. + */ + @Override + public int hashCode() { + return 0; + } + + /** + * Get the "null" string value. + * + * @return The string "null". + */ + @Override + public String toString() { + return "null"; + } + } + + /** + * Regular Expression Pattern that matches JSON Numbers. This is primarily used for + * output to guarantee that we are always writing valid JSON. + */ + static final Pattern NUMBER_PATTERN = Pattern.compile("-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?"); + + /** + * The map where the JSONObject's properties are kept. + */ + private final Map map; + + /** + * It is sometimes more convenient and less ambiguous to have a + * NULL object than to use Java's null value. + * JSONObject.NULL.equals(null) returns true. + * JSONObject.NULL.toString() returns "null". + */ + public static final Object NULL = new Null(); + + /** + * Construct an empty JSONObject. + */ + public JSONObject() { + // HashMap is used on purpose to ensure that elements are unordered by + // the specification. + // JSON tends to be a portable transfer format to allows the container + // implementations to rearrange their items for a faster element + // retrieval based on associative access. + // Therefore, an implementation mustn't rely on the order of the item. + this.map = new HashMap(); + } + + /** + * Construct a JSONObject from a subset of another JSONObject. An array of + * strings is used to identify the keys that should be copied. Missing keys + * are ignored. + * + * @param jo + * A JSONObject. + * @param names + * An array of strings. + */ + public JSONObject(JSONObject jo, String ... names) { + this(names.length); + for (int i = 0; i < names.length; i += 1) { + try { + this.putOnce(names[i], jo.opt(names[i])); + } catch (Exception ignore) { + } + } + } + + /** + * Construct a JSONObject from a JSONTokener. + * + * @param x + * A JSONTokener object containing the source string. + * @throws JSONException + * If there is a syntax error in the source string or a + * duplicated key. + */ + public JSONObject(JSONTokener x) throws JSONException { + this(); + char c; + String key; + + if (x.nextClean() != '{') { + throw x.syntaxError("A JSONObject text must begin with '{'"); + } + for (;;) { + char prev = x.getPrevious(); + c = x.nextClean(); + switch (c) { + case 0: + throw x.syntaxError("A JSONObject text must end with '}'"); + case '}': + return; + case '{': + case '[': + if(prev=='{') { + throw x.syntaxError("A JSON Object can not directly nest another JSON Object or JSON Array."); + } + // fall through + default: + x.back(); + key = x.nextValue().toString(); + } + + // The key is followed by ':'. + + c = x.nextClean(); + if (c != ':') { + throw x.syntaxError("Expected a ':' after a key"); + } + + // Use syntaxError(..) to include error location + + if (key != null) { + // Check if key exists + if (this.opt(key) != null) { + // key already exists + throw x.syntaxError("Duplicate key \"" + key + "\""); + } + // Only add value if non-null + Object value = x.nextValue(); + if (value!=null) { + this.put(key, value); + } + } + + // Pairs are separated by ','. + + switch (x.nextClean()) { + case ';': + case ',': + if (x.nextClean() == '}') { + return; + } + x.back(); + break; + case '}': + return; + default: + throw x.syntaxError("Expected a ',' or '}'"); + } + } + } + + /** + * Construct a JSONObject from a Map. + * + * @param m + * A map object that can be used to initialize the contents of + * the JSONObject. + * @throws JSONException + * If a value in the map is non-finite number. + * @throws NullPointerException + * If a key in the map is null + */ + public JSONObject(Map m) { + if (m == null) { + this.map = new HashMap(); + } else { + this.map = new HashMap(m.size()); + for (final Entry e : m.entrySet()) { + if(e.getKey() == null) { + throw new NullPointerException("Null key."); + } + final Object value = e.getValue(); + if (value != null) { + this.map.put(String.valueOf(e.getKey()), wrap(value)); + } + } + } + } + + /** + * Construct a JSONObject from an Object using bean getters. It reflects on + * all of the public methods of the object. For each of the methods with no + * parameters and a name starting with "get" or + * "is" followed by an uppercase letter, the method is invoked, + * and a key and the value returned from the getter method are put into the + * new JSONObject. + *

+ * The key is formed by removing the "get" or "is" + * prefix. If the second remaining character is not upper case, then the + * first character is converted to lower case. + *

+ * Methods that are static, return void, + * have parameters, or are "bridge" methods, are ignored. + *

+ * For example, if an object has a method named "getName", and + * if the result of calling object.getName() is + * "Larry Fine", then the JSONObject will contain + * "name": "Larry Fine". + *

+ * The {@link JSONPropertyName} annotation can be used on a bean getter to + * override key name used in the JSONObject. For example, using the object + * above with the getName method, if we annotated it with: + *

+     * @JSONPropertyName("FullName")
+     * public String getName() { return this.name; }
+     * 
+ * The resulting JSON object would contain "FullName": "Larry Fine" + *

+ * Similarly, the {@link JSONPropertyName} annotation can be used on non- + * get and is methods. We can also override key + * name used in the JSONObject as seen below even though the field would normally + * be ignored: + *

+     * @JSONPropertyName("FullName")
+     * public String fullName() { return this.name; }
+     * 
+ * The resulting JSON object would contain "FullName": "Larry Fine" + *

+ * The {@link JSONPropertyIgnore} annotation can be used to force the bean property + * to not be serialized into JSON. If both {@link JSONPropertyIgnore} and + * {@link JSONPropertyName} are defined on the same method, a depth comparison is + * performed and the one closest to the concrete class being serialized is used. + * If both annotations are at the same level, then the {@link JSONPropertyIgnore} + * annotation takes precedent and the field is not serialized. + * For example, the following declaration would prevent the getName + * method from being serialized: + *

+     * @JSONPropertyName("FullName")
+     * @JSONPropertyIgnore
+     * public String getName() { return this.name; }
+     * 
+ *

+ * + * @param bean + * An object that has getter methods that should be used to make + * a JSONObject. + */ + public JSONObject(Object bean) { + this(); + this.populateMap(bean); + } + + private JSONObject(Object bean, Set objectsRecord) { + this(); + this.populateMap(bean, objectsRecord); + } + + /** + * Construct a JSONObject from an Object, using reflection to find the + * public members. The resulting JSONObject's keys will be the strings from + * the names array, and the values will be the field values associated with + * those keys in the object. If a key is not found or not visible, then it + * will not be copied into the new JSONObject. + * + * @param object + * An object that has fields that should be used to make a + * JSONObject. + * @param names + * An array of strings, the names of the fields to be obtained + * from the object. + */ + public JSONObject(Object object, String ... names) { + this(names.length); + Class c = object.getClass(); + for (int i = 0; i < names.length; i += 1) { + String name = names[i]; + try { + this.putOpt(name, c.getField(name).get(object)); + } catch (Exception ignore) { + } + } + } + + /** + * Construct a JSONObject from a source JSON text string. This is the most + * commonly used JSONObject constructor. + * + * @param source + * A string beginning with { (left + * brace) and ending with } + *  (right brace). + * @exception JSONException + * If there is a syntax error in the source string or a + * duplicated key. + */ + public JSONObject(String source) throws JSONException { + this(new JSONTokener(source)); + } + + /** + * Construct a JSONObject from a ResourceBundle. + * + * @param baseName + * The ResourceBundle base name. + * @param locale + * The Locale to load the ResourceBundle for. + * @throws JSONException + * If any JSONExceptions are detected. + */ + public JSONObject(String baseName, Locale locale) throws JSONException { + this(); + ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale, + Thread.currentThread().getContextClassLoader()); + +// Iterate through the keys in the bundle. + + Enumeration keys = bundle.getKeys(); + while (keys.hasMoreElements()) { + Object key = keys.nextElement(); + if (key != null) { + +// Go through the path, ensuring that there is a nested JSONObject for each +// segment except the last. Add the value using the last segment's name into +// the deepest nested JSONObject. + + String[] path = ((String) key).split("\\."); + int last = path.length - 1; + JSONObject target = this; + for (int i = 0; i < last; i += 1) { + String segment = path[i]; + JSONObject nextTarget = target.optJSONObject(segment); + if (nextTarget == null) { + nextTarget = new JSONObject(); + target.put(segment, nextTarget); + } + target = nextTarget; + } + target.put(path[last], bundle.getString((String) key)); + } + } + } + + /** + * Constructor to specify an initial capacity of the internal map. Useful for library + * internal calls where we know, or at least can best guess, how big this JSONObject + * will be. + * + * @param initialCapacity initial capacity of the internal map. + */ + protected JSONObject(int initialCapacity){ + this.map = new HashMap(initialCapacity); + } + + /** + * Accumulate values under a key. It is similar to the put method except + * that if there is already an object stored under the key then a JSONArray + * is stored under the key to hold all of the accumulated values. If there + * is already a JSONArray, then the new value is appended to it. In + * contrast, the put method replaces the previous value. + * + * If only one value is accumulated that is not a JSONArray, then the result + * will be the same as using put. But if multiple values are accumulated, + * then the result will be like append. + * + * @param key + * A key string. + * @param value + * An object to be accumulated under the key. + * @return this. + * @throws JSONException + * If the value is non-finite number. + * @throws NullPointerException + * If the key is null. + */ + public JSONObject accumulate(String key, Object value) throws JSONException { + testValidity(value); + Object object = this.opt(key); + if (object == null) { + this.put(key, + value instanceof JSONArray ? new JSONArray().put(value) + : value); + } else if (object instanceof JSONArray) { + ((JSONArray) object).put(value); + } else { + this.put(key, new JSONArray().put(object).put(value)); + } + return this; + } + + /** + * Append values to the array under a key. If the key does not exist in the + * JSONObject, then the key is put in the JSONObject with its value being a + * JSONArray containing the value parameter. If the key was already + * associated with a JSONArray, then the value parameter is appended to it. + * + * @param key + * A key string. + * @param value + * An object to be accumulated under the key. + * @return this. + * @throws JSONException + * If the value is non-finite number or if the current value associated with + * the key is not a JSONArray. + * @throws NullPointerException + * If the key is null. + */ + public JSONObject append(String key, Object value) throws JSONException { + testValidity(value); + Object object = this.opt(key); + if (object == null) { + this.put(key, new JSONArray().put(value)); + } else if (object instanceof JSONArray) { + this.put(key, ((JSONArray) object).put(value)); + } else { + throw wrongValueFormatException(key, "JSONArray", null, null); + } + return this; + } + + /** + * Produce a string from a double. The string "null" will be returned if the + * number is not finite. + * + * @param d + * A double. + * @return A String. + */ + public static String doubleToString(double d) { + if (Double.isInfinite(d) || Double.isNaN(d)) { + return "null"; + } + +// Shave off trailing zeros and decimal point, if possible. + + String string = Double.toString(d); + if (string.indexOf('.') > 0 && string.indexOf('e') < 0 + && string.indexOf('E') < 0) { + while (string.endsWith("0")) { + string = string.substring(0, string.length() - 1); + } + if (string.endsWith(".")) { + string = string.substring(0, string.length() - 1); + } + } + return string; + } + + /** + * Get the value object associated with a key. + * + * @param key + * A key string. + * @return The object associated with the key. + * @throws JSONException + * if the key is not found. + */ + public Object get(String key) throws JSONException { + if (key == null) { + throw new JSONException("Null key."); + } + Object object = this.opt(key); + if (object == null) { + throw new JSONException("JSONObject[" + quote(key) + "] not found."); + } + return object; + } + + /** + * Get the enum value associated with a key. + * + * @param + * Enum Type + * @param clazz + * The type of enum to retrieve. + * @param key + * A key string. + * @return The enum value associated with the key + * @throws JSONException + * if the key is not found or if the value cannot be converted + * to an enum. + */ + public > E getEnum(Class clazz, String key) throws JSONException { + E val = optEnum(clazz, key); + if(val==null) { + // JSONException should really take a throwable argument. + // If it did, I would re-implement this with the Enum.valueOf + // method and place any thrown exception in the JSONException + throw wrongValueFormatException(key, "enum of type " + quote(clazz.getSimpleName()), null); + } + return val; + } + + /** + * Get the boolean value associated with a key. + * + * @param key + * A key string. + * @return The truth. + * @throws JSONException + * if the value is not a Boolean or the String "true" or + * "false". + */ + public boolean getBoolean(String key) throws JSONException { + Object object = this.get(key); + if (object.equals(Boolean.FALSE) + || (object instanceof String && ((String) object) + .equalsIgnoreCase("false"))) { + return false; + } else if (object.equals(Boolean.TRUE) + || (object instanceof String && ((String) object) + .equalsIgnoreCase("true"))) { + return true; + } + throw wrongValueFormatException(key, "Boolean", null); + } + + /** + * Get the BigInteger value associated with a key. + * + * @param key + * A key string. + * @return The numeric value. + * @throws JSONException + * if the key is not found or if the value cannot + * be converted to BigInteger. + */ + public BigInteger getBigInteger(String key) throws JSONException { + Object object = this.get(key); + BigInteger ret = objectToBigInteger(object, null); + if (ret != null) { + return ret; + } + throw wrongValueFormatException(key, "BigInteger", object, null); + } + + /** + * Get the BigDecimal value associated with a key. If the value is float or + * double, the {@link BigDecimal#BigDecimal(double)} constructor will + * be used. See notes on the constructor for conversion issues that may + * arise. + * + * @param key + * A key string. + * @return The numeric value. + * @throws JSONException + * if the key is not found or if the value + * cannot be converted to BigDecimal. + */ + public BigDecimal getBigDecimal(String key) throws JSONException { + Object object = this.get(key); + BigDecimal ret = objectToBigDecimal(object, null); + if (ret != null) { + return ret; + } + throw wrongValueFormatException(key, "BigDecimal", object, null); + } + + /** + * Get the double value associated with a key. + * + * @param key + * A key string. + * @return The numeric value. + * @throws JSONException + * if the key is not found or if the value is not a Number + * object and cannot be converted to a number. + */ + public double getDouble(String key) throws JSONException { + final Object object = this.get(key); + if(object instanceof Number) { + return ((Number)object).doubleValue(); + } + try { + return Double.parseDouble(object.toString()); + } catch (Exception e) { + throw wrongValueFormatException(key, "double", e); + } + } + + /** + * Get the float value associated with a key. + * + * @param key + * A key string. + * @return The numeric value. + * @throws JSONException + * if the key is not found or if the value is not a Number + * object and cannot be converted to a number. + */ + public float getFloat(String key) throws JSONException { + final Object object = this.get(key); + if(object instanceof Number) { + return ((Number)object).floatValue(); + } + try { + return Float.parseFloat(object.toString()); + } catch (Exception e) { + throw wrongValueFormatException(key, "float", e); + } + } + + /** + * Get the Number value associated with a key. + * + * @param key + * A key string. + * @return The numeric value. + * @throws JSONException + * if the key is not found or if the value is not a Number + * object and cannot be converted to a number. + */ + public Number getNumber(String key) throws JSONException { + Object object = this.get(key); + try { + if (object instanceof Number) { + return (Number)object; + } + return stringToNumber(object.toString()); + } catch (Exception e) { + throw wrongValueFormatException(key, "number", e); + } + } + + /** + * Get the int value associated with a key. + * + * @param key + * A key string. + * @return The integer value. + * @throws JSONException + * if the key is not found or if the value cannot be converted + * to an integer. + */ + public int getInt(String key) throws JSONException { + final Object object = this.get(key); + if(object instanceof Number) { + return ((Number)object).intValue(); + } + try { + return Integer.parseInt(object.toString()); + } catch (Exception e) { + throw wrongValueFormatException(key, "int", e); + } + } + + /** + * Get the JSONArray value associated with a key. + * + * @param key + * A key string. + * @return A JSONArray which is the value. + * @throws JSONException + * if the key is not found or if the value is not a JSONArray. + */ + public JSONArray getJSONArray(String key) throws JSONException { + Object object = this.get(key); + if (object instanceof JSONArray) { + return (JSONArray) object; + } + throw wrongValueFormatException(key, "JSONArray", null); + } + + /** + * Get the JSONObject value associated with a key. + * + * @param key + * A key string. + * @return A JSONObject which is the value. + * @throws JSONException + * if the key is not found or if the value is not a JSONObject. + */ + public JSONObject getJSONObject(String key) throws JSONException { + Object object = this.get(key); + if (object instanceof JSONObject) { + return (JSONObject) object; + } + throw wrongValueFormatException(key, "JSONObject", null); + } + + /** + * Get the long value associated with a key. + * + * @param key + * A key string. + * @return The long value. + * @throws JSONException + * if the key is not found or if the value cannot be converted + * to a long. + */ + public long getLong(String key) throws JSONException { + final Object object = this.get(key); + if(object instanceof Number) { + return ((Number)object).longValue(); + } + try { + return Long.parseLong(object.toString()); + } catch (Exception e) { + throw wrongValueFormatException(key, "long", e); + } + } + + /** + * Get an array of field names from a JSONObject. + * + * @param jo + * JSON object + * @return An array of field names, or null if there are no names. + */ + public static String[] getNames(JSONObject jo) { + if (jo.isEmpty()) { + return null; + } + return jo.keySet().toArray(new String[jo.length()]); + } + + /** + * Get an array of public field names from an Object. + * + * @param object + * object to read + * @return An array of field names, or null if there are no names. + */ + public static String[] getNames(Object object) { + if (object == null) { + return null; + } + Class klass = object.getClass(); + Field[] fields = klass.getFields(); + int length = fields.length; + if (length == 0) { + return null; + } + String[] names = new String[length]; + for (int i = 0; i < length; i += 1) { + names[i] = fields[i].getName(); + } + return names; + } + + /** + * Get the string associated with a key. + * + * @param key + * A key string. + * @return A string which is the value. + * @throws JSONException + * if there is no string value for the key. + */ + public String getString(String key) throws JSONException { + Object object = this.get(key); + if (object instanceof String) { + return (String) object; + } + throw wrongValueFormatException(key, "string", null); + } + + /** + * Determine if the JSONObject contains a specific key. + * + * @param key + * A key string. + * @return true if the key exists in the JSONObject. + */ + public boolean has(String key) { + return this.map.containsKey(key); + } + + /** + * Increment a property of a JSONObject. If there is no such property, + * create one with a value of 1 (Integer). If there is such a property, and if it is + * an Integer, Long, Double, Float, BigInteger, or BigDecimal then add one to it. + * No overflow bounds checking is performed, so callers should initialize the key + * prior to this call with an appropriate type that can handle the maximum expected + * value. + * + * @param key + * A key string. + * @return this. + * @throws JSONException + * If there is already a property with this name that is not an + * Integer, Long, Double, or Float. + */ + public JSONObject increment(String key) throws JSONException { + Object value = this.opt(key); + if (value == null) { + this.put(key, 1); + } else if (value instanceof Integer) { + this.put(key, ((Integer) value).intValue() + 1); + } else if (value instanceof Long) { + this.put(key, ((Long) value).longValue() + 1L); + } else if (value instanceof BigInteger) { + this.put(key, ((BigInteger)value).add(BigInteger.ONE)); + } else if (value instanceof Float) { + this.put(key, ((Float) value).floatValue() + 1.0f); + } else if (value instanceof Double) { + this.put(key, ((Double) value).doubleValue() + 1.0d); + } else if (value instanceof BigDecimal) { + this.put(key, ((BigDecimal)value).add(BigDecimal.ONE)); + } else { + throw new JSONException("Unable to increment [" + quote(key) + "]."); + } + return this; + } + + /** + * Determine if the value associated with the key is null or if there is no + * value. + * + * @param key + * A key string. + * @return true if there is no value associated with the key or if the value + * is the JSONObject.NULL object. + */ + public boolean isNull(String key) { + return JSONObject.NULL.equals(this.opt(key)); + } + + /** + * Get an enumeration of the keys of the JSONObject. Modifying this key Set will also + * modify the JSONObject. Use with caution. + * + * @see Set#iterator() + * + * @return An iterator of the keys. + */ + public Iterator keys() { + return this.keySet().iterator(); + } + + /** + * Get a set of keys of the JSONObject. Modifying this key Set will also modify the + * JSONObject. Use with caution. + * + * @see Map#keySet() + * + * @return A keySet. + */ + public Set keySet() { + return this.map.keySet(); + } + + /** + * Get a set of entries of the JSONObject. These are raw values and may not + * match what is returned by the JSONObject get* and opt* functions. Modifying + * the returned EntrySet or the Entry objects contained therein will modify the + * backing JSONObject. This does not return a clone or a read-only view. + * + * Use with caution. + * + * @see Map#entrySet() + * + * @return An Entry Set + */ + protected Set> entrySet() { + return this.map.entrySet(); + } + + /** + * Get the number of keys stored in the JSONObject. + * + * @return The number of keys in the JSONObject. + */ + public int length() { + return this.map.size(); + } + + /** + * Removes all of the elements from this JSONObject. + * The JSONObject will be empty after this call returns. + */ + public void clear() { + this.map.clear(); + } + + /** + * Check if JSONObject is empty. + * + * @return true if JSONObject is empty, otherwise false. + */ + public boolean isEmpty() { + return this.map.isEmpty(); + } + + /** + * Produce a JSONArray containing the names of the elements of this + * JSONObject. + * + * @return A JSONArray containing the key strings, or null if the JSONObject + * is empty. + */ + public JSONArray names() { + if(this.map.isEmpty()) { + return null; + } + return new JSONArray(this.map.keySet()); + } + + /** + * Produce a string from a Number. + * + * @param number + * A Number + * @return A String. + * @throws JSONException + * If n is a non-finite number. + */ + public static String numberToString(Number number) throws JSONException { + if (number == null) { + throw new JSONException("Null pointer"); + } + testValidity(number); + + // Shave off trailing zeros and decimal point, if possible. + + String string = number.toString(); + if (string.indexOf('.') > 0 && string.indexOf('e') < 0 + && string.indexOf('E') < 0) { + while (string.endsWith("0")) { + string = string.substring(0, string.length() - 1); + } + if (string.endsWith(".")) { + string = string.substring(0, string.length() - 1); + } + } + return string; + } + + /** + * Get an optional value associated with a key. + * + * @param key + * A key string. + * @return An object which is the value, or null if there is no value. + */ + public Object opt(String key) { + return key == null ? null : this.map.get(key); + } + + /** + * Get the enum value associated with a key. + * + * @param + * Enum Type + * @param clazz + * The type of enum to retrieve. + * @param key + * A key string. + * @return The enum value associated with the key or null if not found + */ + public > E optEnum(Class clazz, String key) { + return this.optEnum(clazz, key, null); + } + + /** + * Get the enum value associated with a key. + * + * @param + * Enum Type + * @param clazz + * The type of enum to retrieve. + * @param key + * A key string. + * @param defaultValue + * The default in case the value is not found + * @return The enum value associated with the key or defaultValue + * if the value is not found or cannot be assigned to clazz + */ + public > E optEnum(Class clazz, String key, E defaultValue) { + try { + Object val = this.opt(key); + if (NULL.equals(val)) { + return defaultValue; + } + if (clazz.isAssignableFrom(val.getClass())) { + // we just checked it! + @SuppressWarnings("unchecked") + E myE = (E) val; + return myE; + } + return Enum.valueOf(clazz, val.toString()); + } catch (IllegalArgumentException e) { + return defaultValue; + } catch (NullPointerException e) { + return defaultValue; + } + } + + /** + * Get an optional boolean associated with a key. It returns false if there + * is no such key, or if the value is not Boolean.TRUE or the String "true". + * + * @param key + * A key string. + * @return The truth. + */ + public boolean optBoolean(String key) { + return this.optBoolean(key, false); + } + + /** + * Get an optional boolean associated with a key. It returns the + * defaultValue if there is no such key, or if it is not a Boolean or the + * String "true" or "false" (case insensitive). + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return The truth. + */ + public boolean optBoolean(String key, boolean defaultValue) { + Object val = this.opt(key); + if (NULL.equals(val)) { + return defaultValue; + } + if (val instanceof Boolean){ + return ((Boolean) val).booleanValue(); + } + try { + // we'll use the get anyway because it does string conversion. + return this.getBoolean(key); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get an optional BigDecimal associated with a key, or the defaultValue if + * there is no such key or if its value is not a number. If the value is a + * string, an attempt will be made to evaluate it as a number. If the value + * is float or double, then the {@link BigDecimal#BigDecimal(double)} + * constructor will be used. See notes on the constructor for conversion + * issues that may arise. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. + */ + public BigDecimal optBigDecimal(String key, BigDecimal defaultValue) { + Object val = this.opt(key); + return objectToBigDecimal(val, defaultValue); + } + + /** + * @param val value to convert + * @param defaultValue default value to return is the conversion doesn't work or is null. + * @return BigDecimal conversion of the original value, or the defaultValue if unable + * to convert. + */ + static BigDecimal objectToBigDecimal(Object val, BigDecimal defaultValue) { + return objectToBigDecimal(val, defaultValue, true); + } + + /** + * @param val value to convert + * @param defaultValue default value to return is the conversion doesn't work or is null. + * @param exact When true, then {@link Double} and {@link Float} values will be converted exactly. + * When false, they will be converted to {@link String} values before converting to {@link BigDecimal}. + * @return BigDecimal conversion of the original value, or the defaultValue if unable + * to convert. + */ + static BigDecimal objectToBigDecimal(Object val, BigDecimal defaultValue, boolean exact) { + if (NULL.equals(val)) { + return defaultValue; + } + if (val instanceof BigDecimal){ + return (BigDecimal) val; + } + if (val instanceof BigInteger){ + return new BigDecimal((BigInteger) val); + } + if (val instanceof Double || val instanceof Float){ + if (!numberIsFinite((Number)val)) { + return defaultValue; + } + if (exact) { + return new BigDecimal(((Number)val).doubleValue()); + }else { + // use the string constructor so that we maintain "nice" values for doubles and floats + // the double constructor will translate doubles to "exact" values instead of the likely + // intended representation + return new BigDecimal(val.toString()); + } + } + if (val instanceof Long || val instanceof Integer + || val instanceof Short || val instanceof Byte){ + return new BigDecimal(((Number) val).longValue()); + } + // don't check if it's a string in case of unchecked Number subclasses + try { + return new BigDecimal(val.toString()); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get an optional BigInteger associated with a key, or the defaultValue if + * there is no such key or if its value is not a number. If the value is a + * string, an attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. + */ + public BigInteger optBigInteger(String key, BigInteger defaultValue) { + Object val = this.opt(key); + return objectToBigInteger(val, defaultValue); + } + + /** + * @param val value to convert + * @param defaultValue default value to return is the conversion doesn't work or is null. + * @return BigInteger conversion of the original value, or the defaultValue if unable + * to convert. + */ + static BigInteger objectToBigInteger(Object val, BigInteger defaultValue) { + if (NULL.equals(val)) { + return defaultValue; + } + if (val instanceof BigInteger){ + return (BigInteger) val; + } + if (val instanceof BigDecimal){ + return ((BigDecimal) val).toBigInteger(); + } + if (val instanceof Double || val instanceof Float){ + if (!numberIsFinite((Number)val)) { + return defaultValue; + } + return new BigDecimal(((Number) val).doubleValue()).toBigInteger(); + } + if (val instanceof Long || val instanceof Integer + || val instanceof Short || val instanceof Byte){ + return BigInteger.valueOf(((Number) val).longValue()); + } + // don't check if it's a string in case of unchecked Number subclasses + try { + // the other opt functions handle implicit conversions, i.e. + // jo.put("double",1.1d); + // jo.optInt("double"); -- will return 1, not an error + // this conversion to BigDecimal then to BigInteger is to maintain + // that type cast support that may truncate the decimal. + final String valStr = val.toString(); + if(isDecimalNotation(valStr)) { + return new BigDecimal(valStr).toBigInteger(); + } + return new BigInteger(valStr); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get an optional double associated with a key, or NaN if there is no such + * key or if its value is not a number. If the value is a string, an attempt + * will be made to evaluate it as a number. + * + * @param key + * A string which is the key. + * @return An object which is the value. + */ + public double optDouble(String key) { + return this.optDouble(key, Double.NaN); + } + + /** + * Get an optional double associated with a key, or the defaultValue if + * there is no such key or if its value is not a number. If the value is a + * string, an attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. + */ + public double optDouble(String key, double defaultValue) { + Number val = this.optNumber(key); + if (val == null) { + return defaultValue; + } + final double doubleValue = val.doubleValue(); + // if (Double.isNaN(doubleValue) || Double.isInfinite(doubleValue)) { + // return defaultValue; + // } + return doubleValue; + } + + /** + * Get the optional double value associated with an index. NaN is returned + * if there is no value for the index, or if the value is not a number and + * cannot be converted to a number. + * + * @param key + * A key string. + * @return The value. + */ + public float optFloat(String key) { + return this.optFloat(key, Float.NaN); + } + + /** + * Get the optional double value associated with an index. The defaultValue + * is returned if there is no value for the index, or if the value is not a + * number and cannot be converted to a number. + * + * @param key + * A key string. + * @param defaultValue + * The default value. + * @return The value. + */ + public float optFloat(String key, float defaultValue) { + Number val = this.optNumber(key); + if (val == null) { + return defaultValue; + } + final float floatValue = val.floatValue(); + // if (Float.isNaN(floatValue) || Float.isInfinite(floatValue)) { + // return defaultValue; + // } + return floatValue; + } + + /** + * Get an optional int value associated with a key, or zero if there is no + * such key or if the value is not a number. If the value is a string, an + * attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @return An object which is the value. + */ + public int optInt(String key) { + return this.optInt(key, 0); + } + + /** + * Get an optional int value associated with a key, or the default if there + * is no such key or if the value is not a number. If the value is a string, + * an attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. + */ + public int optInt(String key, int defaultValue) { + final Number val = this.optNumber(key, null); + if (val == null) { + return defaultValue; + } + return val.intValue(); + } + + /** + * Get an optional JSONArray associated with a key. It returns null if there + * is no such key, or if its value is not a JSONArray. + * + * @param key + * A key string. + * @return A JSONArray which is the value. + */ + public JSONArray optJSONArray(String key) { + Object o = this.opt(key); + return o instanceof JSONArray ? (JSONArray) o : null; + } + + /** + * Get an optional JSONObject associated with a key. It returns null if + * there is no such key, or if its value is not a JSONObject. + * + * @param key + * A key string. + * @return A JSONObject which is the value. + */ + public JSONObject optJSONObject(String key) { return this.optJSONObject(key, null); } + + /** + * Get an optional JSONObject associated with a key, or the default if there + * is no such key or if the value is not a JSONObject. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An JSONObject which is the value. + */ + public JSONObject optJSONObject(String key, JSONObject defaultValue) { + Object object = this.opt(key); + return object instanceof JSONObject ? (JSONObject) object : defaultValue; + } + + /** + * Get an optional long value associated with a key, or zero if there is no + * such key or if the value is not a number. If the value is a string, an + * attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @return An object which is the value. + */ + public long optLong(String key) { + return this.optLong(key, 0); + } + + /** + * Get an optional long value associated with a key, or the default if there + * is no such key or if the value is not a number. If the value is a string, + * an attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. + */ + public long optLong(String key, long defaultValue) { + final Number val = this.optNumber(key, null); + if (val == null) { + return defaultValue; + } + + return val.longValue(); + } + + /** + * Get an optional {@link Number} value associated with a key, or null + * if there is no such key or if the value is not a number. If the value is a string, + * an attempt will be made to evaluate it as a number ({@link BigDecimal}). This method + * would be used in cases where type coercion of the number value is unwanted. + * + * @param key + * A key string. + * @return An object which is the value. + */ + public Number optNumber(String key) { + return this.optNumber(key, null); + } + + /** + * Get an optional {@link Number} value associated with a key, or the default if there + * is no such key or if the value is not a number. If the value is a string, + * an attempt will be made to evaluate it as a number. This method + * would be used in cases where type coercion of the number value is unwanted. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. + */ + public Number optNumber(String key, Number defaultValue) { + Object val = this.opt(key); + if (NULL.equals(val)) { + return defaultValue; + } + if (val instanceof Number){ + return (Number) val; + } + + try { + return stringToNumber(val.toString()); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get an optional string associated with a key. It returns an empty string + * if there is no such key. If the value is not a string and is not null, + * then it is converted to a string. + * + * @param key + * A key string. + * @return A string which is the value. + */ + public String optString(String key) { + return this.optString(key, ""); + } + + /** + * Get an optional string associated with a key. It returns the defaultValue + * if there is no such key. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return A string which is the value. + */ + public String optString(String key, String defaultValue) { + Object object = this.opt(key); + return NULL.equals(object) ? defaultValue : object.toString(); + } + + /** + * Populates the internal map of the JSONObject with the bean properties. The + * bean can not be recursive. + * + * @see JSONObject#JSONObject(Object) + * + * @param bean + * the bean + */ + private void populateMap(Object bean) { + populateMap(bean, Collections.newSetFromMap(new IdentityHashMap())); + } + + private void populateMap(Object bean, Set objectsRecord) { + Class klass = bean.getClass(); + + // If klass is a System class then set includeSuperClass to false. + + boolean includeSuperClass = klass.getClassLoader() != null; + + Method[] methods = includeSuperClass ? klass.getMethods() : klass.getDeclaredMethods(); + for (final Method method : methods) { + final int modifiers = method.getModifiers(); + if (Modifier.isPublic(modifiers) + && !Modifier.isStatic(modifiers) + && method.getParameterTypes().length == 0 + && !method.isBridge() + && method.getReturnType() != Void.TYPE + && isValidMethodName(method.getName())) { + final String key = getKeyNameFromMethod(method); + if (key != null && !key.isEmpty()) { + try { + final Object result = method.invoke(bean); + if (result != null) { + // check cyclic dependency and throw error if needed + // the wrap and populateMap combination method is + // itself DFS recursive + if (objectsRecord.contains(result)) { + throw recursivelyDefinedObjectException(key); + } + + objectsRecord.add(result); + + this.map.put(key, wrap(result, objectsRecord)); + + objectsRecord.remove(result); + + // we don't use the result anywhere outside of wrap + // if it's a resource we should be sure to close it + // after calling toString + if (result instanceof Closeable) { + try { + ((Closeable) result).close(); + } catch (IOException ignore) { + } + } + } + } catch (IllegalAccessException ignore) { + } catch (IllegalArgumentException ignore) { + } catch (InvocationTargetException ignore) { + } + } + } + } + } + + private static boolean isValidMethodName(String name) { + return !"getClass".equals(name) && !"getDeclaringClass".equals(name); + } + + private static String getKeyNameFromMethod(Method method) { + final int ignoreDepth = getAnnotationDepth(method, JSONPropertyIgnore.class); + if (ignoreDepth > 0) { + final int forcedNameDepth = getAnnotationDepth(method, JSONPropertyName.class); + if (forcedNameDepth < 0 || ignoreDepth <= forcedNameDepth) { + // the hierarchy asked to ignore, and the nearest name override + // was higher or non-existent + return null; + } + } + JSONPropertyName annotation = getAnnotation(method, JSONPropertyName.class); + if (annotation != null && annotation.value() != null && !annotation.value().isEmpty()) { + return annotation.value(); + } + String key; + final String name = method.getName(); + if (name.startsWith("get") && name.length() > 3) { + key = name.substring(3); + } else if (name.startsWith("is") && name.length() > 2) { + key = name.substring(2); + } else { + return null; + } + // if the first letter in the key is not uppercase, then skip. + // This is to maintain backwards compatibility before PR406 + // (https://github.com/stleary/JSON-java/pull/406/) + if (key.length() == 0 || Character.isLowerCase(key.charAt(0))) { + return null; + } + if (key.length() == 1) { + key = key.toLowerCase(Locale.ROOT); + } else if (!Character.isUpperCase(key.charAt(1))) { + key = key.substring(0, 1).toLowerCase(Locale.ROOT) + key.substring(1); + } + return key; + } + + /** + * Searches the class hierarchy to see if the method or it's super + * implementations and interfaces has the annotation. + * + * @param + * type of the annotation + * + * @param m + * method to check + * @param annotationClass + * annotation to look for + * @return the {@link Annotation} if the annotation exists on the current method + * or one of its super class definitions + */ + private static A getAnnotation(final Method m, final Class annotationClass) { + // if we have invalid data the result is null + if (m == null || annotationClass == null) { + return null; + } + + if (m.isAnnotationPresent(annotationClass)) { + return m.getAnnotation(annotationClass); + } + + // if we've already reached the Object class, return null; + Class c = m.getDeclaringClass(); + if (c.getSuperclass() == null) { + return null; + } + + // check directly implemented interfaces for the method being checked + for (Class i : c.getInterfaces()) { + try { + Method im = i.getMethod(m.getName(), m.getParameterTypes()); + return getAnnotation(im, annotationClass); + } catch (final SecurityException ex) { + continue; + } catch (final NoSuchMethodException ex) { + continue; + } + } + + try { + return getAnnotation( + c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()), + annotationClass); + } catch (final SecurityException ex) { + return null; + } catch (final NoSuchMethodException ex) { + return null; + } + } + + /** + * Searches the class hierarchy to see if the method or it's super + * implementations and interfaces has the annotation. Returns the depth of the + * annotation in the hierarchy. + * + * @param m + * method to check + * @param annotationClass + * annotation to look for + * @return Depth of the annotation or -1 if the annotation is not on the method. + */ + private static int getAnnotationDepth(final Method m, final Class annotationClass) { + // if we have invalid data the result is -1 + if (m == null || annotationClass == null) { + return -1; + } + + if (m.isAnnotationPresent(annotationClass)) { + return 1; + } + + // if we've already reached the Object class, return -1; + Class c = m.getDeclaringClass(); + if (c.getSuperclass() == null) { + return -1; + } + + // check directly implemented interfaces for the method being checked + for (Class i : c.getInterfaces()) { + try { + Method im = i.getMethod(m.getName(), m.getParameterTypes()); + int d = getAnnotationDepth(im, annotationClass); + if (d > 0) { + // since the annotation was on the interface, add 1 + return d + 1; + } + } catch (final SecurityException ex) { + continue; + } catch (final NoSuchMethodException ex) { + continue; + } + } + + try { + int d = getAnnotationDepth( + c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()), + annotationClass); + if (d > 0) { + // since the annotation was on the superclass, add 1 + return d + 1; + } + return -1; + } catch (final SecurityException ex) { + return -1; + } catch (final NoSuchMethodException ex) { + return -1; + } + } + + /** + * Put a key/boolean pair in the JSONObject. + * + * @param key + * A key string. + * @param value + * A boolean which is the value. + * @return this. + * @throws JSONException + * If the value is non-finite number. + * @throws NullPointerException + * If the key is null. + */ + public JSONObject put(String key, boolean value) throws JSONException { + return this.put(key, value ? Boolean.TRUE : Boolean.FALSE); + } + + /** + * Put a key/value pair in the JSONObject, where the value will be a + * JSONArray which is produced from a Collection. + * + * @param key + * A key string. + * @param value + * A Collection value. + * @return this. + * @throws JSONException + * If the value is non-finite number. + * @throws NullPointerException + * If the key is null. + */ + public JSONObject put(String key, Collection value) throws JSONException { + return this.put(key, new JSONArray(value)); + } + + /** + * Put a key/double pair in the JSONObject. + * + * @param key + * A key string. + * @param value + * A double which is the value. + * @return this. + * @throws JSONException + * If the value is non-finite number. + * @throws NullPointerException + * If the key is null. + */ + public JSONObject put(String key, double value) throws JSONException { + return this.put(key, Double.valueOf(value)); + } + + /** + * Put a key/float pair in the JSONObject. + * + * @param key + * A key string. + * @param value + * A float which is the value. + * @return this. + * @throws JSONException + * If the value is non-finite number. + * @throws NullPointerException + * If the key is null. + */ + public JSONObject put(String key, float value) throws JSONException { + return this.put(key, Float.valueOf(value)); + } + + /** + * Put a key/int pair in the JSONObject. + * + * @param key + * A key string. + * @param value + * An int which is the value. + * @return this. + * @throws JSONException + * If the value is non-finite number. + * @throws NullPointerException + * If the key is null. + */ + public JSONObject put(String key, int value) throws JSONException { + return this.put(key, Integer.valueOf(value)); + } + + /** + * Put a key/long pair in the JSONObject. + * + * @param key + * A key string. + * @param value + * A long which is the value. + * @return this. + * @throws JSONException + * If the value is non-finite number. + * @throws NullPointerException + * If the key is null. + */ + public JSONObject put(String key, long value) throws JSONException { + return this.put(key, Long.valueOf(value)); + } + + /** + * Put a key/value pair in the JSONObject, where the value will be a + * JSONObject which is produced from a Map. + * + * @param key + * A key string. + * @param value + * A Map value. + * @return this. + * @throws JSONException + * If the value is non-finite number. + * @throws NullPointerException + * If the key is null. + */ + public JSONObject put(String key, Map value) throws JSONException { + return this.put(key, new JSONObject(value)); + } + + /** + * Put a key/value pair in the JSONObject. If the value is null, then the + * key will be removed from the JSONObject if it is present. + * + * @param key + * A key string. + * @param value + * An object which is the value. It should be of one of these + * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, + * String, or the JSONObject.NULL object. + * @return this. + * @throws JSONException + * If the value is non-finite number. + * @throws NullPointerException + * If the key is null. + */ + public JSONObject put(String key, Object value) throws JSONException { + if (key == null) { + throw new NullPointerException("Null key."); + } + if (value != null) { + testValidity(value); + this.map.put(key, value); + } else { + this.remove(key); + } + return this; + } + + /** + * Put a key/value pair in the JSONObject, but only if the key and the value + * are both non-null, and only if there is not already a member with that + * name. + * + * @param key + * key to insert into + * @param value + * value to insert + * @return this. + * @throws JSONException + * if the key is a duplicate + */ + public JSONObject putOnce(String key, Object value) throws JSONException { + if (key != null && value != null) { + if (this.opt(key) != null) { + throw new JSONException("Duplicate key \"" + key + "\""); + } + return this.put(key, value); + } + return this; + } + + /** + * Put a key/value pair in the JSONObject, but only if the key and the value + * are both non-null. + * + * @param key + * A key string. + * @param value + * An object which is the value. It should be of one of these + * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, + * String, or the JSONObject.NULL object. + * @return this. + * @throws JSONException + * If the value is a non-finite number. + */ + public JSONObject putOpt(String key, Object value) throws JSONException { + if (key != null && value != null) { + return this.put(key, value); + } + return this; + } + + /** + * Creates a JSONPointer using an initialization string and tries to + * match it to an item within this JSONObject. For example, given a + * JSONObject initialized with this document: + *
+     * {
+     *     "a":{"b":"c"}
+     * }
+     * 
+ * and this JSONPointer string: + *
+     * "/a/b"
+     * 
+ * Then this method will return the String "c". + * A JSONPointerException may be thrown from code called by this method. + * + * @param jsonPointer string that can be used to create a JSONPointer + * @return the item matched by the JSONPointer, otherwise null + */ + public Object query(String jsonPointer) { + return query(new JSONPointer(jsonPointer)); + } + /** + * Uses a user initialized JSONPointer and tries to + * match it to an item within this JSONObject. For example, given a + * JSONObject initialized with this document: + *
+     * {
+     *     "a":{"b":"c"}
+     * }
+     * 
+ * and this JSONPointer: + *
+     * "/a/b"
+     * 
+ * Then this method will return the String "c". + * A JSONPointerException may be thrown from code called by this method. + * + * @param jsonPointer string that can be used to create a JSONPointer + * @return the item matched by the JSONPointer, otherwise null + */ + public Object query(JSONPointer jsonPointer) { + return jsonPointer.queryFrom(this); + } + + /** + * Queries and returns a value from this object using {@code jsonPointer}, or + * returns null if the query fails due to a missing key. + * + * @param jsonPointer the string representation of the JSON pointer + * @return the queried value or {@code null} + * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax + */ + public Object optQuery(String jsonPointer) { + return optQuery(new JSONPointer(jsonPointer)); + } + + /** + * Queries and returns a value from this object using {@code jsonPointer}, or + * returns null if the query fails due to a missing key. + * + * @param jsonPointer The JSON pointer + * @return the queried value or {@code null} + * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax + */ + public Object optQuery(JSONPointer jsonPointer) { + try { + return jsonPointer.queryFrom(this); + } catch (JSONPointerException e) { + return null; + } + } + + /** + * Produce a string in double quotes with backslash sequences in all the + * right places. A backslash will be inserted within </, producing + * <\/, allowing JSON text to be delivered in HTML. In JSON text, a + * string cannot contain a control character or an unescaped quote or + * backslash. + * + * @param string + * A String + * @return A String correctly formatted for insertion in a JSON text. + */ + public static String quote(String string) { + StringWriter sw = new StringWriter(); + synchronized (sw.getBuffer()) { + try { + return quote(string, sw).toString(); + } catch (IOException ignored) { + // will never happen - we are writing to a string writer + return ""; + } + } + } + + public static Writer quote(String string, Writer w) throws IOException { + if (string == null || string.isEmpty()) { + w.write("\"\""); + return w; + } + + char b; + char c = 0; + String hhhh; + int i; + int len = string.length(); + + w.write('"'); + for (i = 0; i < len; i += 1) { + b = c; + c = string.charAt(i); + switch (c) { + case '\\': + case '"': + w.write('\\'); + w.write(c); + break; + case '/': + if (b == '<') { + w.write('\\'); + } + w.write(c); + break; + case '\b': + w.write("\\b"); + break; + case '\t': + w.write("\\t"); + break; + case '\n': + w.write("\\n"); + break; + case '\f': + w.write("\\f"); + break; + case '\r': + w.write("\\r"); + break; + default: + if (c < ' ' || (c >= '\u0080' && c < '\u00a0') + || (c >= '\u2000' && c < '\u2100')) { + w.write("\\u"); + hhhh = Integer.toHexString(c); + w.write("0000", 0, 4 - hhhh.length()); + w.write(hhhh); + } else { + w.write(c); + } + } + } + w.write('"'); + return w; + } + + /** + * Remove a name and its value, if present. + * + * @param key + * The name to be removed. + * @return The value that was associated with the name, or null if there was + * no value. + */ + public Object remove(String key) { + return this.map.remove(key); + } + + /** + * Determine if two JSONObjects are similar. + * They must contain the same set of names which must be associated with + * similar values. + * + * @param other The other JSONObject + * @return true if they are equal + */ + public boolean similar(Object other) { + try { + if (!(other instanceof JSONObject)) { + return false; + } + if (!this.keySet().equals(((JSONObject)other).keySet())) { + return false; + } + for (final Entry entry : this.entrySet()) { + String name = entry.getKey(); + Object valueThis = entry.getValue(); + Object valueOther = ((JSONObject)other).get(name); + if(valueThis == valueOther) { + continue; + } + if(valueThis == null) { + return false; + } + if (valueThis instanceof JSONObject) { + if (!((JSONObject)valueThis).similar(valueOther)) { + return false; + } + } else if (valueThis instanceof JSONArray) { + if (!((JSONArray)valueThis).similar(valueOther)) { + return false; + } + } else if (valueThis instanceof Number && valueOther instanceof Number) { + if (!isNumberSimilar((Number)valueThis, (Number)valueOther)) { + return false; + }; + } else if (!valueThis.equals(valueOther)) { + return false; + } + } + return true; + } catch (Throwable exception) { + return false; + } + } + + /** + * Compares two numbers to see if they are similar. + * + * If either of the numbers are Double or Float instances, then they are checked to have + * a finite value. If either value is not finite (NaN or ±infinity), then this + * function will always return false. If both numbers are finite, they are first checked + * to be the same type and implement {@link Comparable}. If they do, then the actual + * {@link Comparable#compareTo(Object)} is called. If they are not the same type, or don't + * implement Comparable, then they are converted to {@link BigDecimal}s. Finally the + * BigDecimal values are compared using {@link BigDecimal#compareTo(BigDecimal)}. + * + * @param l the Left value to compare. Can not be null. + * @param r the right value to compare. Can not be null. + * @return true if the numbers are similar, false otherwise. + */ + static boolean isNumberSimilar(Number l, Number r) { + if (!numberIsFinite(l) || !numberIsFinite(r)) { + // non-finite numbers are never similar + return false; + } + + // if the classes are the same and implement Comparable + // then use the built in compare first. + if(l.getClass().equals(r.getClass()) && l instanceof Comparable) { + @SuppressWarnings({ "rawtypes", "unchecked" }) + int compareTo = ((Comparable)l).compareTo(r); + return compareTo==0; + } + + // BigDecimal should be able to handle all of our number types that we support through + // documentation. Convert to BigDecimal first, then use the Compare method to + // decide equality. + final BigDecimal lBigDecimal = objectToBigDecimal(l, null, false); + final BigDecimal rBigDecimal = objectToBigDecimal(r, null, false); + if (lBigDecimal == null || rBigDecimal == null) { + return false; + } + return lBigDecimal.compareTo(rBigDecimal) == 0; + } + + private static boolean numberIsFinite(Number n) { + if (n instanceof Double && (((Double) n).isInfinite() || ((Double) n).isNaN())) { + return false; + } else if (n instanceof Float && (((Float) n).isInfinite() || ((Float) n).isNaN())) { + return false; + } + return true; + } + + /** + * Tests if the value should be tried as a decimal. It makes no test if there are actual digits. + * + * @param val value to test + * @return true if the string is "-0" or if it contains '.', 'e', or 'E', false otherwise. + */ + protected static boolean isDecimalNotation(final String val) { + return val.indexOf('.') > -1 || val.indexOf('e') > -1 + || val.indexOf('E') > -1 || "-0".equals(val); + } + + /** + * Converts a string to a number using the narrowest possible type. Possible + * returns for this function are BigDecimal, Double, BigInteger, Long, and Integer. + * When a Double is returned, it should always be a valid Double and not NaN or +-infinity. + * + * @param val value to convert + * @return Number representation of the value. + * @throws NumberFormatException thrown if the value is not a valid number. A public + * caller should catch this and wrap it in a {@link JSONException} if applicable. + */ + protected static Number stringToNumber(final String val) throws NumberFormatException { + char initial = val.charAt(0); + if ((initial >= '0' && initial <= '9') || initial == '-') { + // decimal representation + if (isDecimalNotation(val)) { + // Use a BigDecimal all the time so we keep the original + // representation. BigDecimal doesn't support -0.0, ensure we + // keep that by forcing a decimal. + try { + BigDecimal bd = new BigDecimal(val); + if(initial == '-' && BigDecimal.ZERO.compareTo(bd)==0) { + return Double.valueOf(-0.0); + } + return bd; + } catch (NumberFormatException retryAsDouble) { + // this is to support "Hex Floats" like this: 0x1.0P-1074 + try { + Double d = Double.valueOf(val); + if(d.isNaN() || d.isInfinite()) { + throw new NumberFormatException("val ["+val+"] is not a valid number."); + } + return d; + } catch (NumberFormatException ignore) { + throw new NumberFormatException("val ["+val+"] is not a valid number."); + } + } + } + // block items like 00 01 etc. Java number parsers treat these as Octal. + if(initial == '0' && val.length() > 1) { + char at1 = val.charAt(1); + if(at1 >= '0' && at1 <= '9') { + throw new NumberFormatException("val ["+val+"] is not a valid number."); + } + } else if (initial == '-' && val.length() > 2) { + char at1 = val.charAt(1); + char at2 = val.charAt(2); + if(at1 == '0' && at2 >= '0' && at2 <= '9') { + throw new NumberFormatException("val ["+val+"] is not a valid number."); + } + } + // integer representation. + // This will narrow any values to the smallest reasonable Object representation + // (Integer, Long, or BigInteger) + + // BigInteger down conversion: We use a similar bitLength compare as + // BigInteger#intValueExact uses. Increases GC, but objects hold + // only what they need. i.e. Less runtime overhead if the value is + // long lived. + BigInteger bi = new BigInteger(val); + if(bi.bitLength() <= 31){ + return Integer.valueOf(bi.intValue()); + } + if(bi.bitLength() <= 63){ + return Long.valueOf(bi.longValue()); + } + return bi; + } + throw new NumberFormatException("val ["+val+"] is not a valid number."); + } + + /** + * Try to convert a string into a number, boolean, or null. If the string + * can't be converted, return the string. + * + * @param string + * A String. can not be null. + * @return A simple JSON value. + * @throws NullPointerException + * Thrown if the string is null. + */ + // Changes to this method must be copied to the corresponding method in + // the XML class to keep full support for Android + public static Object stringToValue(String string) { + if ("".equals(string)) { + return string; + } + + // check JSON key words true/false/null + if ("true".equalsIgnoreCase(string)) { + return Boolean.TRUE; + } + if ("false".equalsIgnoreCase(string)) { + return Boolean.FALSE; + } + if ("null".equalsIgnoreCase(string)) { + return JSONObject.NULL; + } + + /* + * If it might be a number, try converting it. If a number cannot be + * produced, then the value will just be a string. + */ + + char initial = string.charAt(0); + if ((initial >= '0' && initial <= '9') || initial == '-') { + try { + return stringToNumber(string); + } catch (Exception ignore) { + } + } + return string; + } + + /** + * Throw an exception if the object is a NaN or infinite number. + * + * @param o + * The object to test. + * @throws JSONException + * If o is a non-finite number. + */ + public static void testValidity(Object o) throws JSONException { + if (o instanceof Number && !numberIsFinite((Number) o)) { + throw new JSONException("JSON does not allow non-finite numbers."); + } + } + + /** + * Produce a JSONArray containing the values of the members of this + * JSONObject. + * + * @param names + * A JSONArray containing a list of key strings. This determines + * the sequence of the values in the result. + * @return A JSONArray of values. + * @throws JSONException + * If any of the values are non-finite numbers. + */ + public JSONArray toJSONArray(JSONArray names) throws JSONException { + if (names == null || names.isEmpty()) { + return null; + } + JSONArray ja = new JSONArray(); + for (int i = 0; i < names.length(); i += 1) { + ja.put(this.opt(names.getString(i))); + } + return ja; + } + + /** + * Make a JSON text of this JSONObject. For compactness, no whitespace is + * added. If this would not result in a syntactically correct JSON text, + * then null will be returned instead. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * + * @return a printable, displayable, portable, transmittable representation + * of the object, beginning with { (left + * brace) and ending with } (right + * brace). + */ + @Override + public String toString() { + try { + return this.toString(0); + } catch (Exception e) { + return null; + } + } + + /** + * Make a pretty-printed JSON text of this JSONObject. + * + *

If

{@code indentFactor > 0}
and the {@link JSONObject} + * has only one key, then the object will be output on a single line: + *
{@code {"key": 1}}
+ * + *

If an object has 2 or more keys, then it will be output across + * multiple lines:

{@code {
+     *  "key1": 1,
+     *  "key2": "value 2",
+     *  "key3": 3
+     * }}
+ *

+ * Warning: This method assumes that the data structure is acyclical. + * + * + * @param indentFactor + * The number of spaces to add to each level of indentation. + * @return a printable, displayable, portable, transmittable representation + * of the object, beginning with { (left + * brace) and ending with } (right + * brace). + * @throws JSONException + * If the object contains an invalid number. + */ + public String toString(int indentFactor) throws JSONException { + StringWriter w = new StringWriter(); + synchronized (w.getBuffer()) { + return this.write(w, indentFactor, 0).toString(); + } + } + + /** + * Make a JSON text of an Object value. If the object has an + * value.toJSONString() method, then that method will be used to produce the + * JSON text. The method is required to produce a strictly conforming text. + * If the object does not contain a toJSONString method (which is the most + * common case), then a text will be produced by other means. If the value + * is an array or Collection, then a JSONArray will be made from it and its + * toJSONString method will be called. If the value is a MAP, then a + * JSONObject will be made from it and its toJSONString method will be + * called. Otherwise, the value's toString method will be called, and the + * result will be quoted. + * + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @param value + * The value to be serialized. + * @return a printable, displayable, transmittable representation of the + * object, beginning with { (left + * brace) and ending with } (right + * brace). + * @throws JSONException + * If the value is or contains an invalid number. + */ + public static String valueToString(Object value) throws JSONException { + // moves the implementation to JSONWriter as: + // 1. It makes more sense to be part of the writer class + // 2. For Android support this method is not available. By implementing it in the Writer + // Android users can use the writer with the built in Android JSONObject implementation. + return JSONWriter.valueToString(value); + } + + /** + * Wrap an object, if necessary. If the object is null, return the NULL + * object. If it is an array or collection, wrap it in a JSONArray. If it is + * a map, wrap it in a JSONObject. If it is a standard property (Double, + * String, et al) then it is already wrapped. Otherwise, if it comes from + * one of the java packages, turn it into a string. And if it doesn't, try + * to wrap it in a JSONObject. If the wrapping fails, then null is returned. + * + * @param object + * The object to wrap + * @return The wrapped value + */ + public static Object wrap(Object object) { + return wrap(object, null); + } + + private static Object wrap(Object object, Set objectsRecord) { + try { + if (NULL.equals(object)) { + return NULL; + } + if (object instanceof JSONObject || object instanceof JSONArray + || NULL.equals(object) || object instanceof JSONString + || object instanceof Byte || object instanceof Character + || object instanceof Short || object instanceof Integer + || object instanceof Long || object instanceof Boolean + || object instanceof Float || object instanceof Double + || object instanceof String || object instanceof BigInteger + || object instanceof BigDecimal || object instanceof Enum) { + return object; + } + + if (object instanceof Collection) { + Collection coll = (Collection) object; + return new JSONArray(coll); + } + if (object.getClass().isArray()) { + return new JSONArray(object); + } + if (object instanceof Map) { + Map map = (Map) object; + return new JSONObject(map); + } + Package objectPackage = object.getClass().getPackage(); + String objectPackageName = objectPackage != null ? objectPackage + .getName() : ""; + if (objectPackageName.startsWith("java.") + || objectPackageName.startsWith("javax.") + || object.getClass().getClassLoader() == null) { + return object.toString(); + } + if (objectsRecord != null) { + return new JSONObject(object, objectsRecord); + } + else { + return new JSONObject(object); + } + } + catch (JSONException exception) { + throw exception; + } catch (Exception exception) { + return null; + } + } + + /** + * Write the contents of the JSONObject as JSON text to a writer. For + * compactness, no whitespace is added. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @param writer the writer object + * @return The writer. + * @throws JSONException if a called function has an error + */ + public Writer write(Writer writer) throws JSONException { + return this.write(writer, 0, 0); + } + + static final Writer writeValue(Writer writer, Object value, + int indentFactor, int indent) throws JSONException, IOException { + if (value == null || value.equals(null)) { + writer.write("null"); + } else if (value instanceof JSONString) { + Object o; + try { + o = ((JSONString) value).toJSONString(); + } catch (Exception e) { + throw new JSONException(e); + } + writer.write(o != null ? o.toString() : quote(value.toString())); + } else if (value instanceof Number) { + // not all Numbers may match actual JSON Numbers. i.e. fractions or Imaginary + final String numberAsString = numberToString((Number) value); + if(NUMBER_PATTERN.matcher(numberAsString).matches()) { + writer.write(numberAsString); + } else { + // The Number value is not a valid JSON number. + // Instead we will quote it as a string + quote(numberAsString, writer); + } + } else if (value instanceof Boolean) { + writer.write(value.toString()); + } else if (value instanceof Enum) { + writer.write(quote(((Enum)value).name())); + } else if (value instanceof JSONObject) { + ((JSONObject) value).write(writer, indentFactor, indent); + } else if (value instanceof JSONArray) { + ((JSONArray) value).write(writer, indentFactor, indent); + } else if (value instanceof Map) { + Map map = (Map) value; + new JSONObject(map).write(writer, indentFactor, indent); + } else if (value instanceof Collection) { + Collection coll = (Collection) value; + new JSONArray(coll).write(writer, indentFactor, indent); + } else if (value.getClass().isArray()) { + new JSONArray(value).write(writer, indentFactor, indent); + } else { + quote(value.toString(), writer); + } + return writer; + } + + static final void indent(Writer writer, int indent) throws IOException { + for (int i = 0; i < indent; i += 1) { + writer.write(' '); + } + } + + /** + * Write the contents of the JSONObject as JSON text to a writer. + * + *

If

{@code indentFactor > 0}
and the {@link JSONObject} + * has only one key, then the object will be output on a single line: + *
{@code {"key": 1}}
+ * + *

If an object has 2 or more keys, then it will be output across + * multiple lines:

{@code {
+     *  "key1": 1,
+     *  "key2": "value 2",
+     *  "key3": 3
+     * }}
+ *

+ * Warning: This method assumes that the data structure is acyclical. + * + * + * @param writer + * Writes the serialized JSON + * @param indentFactor + * The number of spaces to add to each level of indentation. + * @param indent + * The indentation of the top level. + * @return The writer. + * @throws JSONException if a called function has an error or a write error + * occurs + */ + public Writer write(Writer writer, int indentFactor, int indent) + throws JSONException { + try { + boolean needsComma = false; + final int length = this.length(); + writer.write('{'); + + if (length == 1) { + final Entry entry = this.entrySet().iterator().next(); + final String key = entry.getKey(); + writer.write(quote(key)); + writer.write(':'); + if (indentFactor > 0) { + writer.write(' '); + } + try{ + writeValue(writer, entry.getValue(), indentFactor, indent); + } catch (Exception e) { + throw new JSONException("Unable to write JSONObject value for key: " + key, e); + } + } else if (length != 0) { + final int newIndent = indent + indentFactor; + for (final Entry entry : this.entrySet()) { + if (needsComma) { + writer.write(','); + } + if (indentFactor > 0) { + writer.write('\n'); + } + indent(writer, newIndent); + final String key = entry.getKey(); + writer.write(quote(key)); + writer.write(':'); + if (indentFactor > 0) { + writer.write(' '); + } + try { + writeValue(writer, entry.getValue(), indentFactor, newIndent); + } catch (Exception e) { + throw new JSONException("Unable to write JSONObject value for key: " + key, e); + } + needsComma = true; + } + if (indentFactor > 0) { + writer.write('\n'); + } + indent(writer, indent); + } + writer.write('}'); + return writer; + } catch (IOException exception) { + throw new JSONException(exception); + } + } + + /** + * Returns a java.util.Map containing all of the entries in this object. + * If an entry in the object is a JSONArray or JSONObject it will also + * be converted. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @return a java.util.Map containing the entries of this object + */ + public Map toMap() { + Map results = new HashMap(); + for (Entry entry : this.entrySet()) { + Object value; + if (entry.getValue() == null || NULL.equals(entry.getValue())) { + value = null; + } else if (entry.getValue() instanceof JSONObject) { + value = ((JSONObject) entry.getValue()).toMap(); + } else if (entry.getValue() instanceof JSONArray) { + value = ((JSONArray) entry.getValue()).toList(); + } else { + value = entry.getValue(); + } + results.put(entry.getKey(), value); + } + return results; + } + + /** + * Create a new JSONException in a common format for incorrect conversions. + * @param key name of the key + * @param valueType the type of value being coerced to + * @param cause optional cause of the coercion failure + * @return JSONException that can be thrown. + */ + private static JSONException wrongValueFormatException( + String key, + String valueType, + Throwable cause) { + return new JSONException( + "JSONObject[" + quote(key) + "] is not a " + valueType + "." + , cause); + } + + /** + * Create a new JSONException in a common format for incorrect conversions. + * @param key name of the key + * @param valueType the type of value being coerced to + * @param cause optional cause of the coercion failure + * @return JSONException that can be thrown. + */ + private static JSONException wrongValueFormatException( + String key, + String valueType, + Object value, + Throwable cause) { + return new JSONException( + "JSONObject[" + quote(key) + "] is not a " + valueType + " (" + value + ")." + , cause); + } + + /** + * Create a new JSONException in a common format for recursive object definition. + * @param key name of the key + * @return JSONException that can be thrown. + */ + private static JSONException recursivelyDefinedObjectException(String key) { + return new JSONException( + "JavaBean object contains recursively defined member variable of key " + quote(key) + ); + } +} diff --git a/src/main/java/org/json/JSONPointer.java b/src/main/java/org/json/JSONPointer.java new file mode 100644 index 0000000..f1f7f33 --- /dev/null +++ b/src/main/java/org/json/JSONPointer.java @@ -0,0 +1,295 @@ +package org.json; + +import static java.lang.String.format; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +/** + * A JSON Pointer is a simple query language defined for JSON documents by + * RFC 6901. + * + * In a nutshell, JSONPointer allows the user to navigate into a JSON document + * using strings, and retrieve targeted objects, like a simple form of XPATH. + * Path segments are separated by the '/' char, which signifies the root of + * the document when it appears as the first char of the string. Array + * elements are navigated using ordinals, counting from 0. JSONPointer strings + * may be extended to any arbitrary number of segments. If the navigation + * is successful, the matched item is returned. A matched item may be a + * JSONObject, a JSONArray, or a JSON value. If the JSONPointer string building + * fails, an appropriate exception is thrown. If the navigation fails to find + * a match, a JSONPointerException is thrown. + * + * @author JSON.org + * @version 2016-05-14 + */ +public class JSONPointer { + + // used for URL encoding and decoding + private static final String ENCODING = "utf-8"; + + /** + * This class allows the user to build a JSONPointer in steps, using + * exactly one segment in each step. + */ + public static class Builder { + + // Segments for the eventual JSONPointer string + private final List refTokens = new ArrayList(); + + /** + * Creates a {@code JSONPointer} instance using the tokens previously set using the + * {@link #append(String)} method calls. + * @return a JSONPointer object + */ + public JSONPointer build() { + return new JSONPointer(this.refTokens); + } + + /** + * Adds an arbitrary token to the list of reference tokens. It can be any non-null value. + * + * Unlike in the case of JSON string or URI fragment representation of JSON pointers, the + * argument of this method MUST NOT be escaped. If you want to query the property called + * {@code "a~b"} then you should simply pass the {@code "a~b"} string as-is, there is no + * need to escape it as {@code "a~0b"}. + * + * @param token the new token to be appended to the list + * @return {@code this} + * @throws NullPointerException if {@code token} is null + */ + public Builder append(String token) { + if (token == null) { + throw new NullPointerException("token cannot be null"); + } + this.refTokens.add(token); + return this; + } + + /** + * Adds an integer to the reference token list. Although not necessarily, mostly this token will + * denote an array index. + * + * @param arrayIndex the array index to be added to the token list + * @return {@code this} + */ + public Builder append(int arrayIndex) { + this.refTokens.add(String.valueOf(arrayIndex)); + return this; + } + } + + /** + * Static factory method for {@link Builder}. Example usage: + * + *


+     * JSONPointer pointer = JSONPointer.builder()
+     *       .append("obj")
+     *       .append("other~key").append("another/key")
+     *       .append("\"")
+     *       .append(0)
+     *       .build();
+     * 
+ * + * @return a builder instance which can be used to construct a {@code JSONPointer} instance by chained + * {@link Builder#append(String)} calls. + */ + public static Builder builder() { + return new Builder(); + } + + // Segments for the JSONPointer string + private final List refTokens; + + /** + * Pre-parses and initializes a new {@code JSONPointer} instance. If you want to + * evaluate the same JSON Pointer on different JSON documents then it is recommended + * to keep the {@code JSONPointer} instances due to performance considerations. + * + * @param pointer the JSON String or URI Fragment representation of the JSON pointer. + * @throws IllegalArgumentException if {@code pointer} is not a valid JSON pointer + */ + public JSONPointer(final String pointer) { + if (pointer == null) { + throw new NullPointerException("pointer cannot be null"); + } + if (pointer.isEmpty() || pointer.equals("#")) { + this.refTokens = Collections.emptyList(); + return; + } + String refs; + if (pointer.startsWith("#/")) { + refs = pointer.substring(2); + try { + refs = URLDecoder.decode(refs, ENCODING); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } else if (pointer.startsWith("/")) { + refs = pointer.substring(1); + } else { + throw new IllegalArgumentException("a JSON pointer should start with '/' or '#/'"); + } + this.refTokens = new ArrayList(); + int slashIdx = -1; + int prevSlashIdx = 0; + do { + prevSlashIdx = slashIdx + 1; + slashIdx = refs.indexOf('/', prevSlashIdx); + if(prevSlashIdx == slashIdx || prevSlashIdx == refs.length()) { + // found 2 slashes in a row ( obj//next ) + // or single slash at the end of a string ( obj/test/ ) + this.refTokens.add(""); + } else if (slashIdx >= 0) { + final String token = refs.substring(prevSlashIdx, slashIdx); + this.refTokens.add(unescape(token)); + } else { + // last item after separator, or no separator at all. + final String token = refs.substring(prevSlashIdx); + this.refTokens.add(unescape(token)); + } + } while (slashIdx >= 0); + // using split does not take into account consecutive separators or "ending nulls" + //for (String token : refs.split("/")) { + // this.refTokens.add(unescape(token)); + //} + } + + public JSONPointer(List refTokens) { + this.refTokens = new ArrayList(refTokens); + } + + /** + * @see rfc6901 section 3 + */ + private static String unescape(String token) { + return token.replace("~1", "/").replace("~0", "~"); + } + + /** + * Evaluates this JSON Pointer on the given {@code document}. The {@code document} + * is usually a {@link JSONObject} or a {@link JSONArray} instance, but the empty + * JSON Pointer ({@code ""}) can be evaluated on any JSON values and in such case the + * returned value will be {@code document} itself. + * + * @param document the JSON document which should be the subject of querying. + * @return the result of the evaluation + * @throws JSONPointerException if an error occurs during evaluation + */ + public Object queryFrom(Object document) throws JSONPointerException { + if (this.refTokens.isEmpty()) { + return document; + } + Object current = document; + for (String token : this.refTokens) { + if (current instanceof JSONObject) { + current = ((JSONObject) current).opt(unescape(token)); + } else if (current instanceof JSONArray) { + current = readByIndexToken(current, token); + } else { + throw new JSONPointerException(format( + "value [%s] is not an array or object therefore its key %s cannot be resolved", current, + token)); + } + } + return current; + } + + /** + * Matches a JSONArray element by ordinal position + * @param current the JSONArray to be evaluated + * @param indexToken the array index in string form + * @return the matched object. If no matching item is found a + * @throws JSONPointerException is thrown if the index is out of bounds + */ + private static Object readByIndexToken(Object current, String indexToken) throws JSONPointerException { + try { + int index = Integer.parseInt(indexToken); + JSONArray currentArr = (JSONArray) current; + if (index >= currentArr.length()) { + throw new JSONPointerException(format("index %s is out of bounds - the array has %d elements", indexToken, + Integer.valueOf(currentArr.length()))); + } + try { + return currentArr.get(index); + } catch (JSONException e) { + throw new JSONPointerException("Error reading value at index position " + index, e); + } + } catch (NumberFormatException e) { + throw new JSONPointerException(format("%s is not an array index", indexToken), e); + } + } + + /** + * Returns a string representing the JSONPointer path value using string + * representation + */ + @Override + public String toString() { + StringBuilder rval = new StringBuilder(""); + for (String token: this.refTokens) { + rval.append('/').append(escape(token)); + } + return rval.toString(); + } + + /** + * Escapes path segment values to an unambiguous form. + * The escape char to be inserted is '~'. The chars to be escaped + * are ~, which maps to ~0, and /, which maps to ~1. + * @param token the JSONPointer segment value to be escaped + * @return the escaped value for the token + * + * @see rfc6901 section 3 + */ + private static String escape(String token) { + return token.replace("~", "~0") + .replace("/", "~1"); + } + + /** + * Returns a string representing the JSONPointer path value using URI + * fragment identifier representation + * @return a uri fragment string + */ + public String toURIFragment() { + try { + StringBuilder rval = new StringBuilder("#"); + for (String token : this.refTokens) { + rval.append('/').append(URLEncoder.encode(token, ENCODING)); + } + return rval.toString(); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/src/main/java/org/json/JSONPointerException.java b/src/main/java/org/json/JSONPointerException.java new file mode 100644 index 0000000..0ce1aeb --- /dev/null +++ b/src/main/java/org/json/JSONPointerException.java @@ -0,0 +1,45 @@ +package org.json; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +/** + * The JSONPointerException is thrown by {@link JSONPointer} if an error occurs + * during evaluating a pointer. + * + * @author JSON.org + * @version 2016-05-13 + */ +public class JSONPointerException extends JSONException { + private static final long serialVersionUID = 8872944667561856751L; + + public JSONPointerException(String message) { + super(message); + } + + public JSONPointerException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/main/java/org/json/JSONPropertyIgnore.java b/src/main/java/org/json/JSONPropertyIgnore.java new file mode 100644 index 0000000..682de74 --- /dev/null +++ b/src/main/java/org/json/JSONPropertyIgnore.java @@ -0,0 +1,43 @@ +package org.json; + +/* +Copyright (c) 2018 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Documented +@Retention(RUNTIME) +@Target({METHOD}) +/** + * Use this annotation on a getter method to override the Bean name + * parser for Bean -> JSONObject mapping. If this annotation is + * present at any level in the class hierarchy, then the method will + * not be serialized from the bean into the JSONObject. + */ +public @interface JSONPropertyIgnore { } diff --git a/src/main/java/org/json/JSONPropertyName.java b/src/main/java/org/json/JSONPropertyName.java new file mode 100644 index 0000000..a1bcd58 --- /dev/null +++ b/src/main/java/org/json/JSONPropertyName.java @@ -0,0 +1,47 @@ +package org.json; + +/* +Copyright (c) 2018 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Documented +@Retention(RUNTIME) +@Target({METHOD}) +/** + * Use this annotation on a getter method to override the Bean name + * parser for Bean -> JSONObject mapping. A value set to empty string "" + * will have the Bean parser fall back to the default field name processing. + */ +public @interface JSONPropertyName { + /** + * @return The name of the property as to be used in the JSON Object. + */ + String value(); +} diff --git a/src/main/java/org/json/JSONString.java b/src/main/java/org/json/JSONString.java new file mode 100644 index 0000000..bcd9a81 --- /dev/null +++ b/src/main/java/org/json/JSONString.java @@ -0,0 +1,43 @@ +package org.json; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ + +/** + * The JSONString interface allows a toJSONString() + * method so that a class can change the behavior of + * JSONObject.toString(), JSONArray.toString(), + * and JSONWriter.value(Object). The + * toJSONString method will be used instead of the default behavior + * of using the Object's toString() method and quoting the result. + */ +public interface JSONString { + /** + * The toJSONString method allows a class to produce its own JSON + * serialization. + * + * @return A strictly syntactically correct JSON text. + */ + public String toJSONString(); +} diff --git a/src/main/java/org/json/JSONStringer.java b/src/main/java/org/json/JSONStringer.java new file mode 100644 index 0000000..d2a4dfb --- /dev/null +++ b/src/main/java/org/json/JSONStringer.java @@ -0,0 +1,79 @@ +package org.json; + +/* +Copyright (c) 2006 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +import java.io.StringWriter; + +/** + * JSONStringer provides a quick and convenient way of producing JSON text. + * The texts produced strictly conform to JSON syntax rules. No whitespace is + * added, so the results are ready for transmission or storage. Each instance of + * JSONStringer can produce one JSON text. + *

+ * A JSONStringer instance provides a value method for appending + * values to the + * text, and a key + * method for adding keys before values in objects. There are array + * and endArray methods that make and bound array values, and + * object and endObject methods which make and bound + * object values. All of these methods return the JSONWriter instance, + * permitting cascade style. For example,

+ * myString = new JSONStringer()
+ *     .object()
+ *         .key("JSON")
+ *         .value("Hello, World!")
+ *     .endObject()
+ *     .toString();
which produces the string
+ * {"JSON":"Hello, World!"}
+ *

+ * The first method called must be array or object. + * There are no methods for adding commas or colons. JSONStringer adds them for + * you. Objects and arrays can be nested up to 200 levels deep. + *

+ * This can sometimes be easier than using a JSONObject to build a string. + * @author JSON.org + * @version 2015-12-09 + */ +public class JSONStringer extends JSONWriter { + /** + * Make a fresh JSONStringer. It can be used to build one JSON text. + */ + public JSONStringer() { + super(new StringWriter()); + } + + /** + * Return the JSON text. This method is used to obtain the product of the + * JSONStringer instance. It will return null if there was a + * problem in the construction of the JSON text (such as the calls to + * array were not properly balanced with calls to + * endArray). + * @return The JSON text. + */ + @Override + public String toString() { + return this.mode == 'd' ? this.writer.toString() : null; + } +} diff --git a/src/main/java/org/json/JSONTokener.java b/src/main/java/org/json/JSONTokener.java new file mode 100644 index 0000000..7f0c86a --- /dev/null +++ b/src/main/java/org/json/JSONTokener.java @@ -0,0 +1,545 @@ +package org.json; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringReader; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ + +/** + * A JSONTokener takes a source string and extracts characters and tokens from + * it. It is used by the JSONObject and JSONArray constructors to parse + * JSON source strings. + * @author JSON.org + * @version 2014-05-03 + */ +public class JSONTokener { + /** current read character position on the current line. */ + private long character; + /** flag to indicate if the end of the input has been found. */ + private boolean eof; + /** current read index of the input. */ + private long index; + /** current line of the input. */ + private long line; + /** previous character read from the input. */ + private char previous; + /** Reader for the input. */ + private final Reader reader; + /** flag to indicate that a previous character was requested. */ + private boolean usePrevious; + /** the number of characters read in the previous line. */ + private long characterPreviousLine; + + + /** + * Construct a JSONTokener from a Reader. The caller must close the Reader. + * + * @param reader A reader. + */ + public JSONTokener(Reader reader) { + this.reader = reader.markSupported() + ? reader + : new BufferedReader(reader); + this.eof = false; + this.usePrevious = false; + this.previous = 0; + this.index = 0; + this.character = 1; + this.characterPreviousLine = 0; + this.line = 1; + } + + + /** + * Construct a JSONTokener from an InputStream. The caller must close the input stream. + * @param inputStream The source. + */ + public JSONTokener(InputStream inputStream) { + this(new InputStreamReader(inputStream)); + } + + + /** + * Construct a JSONTokener from a string. + * + * @param s A source string. + */ + public JSONTokener(String s) { + this(new StringReader(s)); + } + + + /** + * Back up one character. This provides a sort of lookahead capability, + * so that you can test for a digit or letter before attempting to parse + * the next number or identifier. + * @throws JSONException Thrown if trying to step back more than 1 step + * or if already at the start of the string + */ + public void back() throws JSONException { + if (this.usePrevious || this.index <= 0) { + throw new JSONException("Stepping back two steps is not supported"); + } + this.decrementIndexes(); + this.usePrevious = true; + this.eof = false; + } + + /** + * Decrements the indexes for the {@link #back()} method based on the previous character read. + */ + private void decrementIndexes() { + this.index--; + if(this.previous=='\r' || this.previous == '\n') { + this.line--; + this.character=this.characterPreviousLine ; + } else if(this.character > 0){ + this.character--; + } + } + + /** + * Get the hex value of a character (base16). + * @param c A character between '0' and '9' or between 'A' and 'F' or + * between 'a' and 'f'. + * @return An int between 0 and 15, or -1 if c was not a hex digit. + */ + public static int dehexchar(char c) { + if (c >= '0' && c <= '9') { + return c - '0'; + } + if (c >= 'A' && c <= 'F') { + return c - ('A' - 10); + } + if (c >= 'a' && c <= 'f') { + return c - ('a' - 10); + } + return -1; + } + + /** + * Checks if the end of the input has been reached. + * + * @return true if at the end of the file and we didn't step back + */ + public boolean end() { + return this.eof && !this.usePrevious; + } + + + /** + * Determine if the source string still contains characters that next() + * can consume. + * @return true if not yet at the end of the source. + * @throws JSONException thrown if there is an error stepping forward + * or backward while checking for more data. + */ + public boolean more() throws JSONException { + if(this.usePrevious) { + return true; + } + try { + this.reader.mark(1); + } catch (IOException e) { + throw new JSONException("Unable to preserve stream position", e); + } + try { + // -1 is EOF, but next() can not consume the null character '\0' + if(this.reader.read() <= 0) { + this.eof = true; + return false; + } + this.reader.reset(); + } catch (IOException e) { + throw new JSONException("Unable to read the next character from the stream", e); + } + return true; + } + + + /** + * Get the next character in the source string. + * + * @return The next character, or 0 if past the end of the source string. + * @throws JSONException Thrown if there is an error reading the source string. + */ + public char next() throws JSONException { + int c; + if (this.usePrevious) { + this.usePrevious = false; + c = this.previous; + } else { + try { + c = this.reader.read(); + } catch (IOException exception) { + throw new JSONException(exception); + } + } + if (c <= 0) { // End of stream + this.eof = true; + return 0; + } + this.incrementIndexes(c); + this.previous = (char) c; + return this.previous; + } + + /** + * Get the last character read from the input or '\0' if nothing has been read yet. + * @return the last character read from the input. + */ + protected char getPrevious() { return this.previous;} + + /** + * Increments the internal indexes according to the previous character + * read and the character passed as the current character. + * @param c the current character read. + */ + private void incrementIndexes(int c) { + if(c > 0) { + this.index++; + if(c=='\r') { + this.line++; + this.characterPreviousLine = this.character; + this.character=0; + }else if (c=='\n') { + if(this.previous != '\r') { + this.line++; + this.characterPreviousLine = this.character; + } + this.character=0; + } else { + this.character++; + } + } + } + + /** + * Consume the next character, and check that it matches a specified + * character. + * @param c The character to match. + * @return The character. + * @throws JSONException if the character does not match. + */ + public char next(char c) throws JSONException { + char n = this.next(); + if (n != c) { + if(n > 0) { + throw this.syntaxError("Expected '" + c + "' and instead saw '" + + n + "'"); + } + throw this.syntaxError("Expected '" + c + "' and instead saw ''"); + } + return n; + } + + + /** + * Get the next n characters. + * + * @param n The number of characters to take. + * @return A string of n characters. + * @throws JSONException + * Substring bounds error if there are not + * n characters remaining in the source string. + */ + public String next(int n) throws JSONException { + if (n == 0) { + return ""; + } + + char[] chars = new char[n]; + int pos = 0; + + while (pos < n) { + chars[pos] = this.next(); + if (this.end()) { + throw this.syntaxError("Substring bounds error"); + } + pos += 1; + } + return new String(chars); + } + + + /** + * Get the next char in the string, skipping whitespace. + * @throws JSONException Thrown if there is an error reading the source string. + * @return A character, or 0 if there are no more characters. + */ + public char nextClean() throws JSONException { + for (;;) { + char c = this.next(); + if (c == 0 || c > ' ') { + return c; + } + } + } + + + /** + * Return the characters up to the next close quote character. + * Backslash processing is done. The formal JSON format does not + * allow strings in single quotes, but an implementation is allowed to + * accept them. + * @param quote The quoting character, either + * " (double quote) or + * ' (single quote). + * @return A String. + * @throws JSONException Unterminated string. + */ + public String nextString(char quote) throws JSONException { + char c; + StringBuilder sb = new StringBuilder(); + for (;;) { + c = this.next(); + switch (c) { + case 0: + case '\n': + case '\r': + throw this.syntaxError("Unterminated string"); + case '\\': + c = this.next(); + switch (c) { + case 'b': + sb.append('\b'); + break; + case 't': + sb.append('\t'); + break; + case 'n': + sb.append('\n'); + break; + case 'f': + sb.append('\f'); + break; + case 'r': + sb.append('\r'); + break; + case 'u': + try { + sb.append((char)Integer.parseInt(this.next(4), 16)); + } catch (NumberFormatException e) { + throw this.syntaxError("Illegal escape.", e); + } + break; + case '"': + case '\'': + case '\\': + case '/': + sb.append(c); + break; + default: + throw this.syntaxError("Illegal escape."); + } + break; + default: + if (c == quote) { + return sb.toString(); + } + sb.append(c); + } + } + } + + + /** + * Get the text up but not including the specified character or the + * end of line, whichever comes first. + * @param delimiter A delimiter character. + * @return A string. + * @throws JSONException Thrown if there is an error while searching + * for the delimiter + */ + public String nextTo(char delimiter) throws JSONException { + StringBuilder sb = new StringBuilder(); + for (;;) { + char c = this.next(); + if (c == delimiter || c == 0 || c == '\n' || c == '\r') { + if (c != 0) { + this.back(); + } + return sb.toString().trim(); + } + sb.append(c); + } + } + + + /** + * Get the text up but not including one of the specified delimiter + * characters or the end of line, whichever comes first. + * @param delimiters A set of delimiter characters. + * @return A string, trimmed. + * @throws JSONException Thrown if there is an error while searching + * for the delimiter + */ + public String nextTo(String delimiters) throws JSONException { + char c; + StringBuilder sb = new StringBuilder(); + for (;;) { + c = this.next(); + if (delimiters.indexOf(c) >= 0 || c == 0 || + c == '\n' || c == '\r') { + if (c != 0) { + this.back(); + } + return sb.toString().trim(); + } + sb.append(c); + } + } + + + /** + * Get the next value. The value can be a Boolean, Double, Integer, + * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object. + * @throws JSONException If syntax error. + * + * @return An object. + */ + public Object nextValue() throws JSONException { + char c = this.nextClean(); + String string; + + switch (c) { + case '"': + case '\'': + return this.nextString(c); + case '{': + this.back(); + try { + return new JSONObject(this); + } catch (StackOverflowError e) { + throw new JSONException("JSON Array or Object depth too large to process.", e); + } + case '[': + this.back(); + try { + return new JSONArray(this); + } catch (StackOverflowError e) { + throw new JSONException("JSON Array or Object depth too large to process.", e); + } + } + + /* + * Handle unquoted text. This could be the values true, false, or + * null, or it can be a number. An implementation (such as this one) + * is allowed to also accept non-standard forms. + * + * Accumulate characters until we reach the end of the text or a + * formatting character. + */ + + StringBuilder sb = new StringBuilder(); + while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) { + sb.append(c); + c = this.next(); + } + if (!this.eof) { + this.back(); + } + + string = sb.toString().trim(); + if ("".equals(string)) { + throw this.syntaxError("Missing value"); + } + return JSONObject.stringToValue(string); + } + + + /** + * Skip characters until the next character is the requested character. + * If the requested character is not found, no characters are skipped. + * @param to A character to skip to. + * @return The requested character, or zero if the requested character + * is not found. + * @throws JSONException Thrown if there is an error while searching + * for the to character + */ + public char skipTo(char to) throws JSONException { + char c; + try { + long startIndex = this.index; + long startCharacter = this.character; + long startLine = this.line; + this.reader.mark(1000000); + do { + c = this.next(); + if (c == 0) { + // in some readers, reset() may throw an exception if + // the remaining portion of the input is greater than + // the mark size (1,000,000 above). + this.reader.reset(); + this.index = startIndex; + this.character = startCharacter; + this.line = startLine; + return 0; + } + } while (c != to); + this.reader.mark(1); + } catch (IOException exception) { + throw new JSONException(exception); + } + this.back(); + return c; + } + + /** + * Make a JSONException to signal a syntax error. + * + * @param message The error message. + * @return A JSONException object, suitable for throwing + */ + public JSONException syntaxError(String message) { + return new JSONException(message + this.toString()); + } + + /** + * Make a JSONException to signal a syntax error. + * + * @param message The error message. + * @param causedBy The throwable that caused the error. + * @return A JSONException object, suitable for throwing + */ + public JSONException syntaxError(String message, Throwable causedBy) { + return new JSONException(message + this.toString(), causedBy); + } + + /** + * Make a printable string of this JSONTokener. + * + * @return " at {index} [character {character} line {line}]" + */ + @Override + public String toString() { + return " at " + this.index + " [character " + this.character + " line " + + this.line + "]"; + } +} diff --git a/src/main/java/org/json/JSONWriter.java b/src/main/java/org/json/JSONWriter.java new file mode 100644 index 0000000..dafb1b2 --- /dev/null +++ b/src/main/java/org/json/JSONWriter.java @@ -0,0 +1,414 @@ +package org.json; + +import java.io.IOException; +import java.util.Collection; +import java.util.Map; + +/* +Copyright (c) 2006 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +/** + * JSONWriter provides a quick and convenient way of producing JSON text. + * The texts produced strictly conform to JSON syntax rules. No whitespace is + * added, so the results are ready for transmission or storage. Each instance of + * JSONWriter can produce one JSON text. + *

+ * A JSONWriter instance provides a value method for appending + * values to the + * text, and a key + * method for adding keys before values in objects. There are array + * and endArray methods that make and bound array values, and + * object and endObject methods which make and bound + * object values. All of these methods return the JSONWriter instance, + * permitting a cascade style. For example,

+ * new JSONWriter(myWriter)
+ *     .object()
+ *         .key("JSON")
+ *         .value("Hello, World!")
+ *     .endObject();
which writes
+ * {"JSON":"Hello, World!"}
+ *

+ * The first method called must be array or object. + * There are no methods for adding commas or colons. JSONWriter adds them for + * you. Objects and arrays can be nested up to 200 levels deep. + *

+ * This can sometimes be easier than using a JSONObject to build a string. + * @author JSON.org + * @version 2016-08-08 + */ +public class JSONWriter { + private static final int maxdepth = 200; + + /** + * The comma flag determines if a comma should be output before the next + * value. + */ + private boolean comma; + + /** + * The current mode. Values: + * 'a' (array), + * 'd' (done), + * 'i' (initial), + * 'k' (key), + * 'o' (object). + */ + protected char mode; + + /** + * The object/array stack. + */ + private final JSONObject stack[]; + + /** + * The stack top index. A value of 0 indicates that the stack is empty. + */ + private int top; + + /** + * The writer that will receive the output. + */ + protected Appendable writer; + + /** + * Make a fresh JSONWriter. It can be used to build one JSON text. + * @param w an appendable object + */ + public JSONWriter(Appendable w) { + this.comma = false; + this.mode = 'i'; + this.stack = new JSONObject[maxdepth]; + this.top = 0; + this.writer = w; + } + + /** + * Append a value. + * @param string A string value. + * @return this + * @throws JSONException If the value is out of sequence. + */ + private JSONWriter append(String string) throws JSONException { + if (string == null) { + throw new JSONException("Null pointer"); + } + if (this.mode == 'o' || this.mode == 'a') { + try { + if (this.comma && this.mode == 'a') { + this.writer.append(','); + } + this.writer.append(string); + } catch (IOException e) { + // Android as of API 25 does not support this exception constructor + // however we won't worry about it. If an exception is happening here + // it will just throw a "Method not found" exception instead. + throw new JSONException(e); + } + if (this.mode == 'o') { + this.mode = 'k'; + } + this.comma = true; + return this; + } + throw new JSONException("Value out of sequence."); + } + + /** + * Begin appending a new array. All values until the balancing + * endArray will be appended to this array. The + * endArray method must be called to mark the array's end. + * @return this + * @throws JSONException If the nesting is too deep, or if the object is + * started in the wrong place (for example as a key or after the end of the + * outermost array or object). + */ + public JSONWriter array() throws JSONException { + if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') { + this.push(null); + this.append("["); + this.comma = false; + return this; + } + throw new JSONException("Misplaced array."); + } + + /** + * End something. + * @param m Mode + * @param c Closing character + * @return this + * @throws JSONException If unbalanced. + */ + private JSONWriter end(char m, char c) throws JSONException { + if (this.mode != m) { + throw new JSONException(m == 'a' + ? "Misplaced endArray." + : "Misplaced endObject."); + } + this.pop(m); + try { + this.writer.append(c); + } catch (IOException e) { + // Android as of API 25 does not support this exception constructor + // however we won't worry about it. If an exception is happening here + // it will just throw a "Method not found" exception instead. + throw new JSONException(e); + } + this.comma = true; + return this; + } + + /** + * End an array. This method most be called to balance calls to + * array. + * @return this + * @throws JSONException If incorrectly nested. + */ + public JSONWriter endArray() throws JSONException { + return this.end('a', ']'); + } + + /** + * End an object. This method most be called to balance calls to + * object. + * @return this + * @throws JSONException If incorrectly nested. + */ + public JSONWriter endObject() throws JSONException { + return this.end('k', '}'); + } + + /** + * Append a key. The key will be associated with the next value. In an + * object, every value must be preceded by a key. + * @param string A key string. + * @return this + * @throws JSONException If the key is out of place. For example, keys + * do not belong in arrays or if the key is null. + */ + public JSONWriter key(String string) throws JSONException { + if (string == null) { + throw new JSONException("Null key."); + } + if (this.mode == 'k') { + try { + JSONObject topObject = this.stack[this.top - 1]; + // don't use the built in putOnce method to maintain Android support + if(topObject.has(string)) { + throw new JSONException("Duplicate key \"" + string + "\""); + } + topObject.put(string, true); + if (this.comma) { + this.writer.append(','); + } + this.writer.append(JSONObject.quote(string)); + this.writer.append(':'); + this.comma = false; + this.mode = 'o'; + return this; + } catch (IOException e) { + // Android as of API 25 does not support this exception constructor + // however we won't worry about it. If an exception is happening here + // it will just throw a "Method not found" exception instead. + throw new JSONException(e); + } + } + throw new JSONException("Misplaced key."); + } + + + /** + * Begin appending a new object. All keys and values until the balancing + * endObject will be appended to this object. The + * endObject method must be called to mark the object's end. + * @return this + * @throws JSONException If the nesting is too deep, or if the object is + * started in the wrong place (for example as a key or after the end of the + * outermost array or object). + */ + public JSONWriter object() throws JSONException { + if (this.mode == 'i') { + this.mode = 'o'; + } + if (this.mode == 'o' || this.mode == 'a') { + this.append("{"); + this.push(new JSONObject()); + this.comma = false; + return this; + } + throw new JSONException("Misplaced object."); + + } + + + /** + * Pop an array or object scope. + * @param c The scope to close. + * @throws JSONException If nesting is wrong. + */ + private void pop(char c) throws JSONException { + if (this.top <= 0) { + throw new JSONException("Nesting error."); + } + char m = this.stack[this.top - 1] == null ? 'a' : 'k'; + if (m != c) { + throw new JSONException("Nesting error."); + } + this.top -= 1; + this.mode = this.top == 0 + ? 'd' + : this.stack[this.top - 1] == null + ? 'a' + : 'k'; + } + + /** + * Push an array or object scope. + * @param jo The scope to open. + * @throws JSONException If nesting is too deep. + */ + private void push(JSONObject jo) throws JSONException { + if (this.top >= maxdepth) { + throw new JSONException("Nesting too deep."); + } + this.stack[this.top] = jo; + this.mode = jo == null ? 'a' : 'k'; + this.top += 1; + } + + /** + * Make a JSON text of an Object value. If the object has an + * value.toJSONString() method, then that method will be used to produce the + * JSON text. The method is required to produce a strictly conforming text. + * If the object does not contain a toJSONString method (which is the most + * common case), then a text will be produced by other means. If the value + * is an array or Collection, then a JSONArray will be made from it and its + * toJSONString method will be called. If the value is a MAP, then a + * JSONObject will be made from it and its toJSONString method will be + * called. Otherwise, the value's toString method will be called, and the + * result will be quoted. + * + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @param value + * The value to be serialized. + * @return a printable, displayable, transmittable representation of the + * object, beginning with { (left + * brace) and ending with } (right + * brace). + * @throws JSONException + * If the value is or contains an invalid number. + */ + public static String valueToString(Object value) throws JSONException { + if (value == null || value.equals(null)) { + return "null"; + } + if (value instanceof JSONString) { + String object; + try { + object = ((JSONString) value).toJSONString(); + } catch (Exception e) { + throw new JSONException(e); + } + if (object != null) { + return object; + } + throw new JSONException("Bad value from toJSONString: " + object); + } + if (value instanceof Number) { + // not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex + final String numberAsString = JSONObject.numberToString((Number) value); + if(JSONObject.NUMBER_PATTERN.matcher(numberAsString).matches()) { + // Close enough to a JSON number that we will return it unquoted + return numberAsString; + } + // The Number value is not a valid JSON number. + // Instead we will quote it as a string + return JSONObject.quote(numberAsString); + } + if (value instanceof Boolean || value instanceof JSONObject + || value instanceof JSONArray) { + return value.toString(); + } + if (value instanceof Map) { + Map map = (Map) value; + return new JSONObject(map).toString(); + } + if (value instanceof Collection) { + Collection coll = (Collection) value; + return new JSONArray(coll).toString(); + } + if (value.getClass().isArray()) { + return new JSONArray(value).toString(); + } + if(value instanceof Enum){ + return JSONObject.quote(((Enum)value).name()); + } + return JSONObject.quote(value.toString()); + } + + /** + * Append either the value true or the value + * false. + * @param b A boolean. + * @return this + * @throws JSONException if a called function has an error + */ + public JSONWriter value(boolean b) throws JSONException { + return this.append(b ? "true" : "false"); + } + + /** + * Append a double value. + * @param d A double. + * @return this + * @throws JSONException If the number is not finite. + */ + public JSONWriter value(double d) throws JSONException { + return this.value(Double.valueOf(d)); + } + + /** + * Append a long value. + * @param l A long. + * @return this + * @throws JSONException if a called function has an error + */ + public JSONWriter value(long l) throws JSONException { + return this.append(Long.toString(l)); + } + + + /** + * Append an object value. + * @param object The object to append. It can be null, or a Boolean, Number, + * String, JSONObject, or JSONArray, or an object that implements JSONString. + * @return this + * @throws JSONException If the value is out of sequence. + */ + public JSONWriter value(Object object) throws JSONException { + return this.append(valueToString(object)); + } +} diff --git a/src/main/java/org/json/Property.java b/src/main/java/org/json/Property.java new file mode 100644 index 0000000..7caeebb --- /dev/null +++ b/src/main/java/org/json/Property.java @@ -0,0 +1,75 @@ +package org.json; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +import java.util.Enumeration; +import java.util.Properties; + +/** + * Converts a Property file data into JSONObject and back. + * @author JSON.org + * @version 2015-05-05 + */ +public class Property { + /** + * Converts a property file object into a JSONObject. The property file object is a table of name value pairs. + * @param properties java.util.Properties + * @return JSONObject + * @throws JSONException if a called function has an error + */ + public static JSONObject toJSONObject(java.util.Properties properties) throws JSONException { + // can't use the new constructor for Android support + // JSONObject jo = new JSONObject(properties == null ? 0 : properties.size()); + JSONObject jo = new JSONObject(); + if (properties != null && !properties.isEmpty()) { + Enumeration enumProperties = properties.propertyNames(); + while(enumProperties.hasMoreElements()) { + String name = (String)enumProperties.nextElement(); + jo.put(name, properties.getProperty(name)); + } + } + return jo; + } + + /** + * Converts the JSONObject into a property file object. + * @param jo JSONObject + * @return java.util.Properties + * @throws JSONException if a called function has an error + */ + public static Properties toProperties(JSONObject jo) throws JSONException { + Properties properties = new Properties(); + if (jo != null) { + // Don't use the new entrySet API to maintain Android support + for (final String key : jo.keySet()) { + Object value = jo.opt(key); + if (!JSONObject.NULL.equals(value)) { + properties.put(key, value.toString()); + } + } + } + return properties; + } +} diff --git a/src/main/java/org/json/XML.java b/src/main/java/org/json/XML.java new file mode 100644 index 0000000..33838a1 --- /dev/null +++ b/src/main/java/org/json/XML.java @@ -0,0 +1,883 @@ +package org.json; + +/* +Copyright (c) 2015 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +import java.io.Reader; +import java.io.StringReader; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Iterator; + + +/** + * This provides static methods to convert an XML text into a JSONObject, and to + * covert a JSONObject into an XML text. + * + * @author JSON.org + * @version 2016-08-10 + */ +@SuppressWarnings("boxing") +public class XML { + + /** The Character '&'. */ + public static final Character AMP = '&'; + + /** The Character '''. */ + public static final Character APOS = '\''; + + /** The Character '!'. */ + public static final Character BANG = '!'; + + /** The Character '='. */ + public static final Character EQ = '='; + + /** The Character

{@code '>'. }
*/ + public static final Character GT = '>'; + + /** The Character '<'. */ + public static final Character LT = '<'; + + /** The Character '?'. */ + public static final Character QUEST = '?'; + + /** The Character '"'. */ + public static final Character QUOT = '"'; + + /** The Character '/'. */ + public static final Character SLASH = '/'; + + /** + * Null attribute name + */ + public static final String NULL_ATTR = "xsi:nil"; + + public static final String TYPE_ATTR = "xsi:type"; + + /** + * Creates an iterator for navigating Code Points in a string instead of + * characters. Once Java7 support is dropped, this can be replaced with + * + * string.codePoints() + * + * which is available in Java8 and above. + * + * @see http://stackoverflow.com/a/21791059/6030888 + */ + private static Iterable codePointIterator(final String string) { + return new Iterable() { + @Override + public Iterator iterator() { + return new Iterator() { + private int nextIndex = 0; + private int length = string.length(); + + @Override + public boolean hasNext() { + return this.nextIndex < this.length; + } + + @Override + public Integer next() { + int result = string.codePointAt(this.nextIndex); + this.nextIndex += Character.charCount(result); + return result; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + }; + } + + /** + * Replace special characters with XML escapes: + * + *
{@code 
+     * & (ampersand) is replaced by &amp;
+     * < (less than) is replaced by &lt;
+     * > (greater than) is replaced by &gt;
+     * " (double quote) is replaced by &quot;
+     * ' (single quote / apostrophe) is replaced by &apos;
+     * }
+ * + * @param string + * The string to be escaped. + * @return The escaped string. + */ + public static String escape(String string) { + StringBuilder sb = new StringBuilder(string.length()); + for (final int cp : codePointIterator(string)) { + switch (cp) { + case '&': + sb.append("&"); + break; + case '<': + sb.append("<"); + break; + case '>': + sb.append(">"); + break; + case '"': + sb.append("""); + break; + case '\'': + sb.append("'"); + break; + default: + if (mustEscape(cp)) { + sb.append("&#x"); + sb.append(Integer.toHexString(cp)); + sb.append(';'); + } else { + sb.appendCodePoint(cp); + } + } + } + return sb.toString(); + } + + /** + * @param cp code point to test + * @return true if the code point is not valid for an XML + */ + private static boolean mustEscape(int cp) { + /* Valid range from https://www.w3.org/TR/REC-xml/#charsets + * + * #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] + * + * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. + */ + // isISOControl is true when (cp >= 0 && cp <= 0x1F) || (cp >= 0x7F && cp <= 0x9F) + // all ISO control characters are out of range except tabs and new lines + return (Character.isISOControl(cp) + && cp != 0x9 + && cp != 0xA + && cp != 0xD + ) || !( + // valid the range of acceptable characters that aren't control + (cp >= 0x20 && cp <= 0xD7FF) + || (cp >= 0xE000 && cp <= 0xFFFD) + || (cp >= 0x10000 && cp <= 0x10FFFF) + ) + ; + } + + /** + * Removes XML escapes from the string. + * + * @param string + * string to remove escapes from + * @return string with converted entities + */ + public static String unescape(String string) { + StringBuilder sb = new StringBuilder(string.length()); + for (int i = 0, length = string.length(); i < length; i++) { + char c = string.charAt(i); + if (c == '&') { + final int semic = string.indexOf(';', i); + if (semic > i) { + final String entity = string.substring(i + 1, semic); + sb.append(XMLTokener.unescapeEntity(entity)); + // skip past the entity we just parsed. + i += entity.length() + 1; + } else { + // this shouldn't happen in most cases since the parser + // errors on unclosed entries. + sb.append(c); + } + } else { + // not part of an entity + sb.append(c); + } + } + return sb.toString(); + } + + /** + * Throw an exception if the string contains whitespace. Whitespace is not + * allowed in tagNames and attributes. + * + * @param string + * A string. + * @throws JSONException Thrown if the string contains whitespace or is empty. + */ + public static void noSpace(String string) throws JSONException { + int i, length = string.length(); + if (length == 0) { + throw new JSONException("Empty string."); + } + for (i = 0; i < length; i += 1) { + if (Character.isWhitespace(string.charAt(i))) { + throw new JSONException("'" + string + + "' contains a space character."); + } + } + } + + /** + * Scan the content following the named tag, attaching it to the context. + * + * @param x + * The XMLTokener containing the source string. + * @param context + * The JSONObject that will include the new material. + * @param name + * The tag name. + * @return true if the close tag is processed. + * @throws JSONException + */ + private static boolean parse(XMLTokener x, JSONObject context, String name, XMLParserConfiguration config) + throws JSONException { + char c; + int i; + JSONObject jsonObject = null; + String string; + String tagName; + Object token; + XMLXsiTypeConverter xmlXsiTypeConverter; + + // Test for and skip past these forms: + // + // + // + // + // Report errors for these forms: + // <> + // <= + // << + + token = x.nextToken(); + + // "); + return false; + } + x.back(); + } else if (c == '[') { + token = x.nextToken(); + if ("CDATA".equals(token)) { + if (x.next() == '[') { + string = x.nextCDATA(); + if (string.length() > 0) { + context.accumulate(config.getcDataTagName(), string); + } + return false; + } + } + throw x.syntaxError("Expected 'CDATA['"); + } + i = 1; + do { + token = x.nextMeta(); + if (token == null) { + throw x.syntaxError("Missing '>' after ' 0); + return false; + } else if (token == QUEST) { + + // "); + return false; + } else if (token == SLASH) { + + // Close tag + if (x.nextToken() != GT) { + throw x.syntaxError("Misshaped tag"); + } + if (config.getForceList().contains(tagName)) { + // Force the value to be an array + if (nilAttributeFound) { + context.append(tagName, JSONObject.NULL); + } else if (jsonObject.length() > 0) { + context.append(tagName, jsonObject); + } else { + context.put(tagName, new JSONArray()); + } + } else { + if (nilAttributeFound) { + context.accumulate(tagName, JSONObject.NULL); + } else if (jsonObject.length() > 0) { + context.accumulate(tagName, jsonObject); + } else { + context.accumulate(tagName, ""); + } + } + return false; + + } else if (token == GT) { + // Content, between <...> and + for (;;) { + token = x.nextContent(); + if (token == null) { + if (tagName != null) { + throw x.syntaxError("Unclosed tag " + tagName); + } + return false; + } else if (token instanceof String) { + string = (String) token; + if (string.length() > 0) { + if(xmlXsiTypeConverter != null) { + jsonObject.accumulate(config.getcDataTagName(), + stringToValue(string, xmlXsiTypeConverter)); + } else { + jsonObject.accumulate(config.getcDataTagName(), + config.isKeepStrings() ? string : stringToValue(string)); + } + } + + } else if (token == LT) { + // Nested element + if (parse(x, jsonObject, tagName, config)) { + if (config.getForceList().contains(tagName)) { + // Force the value to be an array + if (jsonObject.length() == 0) { + context.put(tagName, new JSONArray()); + } else if (jsonObject.length() == 1 + && jsonObject.opt(config.getcDataTagName()) != null) { + context.append(tagName, jsonObject.opt(config.getcDataTagName())); + } else { + context.append(tagName, jsonObject); + } + } else { + if (jsonObject.length() == 0) { + context.accumulate(tagName, ""); + } else if (jsonObject.length() == 1 + && jsonObject.opt(config.getcDataTagName()) != null) { + context.accumulate(tagName, jsonObject.opt(config.getcDataTagName())); + } else { + context.accumulate(tagName, jsonObject); + } + } + + return false; + } + } + } + } else { + throw x.syntaxError("Misshaped tag"); + } + } + } + } + + /** + * This method tries to convert the given string value to the target object + * @param string String to convert + * @param typeConverter value converter to convert string to integer, boolean e.t.c + * @return JSON value of this string or the string + */ + public static Object stringToValue(String string, XMLXsiTypeConverter typeConverter) { + if(typeConverter != null) { + return typeConverter.convert(string); + } + return stringToValue(string); + } + + /** + * This method is the same as {@link JSONObject#stringToValue(String)}. + * + * @param string String to convert + * @return JSON value of this string or the string + */ + // To maintain compatibility with the Android API, this method is a direct copy of + // the one in JSONObject. Changes made here should be reflected there. + // This method should not make calls out of the XML object. + public static Object stringToValue(String string) { + if ("".equals(string)) { + return string; + } + + // check JSON key words true/false/null + if ("true".equalsIgnoreCase(string)) { + return Boolean.TRUE; + } + if ("false".equalsIgnoreCase(string)) { + return Boolean.FALSE; + } + if ("null".equalsIgnoreCase(string)) { + return JSONObject.NULL; + } + + /* + * If it might be a number, try converting it. If a number cannot be + * produced, then the value will just be a string. + */ + + char initial = string.charAt(0); + if ((initial >= '0' && initial <= '9') || initial == '-') { + try { + return stringToNumber(string); + } catch (Exception ignore) { + } + } + return string; + } + + /** + * direct copy of {@link JSONObject#stringToNumber(String)} to maintain Android support. + */ + private static Number stringToNumber(final String val) throws NumberFormatException { + char initial = val.charAt(0); + if ((initial >= '0' && initial <= '9') || initial == '-') { + // decimal representation + if (isDecimalNotation(val)) { + // Use a BigDecimal all the time so we keep the original + // representation. BigDecimal doesn't support -0.0, ensure we + // keep that by forcing a decimal. + try { + BigDecimal bd = new BigDecimal(val); + if(initial == '-' && BigDecimal.ZERO.compareTo(bd)==0) { + return Double.valueOf(-0.0); + } + return bd; + } catch (NumberFormatException retryAsDouble) { + // this is to support "Hex Floats" like this: 0x1.0P-1074 + try { + Double d = Double.valueOf(val); + if(d.isNaN() || d.isInfinite()) { + throw new NumberFormatException("val ["+val+"] is not a valid number."); + } + return d; + } catch (NumberFormatException ignore) { + throw new NumberFormatException("val ["+val+"] is not a valid number."); + } + } + } + // block items like 00 01 etc. Java number parsers treat these as Octal. + if(initial == '0' && val.length() > 1) { + char at1 = val.charAt(1); + if(at1 >= '0' && at1 <= '9') { + throw new NumberFormatException("val ["+val+"] is not a valid number."); + } + } else if (initial == '-' && val.length() > 2) { + char at1 = val.charAt(1); + char at2 = val.charAt(2); + if(at1 == '0' && at2 >= '0' && at2 <= '9') { + throw new NumberFormatException("val ["+val+"] is not a valid number."); + } + } + // integer representation. + // This will narrow any values to the smallest reasonable Object representation + // (Integer, Long, or BigInteger) + + // BigInteger down conversion: We use a similar bitLength compare as + // BigInteger#intValueExact uses. Increases GC, but objects hold + // only what they need. i.e. Less runtime overhead if the value is + // long lived. + BigInteger bi = new BigInteger(val); + if(bi.bitLength() <= 31){ + return Integer.valueOf(bi.intValue()); + } + if(bi.bitLength() <= 63){ + return Long.valueOf(bi.longValue()); + } + return bi; + } + throw new NumberFormatException("val ["+val+"] is not a valid number."); + } + + /** + * direct copy of {@link JSONObject#isDecimalNotation(String)} to maintain Android support. + */ + private static boolean isDecimalNotation(final String val) { + return val.indexOf('.') > -1 || val.indexOf('e') > -1 + || val.indexOf('E') > -1 || "-0".equals(val); + } + + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONObject. Some information may be lost in this transformation because + * JSON is a data format and XML is a document format. XML uses elements, + * attributes, and content text, while JSON uses unordered collections of + * name/value pairs and arrays of values. JSON does not does not like to + * distinguish between elements and attributes. Sequences of similar + * elements are represented as JSONArrays. Content text may be placed in a + * "content" member. Comments, prologs, DTDs, and
{@code 
+     * <[ [ ]]>}
+ * are ignored. + * + * @param string + * The source string. + * @return A JSONObject containing the structured data from the XML string. + * @throws JSONException Thrown if there is an errors while parsing the string + */ + public static JSONObject toJSONObject(String string) throws JSONException { + return toJSONObject(string, XMLParserConfiguration.ORIGINAL); + } + + /** + * Convert a well-formed (but not necessarily valid) XML into a + * JSONObject. Some information may be lost in this transformation because + * JSON is a data format and XML is a document format. XML uses elements, + * attributes, and content text, while JSON uses unordered collections of + * name/value pairs and arrays of values. JSON does not does not like to + * distinguish between elements and attributes. Sequences of similar + * elements are represented as JSONArrays. Content text may be placed in a + * "content" member. Comments, prologs, DTDs, and
{@code 
+     * <[ [ ]]>}
+ * are ignored. + * + * @param reader The XML source reader. + * @return A JSONObject containing the structured data from the XML string. + * @throws JSONException Thrown if there is an errors while parsing the string + */ + public static JSONObject toJSONObject(Reader reader) throws JSONException { + return toJSONObject(reader, XMLParserConfiguration.ORIGINAL); + } + + /** + * Convert a well-formed (but not necessarily valid) XML into a + * JSONObject. Some information may be lost in this transformation because + * JSON is a data format and XML is a document format. XML uses elements, + * attributes, and content text, while JSON uses unordered collections of + * name/value pairs and arrays of values. JSON does not does not like to + * distinguish between elements and attributes. Sequences of similar + * elements are represented as JSONArrays. Content text may be placed in a + * "content" member. Comments, prologs, DTDs, and
{@code
+     * <[ [ ]]>}
+ * are ignored. + * + * All values are converted as strings, for 1, 01, 29.0 will not be coerced to + * numbers but will instead be the exact value as seen in the XML document. + * + * @param reader The XML source reader. + * @param keepStrings If true, then values will not be coerced into boolean + * or numeric values and will instead be left as strings + * @return A JSONObject containing the structured data from the XML string. + * @throws JSONException Thrown if there is an errors while parsing the string + */ + public static JSONObject toJSONObject(Reader reader, boolean keepStrings) throws JSONException { + if(keepStrings) { + return toJSONObject(reader, XMLParserConfiguration.KEEP_STRINGS); + } + return toJSONObject(reader, XMLParserConfiguration.ORIGINAL); + } + + /** + * Convert a well-formed (but not necessarily valid) XML into a + * JSONObject. Some information may be lost in this transformation because + * JSON is a data format and XML is a document format. XML uses elements, + * attributes, and content text, while JSON uses unordered collections of + * name/value pairs and arrays of values. JSON does not does not like to + * distinguish between elements and attributes. Sequences of similar + * elements are represented as JSONArrays. Content text may be placed in a + * "content" member. Comments, prologs, DTDs, and
{@code
+     * <[ [ ]]>}
+ * are ignored. + * + * All values are converted as strings, for 1, 01, 29.0 will not be coerced to + * numbers but will instead be the exact value as seen in the XML document. + * + * @param reader The XML source reader. + * @param config Configuration options for the parser + * @return A JSONObject containing the structured data from the XML string. + * @throws JSONException Thrown if there is an errors while parsing the string + */ + public static JSONObject toJSONObject(Reader reader, XMLParserConfiguration config) throws JSONException { + JSONObject jo = new JSONObject(); + XMLTokener x = new XMLTokener(reader); + while (x.more()) { + x.skipPast("<"); + if(x.more()) { + parse(x, jo, null, config); + } + } + return jo; + } + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONObject. Some information may be lost in this transformation because + * JSON is a data format and XML is a document format. XML uses elements, + * attributes, and content text, while JSON uses unordered collections of + * name/value pairs and arrays of values. JSON does not does not like to + * distinguish between elements and attributes. Sequences of similar + * elements are represented as JSONArrays. Content text may be placed in a + * "content" member. Comments, prologs, DTDs, and
{@code 
+     * <[ [ ]]>}
+ * are ignored. + * + * All values are converted as strings, for 1, 01, 29.0 will not be coerced to + * numbers but will instead be the exact value as seen in the XML document. + * + * @param string + * The source string. + * @param keepStrings If true, then values will not be coerced into boolean + * or numeric values and will instead be left as strings + * @return A JSONObject containing the structured data from the XML string. + * @throws JSONException Thrown if there is an errors while parsing the string + */ + public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { + return toJSONObject(new StringReader(string), keepStrings); + } + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONObject. Some information may be lost in this transformation because + * JSON is a data format and XML is a document format. XML uses elements, + * attributes, and content text, while JSON uses unordered collections of + * name/value pairs and arrays of values. JSON does not does not like to + * distinguish between elements and attributes. Sequences of similar + * elements are represented as JSONArrays. Content text may be placed in a + * "content" member. Comments, prologs, DTDs, and
{@code 
+     * <[ [ ]]>}
+ * are ignored. + * + * All values are converted as strings, for 1, 01, 29.0 will not be coerced to + * numbers but will instead be the exact value as seen in the XML document. + * + * @param string + * The source string. + * @param config Configuration options for the parser. + * @return A JSONObject containing the structured data from the XML string. + * @throws JSONException Thrown if there is an errors while parsing the string + */ + public static JSONObject toJSONObject(String string, XMLParserConfiguration config) throws JSONException { + return toJSONObject(new StringReader(string), config); + } + + /** + * Convert a JSONObject into a well-formed, element-normal XML string. + * + * @param object + * A JSONObject. + * @return A string. + * @throws JSONException Thrown if there is an error parsing the string + */ + public static String toString(Object object) throws JSONException { + return toString(object, null, XMLParserConfiguration.ORIGINAL); + } + + /** + * Convert a JSONObject into a well-formed, element-normal XML string. + * + * @param object + * A JSONObject. + * @param tagName + * The optional name of the enclosing tag. + * @return A string. + * @throws JSONException Thrown if there is an error parsing the string + */ + public static String toString(final Object object, final String tagName) { + return toString(object, tagName, XMLParserConfiguration.ORIGINAL); + } + + /** + * Convert a JSONObject into a well-formed, element-normal XML string. + * + * @param object + * A JSONObject. + * @param tagName + * The optional name of the enclosing tag. + * @param config + * Configuration that can control output to XML. + * @return A string. + * @throws JSONException Thrown if there is an error parsing the string + */ + public static String toString(final Object object, final String tagName, final XMLParserConfiguration config) + throws JSONException { + StringBuilder sb = new StringBuilder(); + JSONArray ja; + JSONObject jo; + String string; + + if (object instanceof JSONObject) { + + // Emit + if (tagName != null) { + sb.append('<'); + sb.append(tagName); + sb.append('>'); + } + + // Loop thru the keys. + // don't use the new entrySet accessor to maintain Android Support + jo = (JSONObject) object; + for (final String key : jo.keySet()) { + Object value = jo.opt(key); + if (value == null) { + value = ""; + } else if (value.getClass().isArray()) { + value = new JSONArray(value); + } + + // Emit content in body + if (key.equals(config.getcDataTagName())) { + if (value instanceof JSONArray) { + ja = (JSONArray) value; + int jaLength = ja.length(); + // don't use the new iterator API to maintain support for Android + for (int i = 0; i < jaLength; i++) { + if (i > 0) { + sb.append('\n'); + } + Object val = ja.opt(i); + sb.append(escape(val.toString())); + } + } else { + sb.append(escape(value.toString())); + } + + // Emit an array of similar keys + + } else if (value instanceof JSONArray) { + ja = (JSONArray) value; + int jaLength = ja.length(); + // don't use the new iterator API to maintain support for Android + for (int i = 0; i < jaLength; i++) { + Object val = ja.opt(i); + if (val instanceof JSONArray) { + sb.append('<'); + sb.append(key); + sb.append('>'); + sb.append(toString(val, null, config)); + sb.append("'); + } else { + sb.append(toString(val, key, config)); + } + } + } else if ("".equals(value)) { + sb.append('<'); + sb.append(key); + sb.append("/>"); + + // Emit a new tag + + } else { + sb.append(toString(value, key, config)); + } + } + if (tagName != null) { + + // Emit the close tag + sb.append("'); + } + return sb.toString(); + + } + + if (object != null && (object instanceof JSONArray || object.getClass().isArray())) { + if(object.getClass().isArray()) { + ja = new JSONArray(object); + } else { + ja = (JSONArray) object; + } + int jaLength = ja.length(); + // don't use the new iterator API to maintain support for Android + for (int i = 0; i < jaLength; i++) { + Object val = ja.opt(i); + // XML does not have good support for arrays. If an array + // appears in a place where XML is lacking, synthesize an + // element. + sb.append(toString(val, tagName == null ? "array" : tagName, config)); + } + return sb.toString(); + } + + string = (object == null) ? "null" : escape(object.toString()); + return (tagName == null) ? "\"" + string + "\"" + : (string.length() == 0) ? "<" + tagName + "/>" : "<" + tagName + + ">" + string + ""; + + } +} diff --git a/src/main/java/org/json/XMLParserConfiguration.java b/src/main/java/org/json/XMLParserConfiguration.java new file mode 100644 index 0000000..a1fd63e --- /dev/null +++ b/src/main/java/org/json/XMLParserConfiguration.java @@ -0,0 +1,320 @@ +package org.json; +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + + +/** + * Configuration object for the XML parser. The configuration is immutable. + * @author AylwardJ + */ +@SuppressWarnings({""}) +public class XMLParserConfiguration { + /** Original Configuration of the XML Parser. */ + public static final XMLParserConfiguration ORIGINAL + = new XMLParserConfiguration(); + /** Original configuration of the XML Parser except that values are kept as strings. */ + public static final XMLParserConfiguration KEEP_STRINGS + = new XMLParserConfiguration().withKeepStrings(true); + + /** + * When parsing the XML into JSON, specifies if values should be kept as strings (true), or if + * they should try to be guessed into JSON values (numeric, boolean, string) + */ + private boolean keepStrings; + + /** + * The name of the key in a JSON Object that indicates a CDATA section. Historically this has + * been the value "content" but can be changed. Use null to indicate no CDATA + * processing. + */ + private String cDataTagName; + + /** + * When parsing the XML into JSON, specifies if values with attribute xsi:nil="true" + * should be kept as attribute(false), or they should be converted to + * null(true) + */ + private boolean convertNilAttributeToNull; + + /** + * This will allow type conversion for values in XML if xsi:type attribute is defined + */ + private Map> xsiTypeMap; + + /** + * When parsing the XML into JSON, specifies the tags whose values should be converted + * to arrays + */ + private Set forceList; + + /** + * Default parser configuration. Does not keep strings (tries to implicitly convert + * values), and the CDATA Tag Name is "content". + */ + public XMLParserConfiguration () { + this.keepStrings = false; + this.cDataTagName = "content"; + this.convertNilAttributeToNull = false; + this.xsiTypeMap = Collections.emptyMap(); + this.forceList = Collections.emptySet(); + } + + /** + * Configure the parser string processing and use the default CDATA Tag Name as "content". + * @param keepStrings true to parse all values as string. + * false to try and convert XML string values into a JSON value. + * @deprecated This constructor has been deprecated in favor of using the new builder + * pattern for the configuration. + * This constructor may be removed in a future release. + */ + @Deprecated + public XMLParserConfiguration (final boolean keepStrings) { + this(keepStrings, "content", false); + } + + /** + * Configure the parser string processing to try and convert XML values to JSON values and + * use the passed CDATA Tag Name the processing value. Pass null to + * disable CDATA processing + * @param cDataTagName null to disable CDATA processing. Any other value + * to use that value as the JSONObject key name to process as CDATA. + * @deprecated This constructor has been deprecated in favor of using the new builder + * pattern for the configuration. + * This constructor may be removed in a future release. + */ + @Deprecated + public XMLParserConfiguration (final String cDataTagName) { + this(false, cDataTagName, false); + } + + /** + * Configure the parser to use custom settings. + * @param keepStrings true to parse all values as string. + * false to try and convert XML string values into a JSON value. + * @param cDataTagName null to disable CDATA processing. Any other value + * to use that value as the JSONObject key name to process as CDATA. + * @deprecated This constructor has been deprecated in favor of using the new builder + * pattern for the configuration. + * This constructor may be removed in a future release. + */ + @Deprecated + public XMLParserConfiguration (final boolean keepStrings, final String cDataTagName) { + this.keepStrings = keepStrings; + this.cDataTagName = cDataTagName; + this.convertNilAttributeToNull = false; + } + + /** + * Configure the parser to use custom settings. + * @param keepStrings true to parse all values as string. + * false to try and convert XML string values into a JSON value. + * @param cDataTagName null to disable CDATA processing. Any other value + * to use that value as the JSONObject key name to process as CDATA. + * @param convertNilAttributeToNull true to parse values with attribute xsi:nil="true" as null. + * false to parse values with attribute xsi:nil="true" as {"xsi:nil":true}. + * @deprecated This constructor has been deprecated in favor of using the new builder + * pattern for the configuration. + * This constructor may be removed or marked private in a future release. + */ + @Deprecated + public XMLParserConfiguration (final boolean keepStrings, final String cDataTagName, final boolean convertNilAttributeToNull) { + this.keepStrings = keepStrings; + this.cDataTagName = cDataTagName; + this.convertNilAttributeToNull = convertNilAttributeToNull; + } + + /** + * Configure the parser to use custom settings. + * @param keepStrings true to parse all values as string. + * false to try and convert XML string values into a JSON value. + * @param cDataTagName null to disable CDATA processing. Any other value + * to use that value as the JSONObject key name to process as CDATA. + * @param convertNilAttributeToNull true to parse values with attribute xsi:nil="true" as null. + * false to parse values with attribute xsi:nil="true" as {"xsi:nil":true}. + * @param xsiTypeMap new HashMap>() to parse values with attribute + * xsi:type="integer" as integer, xsi:type="string" as string + * @param forceList new HashSet() to parse the provided tags' values as arrays + */ + private XMLParserConfiguration (final boolean keepStrings, final String cDataTagName, + final boolean convertNilAttributeToNull, final Map> xsiTypeMap, final Set forceList ) { + this.keepStrings = keepStrings; + this.cDataTagName = cDataTagName; + this.convertNilAttributeToNull = convertNilAttributeToNull; + this.xsiTypeMap = Collections.unmodifiableMap(xsiTypeMap); + this.forceList = Collections.unmodifiableSet(forceList); + } + + /** + * Provides a new instance of the same configuration. + */ + @Override + protected XMLParserConfiguration clone() { + // future modifications to this method should always ensure a "deep" + // clone in the case of collections. i.e. if a Map is added as a configuration + // item, a new map instance should be created and if possible each value in the + // map should be cloned as well. If the values of the map are known to also + // be immutable, then a shallow clone of the map is acceptable. + return new XMLParserConfiguration( + this.keepStrings, + this.cDataTagName, + this.convertNilAttributeToNull, + this.xsiTypeMap, + this.forceList + ); + } + + /** + * When parsing the XML into JSON, specifies if values should be kept as strings (true), or if + * they should try to be guessed into JSON values (numeric, boolean, string) + * + * @return The keepStrings configuration value. + */ + public boolean isKeepStrings() { + return this.keepStrings; + } + + /** + * When parsing the XML into JSON, specifies if values should be kept as strings (true), or if + * they should try to be guessed into JSON values (numeric, boolean, string) + * + * @param newVal + * new value to use for the keepStrings configuration option. + * + * @return The existing configuration will not be modified. A new configuration is returned. + */ + public XMLParserConfiguration withKeepStrings(final boolean newVal) { + XMLParserConfiguration newConfig = this.clone(); + newConfig.keepStrings = newVal; + return newConfig; + } + + /** + * The name of the key in a JSON Object that indicates a CDATA section. Historically this has + * been the value "content" but can be changed. Use null to indicate no CDATA + * processing. + * + * @return The cDataTagName configuration value. + */ + public String getcDataTagName() { + return this.cDataTagName; + } + + /** + * The name of the key in a JSON Object that indicates a CDATA section. Historically this has + * been the value "content" but can be changed. Use null to indicate no CDATA + * processing. + * + * @param newVal + * new value to use for the cDataTagName configuration option. + * + * @return The existing configuration will not be modified. A new configuration is returned. + */ + public XMLParserConfiguration withcDataTagName(final String newVal) { + XMLParserConfiguration newConfig = this.clone(); + newConfig.cDataTagName = newVal; + return newConfig; + } + + /** + * When parsing the XML into JSON, specifies if values with attribute xsi:nil="true" + * should be kept as attribute(false), or they should be converted to + * null(true) + * + * @return The convertNilAttributeToNull configuration value. + */ + public boolean isConvertNilAttributeToNull() { + return this.convertNilAttributeToNull; + } + + /** + * When parsing the XML into JSON, specifies if values with attribute xsi:nil="true" + * should be kept as attribute(false), or they should be converted to + * null(true) + * + * @param newVal + * new value to use for the convertNilAttributeToNull configuration option. + * + * @return The existing configuration will not be modified. A new configuration is returned. + */ + public XMLParserConfiguration withConvertNilAttributeToNull(final boolean newVal) { + XMLParserConfiguration newConfig = this.clone(); + newConfig.convertNilAttributeToNull = newVal; + return newConfig; + } + + /** + * When parsing the XML into JSON, specifies that the values with attribute xsi:type + * will be converted to target type defined to client in this configuration + * {@code Map>} to parse values with attribute + * xsi:type="integer" as integer, xsi:type="string" as string + * @return xsiTypeMap unmodifiable configuration map. + */ + public Map> getXsiTypeMap() { + return this.xsiTypeMap; + } + + /** + * When parsing the XML into JSON, specifies that the values with attribute xsi:type + * will be converted to target type defined to client in this configuration + * {@code Map>} to parse values with attribute + * xsi:type="integer" as integer, xsi:type="string" as string + * @param xsiTypeMap {@code new HashMap>()} to parse values with attribute + * xsi:type="integer" as integer, xsi:type="string" as string + * @return The existing configuration will not be modified. A new configuration is returned. + */ + public XMLParserConfiguration withXsiTypeMap(final Map> xsiTypeMap) { + XMLParserConfiguration newConfig = this.clone(); + Map> cloneXsiTypeMap = new HashMap>(xsiTypeMap); + newConfig.xsiTypeMap = Collections.unmodifiableMap(cloneXsiTypeMap); + return newConfig; + } + + /** + * When parsing the XML into JSON, specifies that tags that will be converted to arrays + * in this configuration {@code Set} to parse the provided tags' values as arrays + * @return forceList unmodifiable configuration set. + */ + public Set getForceList() { + return this.forceList; + } + + /** + * When parsing the XML into JSON, specifies that tags that will be converted to arrays + * in this configuration {@code Set} to parse the provided tags' values as arrays + * @param forceList {@code new HashSet()} to parse the provided tags' values as arrays + * @return The existing configuration will not be modified. A new configuration is returned. + */ + public XMLParserConfiguration withForceList(final Set forceList) { + XMLParserConfiguration newConfig = this.clone(); + Set cloneForceList = new HashSet(forceList); + newConfig.forceList = Collections.unmodifiableSet(cloneForceList); + return newConfig; + } +} diff --git a/src/main/java/org/json/XMLTokener.java b/src/main/java/org/json/XMLTokener.java new file mode 100644 index 0000000..3bbd382 --- /dev/null +++ b/src/main/java/org/json/XMLTokener.java @@ -0,0 +1,416 @@ +package org.json; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +import java.io.Reader; + +/** + * The XMLTokener extends the JSONTokener to provide additional methods + * for the parsing of XML texts. + * @author JSON.org + * @version 2015-12-09 + */ +public class XMLTokener extends JSONTokener { + + + /** The table of entity values. It initially contains Character values for + * amp, apos, gt, lt, quot. + */ + public static final java.util.HashMap entity; + + static { + entity = new java.util.HashMap(8); + entity.put("amp", XML.AMP); + entity.put("apos", XML.APOS); + entity.put("gt", XML.GT); + entity.put("lt", XML.LT); + entity.put("quot", XML.QUOT); + } + + /** + * Construct an XMLTokener from a Reader. + * @param r A source reader. + */ + public XMLTokener(Reader r) { + super(r); + } + + /** + * Construct an XMLTokener from a string. + * @param s A source string. + */ + public XMLTokener(String s) { + super(s); + } + + /** + * Get the text in the CDATA block. + * @return The string up to the ]]>. + * @throws JSONException If the ]]> is not found. + */ + public String nextCDATA() throws JSONException { + char c; + int i; + StringBuilder sb = new StringBuilder(); + while (more()) { + c = next(); + sb.append(c); + i = sb.length() - 3; + if (i >= 0 && sb.charAt(i) == ']' && + sb.charAt(i + 1) == ']' && sb.charAt(i + 2) == '>') { + sb.setLength(i); + return sb.toString(); + } + } + throw syntaxError("Unclosed CDATA"); + } + + + /** + * Get the next XML outer token, trimming whitespace. There are two kinds + * of tokens: the
{@code '<' }
character which begins a markup + * tag, and the content + * text between markup tags. + * + * @return A string, or a
{@code '<' }
Character, or null if + * there is no more source text. + * @throws JSONException if a called function has an error + */ + public Object nextContent() throws JSONException { + char c; + StringBuilder sb; + do { + c = next(); + } while (Character.isWhitespace(c)); + if (c == 0) { + return null; + } + if (c == '<') { + return XML.LT; + } + sb = new StringBuilder(); + for (;;) { + if (c == 0) { + return sb.toString().trim(); + } + if (c == '<') { + back(); + return sb.toString().trim(); + } + if (c == '&') { + sb.append(nextEntity(c)); + } else { + sb.append(c); + } + c = next(); + } + } + + + /** + *
{@code
+     * Return the next entity. These entities are translated to Characters:
+     *     &  '  >  <  ".
+     * }
+ * @param ampersand An ampersand character. + * @return A Character or an entity String if the entity is not recognized. + * @throws JSONException If missing ';' in XML entity. + */ + public Object nextEntity(@SuppressWarnings("unused") char ampersand) throws JSONException { + StringBuilder sb = new StringBuilder(); + for (;;) { + char c = next(); + if (Character.isLetterOrDigit(c) || c == '#') { + sb.append(Character.toLowerCase(c)); + } else if (c == ';') { + break; + } else { + throw syntaxError("Missing ';' in XML entity: &" + sb); + } + } + String string = sb.toString(); + return unescapeEntity(string); + } + + /** + * Unescape an XML entity encoding; + * @param e entity (only the actual entity value, not the preceding & or ending ; + * @return + */ + static String unescapeEntity(String e) { + // validate + if (e == null || e.isEmpty()) { + return ""; + } + // if our entity is an encoded unicode point, parse it. + if (e.charAt(0) == '#') { + int cp; + if (e.charAt(1) == 'x' || e.charAt(1) == 'X') { + // hex encoded unicode + cp = Integer.parseInt(e.substring(2), 16); + } else { + // decimal encoded unicode + cp = Integer.parseInt(e.substring(1)); + } + return new String(new int[] {cp},0,1); + } + Character knownEntity = entity.get(e); + if(knownEntity==null) { + // we don't know the entity so keep it encoded + return '&' + e + ';'; + } + return knownEntity.toString(); + } + + + /** + *
{@code 
+     * Returns the next XML meta token. This is used for skipping over 
+     * and  structures.
+     *  }
+ * @return
{@code Syntax characters (< > / = ! ?) are returned as
+     *  Character, and strings and names are returned as Boolean. We don't care
+     *  what the values actually are.
+     *  }
+ * @throws JSONException If a string is not properly closed or if the XML + * is badly structured. + */ + public Object nextMeta() throws JSONException { + char c; + char q; + do { + c = next(); + } while (Character.isWhitespace(c)); + switch (c) { + case 0: + throw syntaxError("Misshaped meta tag"); + case '<': + return XML.LT; + case '>': + return XML.GT; + case '/': + return XML.SLASH; + case '=': + return XML.EQ; + case '!': + return XML.BANG; + case '?': + return XML.QUEST; + case '"': + case '\'': + q = c; + for (;;) { + c = next(); + if (c == 0) { + throw syntaxError("Unterminated string"); + } + if (c == q) { + return Boolean.TRUE; + } + } + default: + for (;;) { + c = next(); + if (Character.isWhitespace(c)) { + return Boolean.TRUE; + } + switch (c) { + case 0: + throw syntaxError("Unterminated string"); + case '<': + case '>': + case '/': + case '=': + case '!': + case '?': + case '"': + case '\'': + back(); + return Boolean.TRUE; + } + } + } + } + + + /** + *
{@code
+     * Get the next XML Token. These tokens are found inside of angle
+     * brackets. It may be one of these characters: / > = ! ? or it
+     * may be a string wrapped in single quotes or double quotes, or it may be a
+     * name.
+     * }
+ * @return a String or a Character. + * @throws JSONException If the XML is not well formed. + */ + public Object nextToken() throws JSONException { + char c; + char q; + StringBuilder sb; + do { + c = next(); + } while (Character.isWhitespace(c)); + switch (c) { + case 0: + throw syntaxError("Misshaped element"); + case '<': + throw syntaxError("Misplaced '<'"); + case '>': + return XML.GT; + case '/': + return XML.SLASH; + case '=': + return XML.EQ; + case '!': + return XML.BANG; + case '?': + return XML.QUEST; + +// Quoted string + + case '"': + case '\'': + q = c; + sb = new StringBuilder(); + for (;;) { + c = next(); + if (c == 0) { + throw syntaxError("Unterminated string"); + } + if (c == q) { + return sb.toString(); + } + if (c == '&') { + sb.append(nextEntity(c)); + } else { + sb.append(c); + } + } + default: + +// Name + + sb = new StringBuilder(); + for (;;) { + sb.append(c); + c = next(); + if (Character.isWhitespace(c)) { + return sb.toString(); + } + switch (c) { + case 0: + return sb.toString(); + case '>': + case '/': + case '=': + case '!': + case '?': + case '[': + case ']': + back(); + return sb.toString(); + case '<': + case '"': + case '\'': + throw syntaxError("Bad character in a name"); + } + } + } + } + + + /** + * Skip characters until past the requested string. + * If it is not found, we are left at the end of the source with a result of false. + * @param to A string to skip past. + */ + // The Android implementation of JSONTokener has a public method of public void skipPast(String to) + // even though ours does not have that method, to have API compatibility, our method in the subclass + // should match. + public void skipPast(String to) { + boolean b; + char c; + int i; + int j; + int offset = 0; + int length = to.length(); + char[] circle = new char[length]; + + /* + * First fill the circle buffer with as many characters as are in the + * to string. If we reach an early end, bail. + */ + + for (i = 0; i < length; i += 1) { + c = next(); + if (c == 0) { + return; + } + circle[i] = c; + } + + /* We will loop, possibly for all of the remaining characters. */ + + for (;;) { + j = offset; + b = true; + + /* Compare the circle buffer with the to string. */ + + for (i = 0; i < length; i += 1) { + if (circle[j] != to.charAt(i)) { + b = false; + break; + } + j += 1; + if (j >= length) { + j -= length; + } + } + + /* If we exit the loop with b intact, then victory is ours. */ + + if (b) { + return; + } + + /* Get the next character. If there isn't one, then defeat is ours. */ + + c = next(); + if (c == 0) { + return; + } + /* + * Shove the character in the circle buffer and advance the + * circle offset. The offset is mod n. + */ + circle[offset] = c; + offset += 1; + if (offset >= length) { + offset -= length; + } + } + } +} diff --git a/src/main/java/org/json/XMLXsiTypeConverter.java b/src/main/java/org/json/XMLXsiTypeConverter.java new file mode 100644 index 0000000..0f8a8c3 --- /dev/null +++ b/src/main/java/org/json/XMLXsiTypeConverter.java @@ -0,0 +1,66 @@ +package org.json; +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +/** + * Type conversion configuration interface to be used with xsi:type attributes. + *
+ * XML Sample
+ * {@code
+ *      
+ *          12345
+ *          54321
+ *      
+ * }
+ * JSON Output
+ * {@code
+ *     {
+ *         "root" : {
+ *             "asString" : "12345",
+ *             "asInt": 54321
+ *         }
+ *     }
+ * }
+ *
+ * Usage
+ * {@code
+ *      Map> xsiTypeMap = new HashMap>();
+ *      xsiTypeMap.put("string", new XMLXsiTypeConverter() {
+ *          @Override public String convert(final String value) {
+ *              return value;
+ *          }
+ *      });
+ *      xsiTypeMap.put("integer", new XMLXsiTypeConverter() {
+ *          @Override public Integer convert(final String value) {
+ *              return Integer.valueOf(value);
+ *          }
+ *      });
+ * }
+ * 
+ * @author kumar529 + * @param return type of convert method + */ +public interface XMLXsiTypeConverter { + T convert(String value); +}