1
0
mirror of https://github.com/chylex/Hardcore-Ender-Expansion-2.git synced 2025-09-15 14:32:09 +02:00

7 Commits

94 changed files with 671 additions and 3072 deletions

1
.gitignore vendored
View File

@@ -14,7 +14,6 @@ out
!.idea/kotlinc.xml !.idea/kotlinc.xml
!.idea/statistic.xml !.idea/statistic.xml
!.idea/vcs.xml !.idea/vcs.xml
!.idea/shelf
# eclipse # eclipse
bin bin

View File

@@ -1,4 +0,0 @@
<changelist name="Datagen_Recipes" date="1601734824200" recycled="true">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Datagen_Recipes/shelved.patch" />
<option name="DESCRIPTION" value="Datagen Recipes" />
</changelist>

View File

@@ -1,79 +0,0 @@
Index: data/src/main/java/chylex/hee/datagen/DataGen.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
<+>package chylex.hee.datagen\nimport chylex.hee.HEE\nimport chylex.hee.datagen.client.BlockItemModels\nimport chylex.hee.datagen.client.BlockModels\nimport chylex.hee.datagen.client.BlockStates\nimport chylex.hee.datagen.client.ItemModels\nimport chylex.hee.system.forge.SubscribeAllEvents\nimport chylex.hee.system.forge.SubscribeEvent\nimport net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus.MOD\nimport net.minecraftforge.fml.event.lifecycle.GatherDataEvent\n\n@SubscribeAllEvents(modid = HEE.ID, bus = MOD)\nobject DataGen{\n\t@SubscribeEvent\n\tfun register(e: GatherDataEvent){\n\t\tval modid = HEE.ID\n\t\tval helper = e.existingFileHelper\n\t\t\n\t\twith(e.generator){\n\t\t\tif (e.includeClient()){\n\t\t\t\taddProvider(BlockStates(this, modid, helper))\n\t\t\t\taddProvider(BlockModels(this, modid, helper))\n\t\t\t\taddProvider(BlockItemModels(this, modid, helper))\n\t\t\t\taddProvider(ItemModels(this, modid, helper))\n\t\t\t}\n\t\t}\n\t}\n}\n
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- a/data/src/main/java/chylex/hee/datagen/DataGen.kt (revision f8888e0a3b33898551301124a0879cea12fc1f06)
+++ b/data/src/main/java/chylex/hee/datagen/DataGen.kt (date 1601732788951)
@@ -4,6 +4,7 @@
import chylex.hee.datagen.client.BlockModels
import chylex.hee.datagen.client.BlockStates
import chylex.hee.datagen.client.ItemModels
+import chylex.hee.datagen.server.Recipes
import chylex.hee.system.forge.SubscribeAllEvents
import chylex.hee.system.forge.SubscribeEvent
import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus.MOD
@@ -23,6 +24,10 @@
addProvider(BlockItemModels(this, modid, helper))
addProvider(ItemModels(this, modid, helper))
}
+
+ if (e.includeServer()){
+ addProvider(Recipes(this))
+ }
}
}
}
Index: data/src/main/java/chylex/hee/datagen/server/Recipes.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- /dev/null (date 1601733265753)
+++ b/data/src/main/java/chylex/hee/datagen/server/Recipes.kt (date 1601733265753)
@@ -0,0 +1,15 @@
+package chylex.hee.datagen.server
+import chylex.hee.datagen.server.util.ingredients
+import chylex.hee.datagen.server.util.shapeless
+import chylex.hee.init.ModItems
+import net.minecraft.data.DataGenerator
+import net.minecraft.data.IFinishedRecipe
+import net.minecraft.data.RecipeProvider
+import net.minecraft.item.Items
+import java.util.function.Consumer
+
+class Recipes(generator: DataGenerator) : RecipeProvider(generator){
+ override fun registerRecipes(consumer: Consumer<IFinishedRecipe>) = with(consumer){
+ shapeless(ModItems.ALTERATION_NEXUS, 1){ ingredients(Items.DIAMOND, Items.ENDER_EYE, ModItems.ANCIENT_DUST, ModItems.ETHEREUM) }
+ }
+}
Index: data/src/main/java/chylex/hee/datagen/server/util/RecipeProviderExt.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- /dev/null (date 1601733249382)
+++ b/data/src/main/java/chylex/hee/datagen/server/util/RecipeProviderExt.kt (date 1601733249382)
@@ -0,0 +1,20 @@
+package chylex.hee.datagen.server.util
+import net.minecraft.data.IFinishedRecipe
+import net.minecraft.data.ShapedRecipeBuilder
+import net.minecraft.data.ShapelessRecipeBuilder
+import net.minecraft.util.IItemProvider
+import java.util.function.Consumer
+
+fun Consumer<IFinishedRecipe>.shaped(result: IItemProvider, amount: Int, callback: ShapedRecipeBuilder.() -> Unit){
+ ShapedRecipeBuilder(result, amount).apply(callback).build(this)
+}
+
+fun Consumer<IFinishedRecipe>.shapeless(result: IItemProvider, amount: Int, callback: ShapelessRecipeBuilder.() -> Unit){
+ ShapelessRecipeBuilder(result, amount).apply(callback).build(this)
+}
+
+fun ShapelessRecipeBuilder.ingredients(vararg ingredients: IItemProvider){
+ for(ingredient in ingredients){
+ this.addIngredient(ingredient)
+ }
+}

View File

@@ -1,4 +0,0 @@
<changelist name="Development3" date="1601983889370" recycled="true">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Development3/shelved.patch" />
<option name="DESCRIPTION" value="Development" />
</changelist>

File diff suppressed because one or more lines are too long

4
.idea/shelf/Dust.xml generated
View File

@@ -1,4 +0,0 @@
<changelist name="Dust" date="1590783410567" recycled="false">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Dust/shelved.patch" />
<option name="DESCRIPTION" value="Dust" />
</changelist>

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +0,0 @@
<changelist name="EnderEyeAttack_kt" date="1601761992769" recycled="true">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/EnderEyeAttack_kt/shelved.patch" />
<option name="DESCRIPTION" value="EnderEyeAttack.kt" />
</changelist>

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +0,0 @@
<changelist name="Ender_Eye" date="1595119986895" recycled="true">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Ender_Eye/shelved.patch" />
<option name="DESCRIPTION" value="Ender Eye" />
</changelist>

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +0,0 @@
<changelist name="Ender_Eye_Stuff" date="1601351827334" recycled="true">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Ender_Eye_Stuff/shelved.patch" />
<option name="DESCRIPTION" value="Ender Eye Stuff" />
</changelist>

File diff suppressed because one or more lines are too long

4
.idea/shelf/Eye.xml generated
View File

@@ -1,4 +0,0 @@
<changelist name="Eye" date="1605472809585" recycled="true">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Eye/shelved.patch" />
<option name="DESCRIPTION" value="Eye" />
</changelist>

File diff suppressed because one or more lines are too long

4
.idea/shelf/Ideas.xml generated
View File

@@ -1,4 +0,0 @@
<changelist name="Ideas" date="1595089578362" recycled="false">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Ideas/shelved.patch" />
<option name="DESCRIPTION" value="Ideas" />
</changelist>

File diff suppressed because one or more lines are too long

4
.idea/shelf/Later.xml generated
View File

@@ -1,4 +0,0 @@
<changelist name="Later" date="1579750352473" recycled="false">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Later/shelved.patch" />
<option name="DESCRIPTION" value="Later" />
</changelist>

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +0,0 @@
<changelist name="Later1" date="1607753523089" recycled="true">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Later1/shelved.patch" />
<option name="DESCRIPTION" value="Later" />
</changelist>

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +0,0 @@
<changelist name="Later2" date="1610732422264" recycled="false">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Later2/shelved.patch" />
<option name="DESCRIPTION" value="Later" />
</changelist>

View File

@@ -1,19 +0,0 @@
Index: src/system/src/main/java/chylex/hee/game/entity/EntitySelector.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
<+>package chylex.hee.game.entity\n\nimport chylex.hee.system.math.square\nimport net.minecraft.entity.Entity\nimport net.minecraft.util.math.AxisAlignedBB\nimport net.minecraft.util.math.Vec3d\nimport net.minecraft.world.IEntityReader\nimport java.util.function.Predicate\n\n@Suppress(\"NOTHING_TO_INLINE\")\nclass EntitySelector(private val world: IEntityReader, private val predicate: Predicate<in Entity>) {\n\tfun <T : Entity> inBox(cls: Class<T>, aabb: AxisAlignedBB): List<T> {\n\t\treturn world.getEntitiesWithinAABB(cls, aabb, predicate)\n\t}\n\t\n\tfun <T : Entity> inRange(cls: Class<T>, point: Vec3d, range: Double): List<T> {\n\t\tval aabb = AxisAlignedBB(point.x - range, point.y - range, point.z - range, point.x + range, point.y + range, point.z + range)\n\t\tval rangeSq = square(range)\n\t\t\n\t\treturn world.getEntitiesWithinAABB(cls, aabb) { predicate.test(it) && it!!.posVec.squareDistanceTo(point) <= rangeSq }\n\t}\n\t\n\t// Reified\n\t\n\tinline fun <reified T : Entity> inBox(aabb: AxisAlignedBB) = inBox(T::class.java, aabb)\n\tinline fun <reified T : Entity> inRange(point: Vec3d, range: Double) = inRange(T::class.java, point, range)\n\t\n\t// General\n\t\n\tinline fun allInBox(aabb: AxisAlignedBB) = inBox(Entity::class.java, aabb)\n\tinline fun allInRange(point: Vec3d, range: Double) = inRange(Entity::class.java, point, range)\n}\n
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/system/src/main/java/chylex/hee/game/entity/EntitySelector.kt b/src/system/src/main/java/chylex/hee/game/entity/EntitySelector.kt
--- a/src/system/src/main/java/chylex/hee/game/entity/EntitySelector.kt (revision 276df769798cbd4fd8154c5ebca0001dd8639545)
+++ b/src/system/src/main/java/chylex/hee/game/entity/EntitySelector.kt (date 1609259090000)
@@ -20,6 +20,8 @@
return world.getEntitiesWithinAABB(cls, aabb) { predicate.test(it) && it!!.posVec.squareDistanceTo(point) <= rangeSq }
}
+ // TODO only loaded? fuck
+
// Reified
inline fun <reified T : Entity> inBox(aabb: AxisAlignedBB) = inBox(T::class.java, aabb)

View File

@@ -1,4 +0,0 @@
<changelist name="Recipe_Datagen" date="1601740449134" recycled="false">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Recipe_Datagen/shelved.patch" />
<option name="DESCRIPTION" value="Recipe Datagen" />
</changelist>

View File

@@ -1,47 +0,0 @@
Index: data/src/main/java/chylex/hee/datagen/server/Recipes.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- /dev/null (date 1601740133630)
+++ b/data/src/main/java/chylex/hee/datagen/server/Recipes.kt (date 1601740133630)
@@ -0,0 +1,11 @@
+package chylex.hee.datagen.server
+import net.minecraft.data.DataGenerator
+import net.minecraft.data.IFinishedRecipe
+import net.minecraft.data.RecipeProvider
+import java.util.function.Consumer
+
+class Recipes(generator: DataGenerator) : RecipeProvider(generator){
+ override fun registerRecipes(consumer: Consumer<IFinishedRecipe>) = with(consumer){
+ // shapeless(ModItems.ALTERATION_NEXUS, 1){ ingredients(Items.DIAMOND, Items.ENDER_EYE, ModItems.ANCIENT_DUST, ModItems.ETHEREUM) }
+ }
+}
Index: data/src/main/java/chylex/hee/datagen/server/util/RecipeProviderExt.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- /dev/null (date 1601734823610)
+++ b/data/src/main/java/chylex/hee/datagen/server/util/RecipeProviderExt.kt (date 1601734823610)
@@ -0,0 +1,20 @@
+package chylex.hee.datagen.server.util
+import net.minecraft.data.IFinishedRecipe
+import net.minecraft.data.ShapedRecipeBuilder
+import net.minecraft.data.ShapelessRecipeBuilder
+import net.minecraft.util.IItemProvider
+import java.util.function.Consumer
+
+fun Consumer<IFinishedRecipe>.shaped(result: IItemProvider, amount: Int, callback: ShapedRecipeBuilder.() -> Unit){
+ ShapedRecipeBuilder(result, amount).apply(callback).build(this)
+}
+
+fun Consumer<IFinishedRecipe>.shapeless(result: IItemProvider, amount: Int, callback: ShapelessRecipeBuilder.() -> Unit){
+ ShapelessRecipeBuilder(result, amount).apply(callback).build(this)
+}
+
+fun ShapelessRecipeBuilder.ingredients(vararg ingredients: IItemProvider){
+ for(ingredient in ingredients){
+ this.addIngredient(ingredient)
+ }
+}

View File

@@ -1,4 +0,0 @@
<changelist name="Shulker_Box_Animation" date="1590248312609" recycled="false">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Shulker_Box_Animation/shelved.patch" />
<option name="DESCRIPTION" value="Shulker Box Animation" />
</changelist>

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +0,0 @@
<changelist name="StructureFile" date="1601888541958" recycled="true">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/StructureFile/shelved.patch" />
<option name="DESCRIPTION" value="StructureFile" />
</changelist>

File diff suppressed because one or more lines are too long

4
.idea/shelf/TODO.xml generated
View File

@@ -1,4 +0,0 @@
<changelist name="TODO" date="1601072216412" recycled="false">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/TODO/shelved.patch" />
<option name="DESCRIPTION" value="TODO" />
</changelist>

File diff suppressed because one or more lines are too long

View File

@@ -1,14 +0,0 @@
<changelist name="Territories" date="1593174807954" recycled="false">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Territories/shelved.patch" />
<option name="DESCRIPTION" value="Territories" />
<binary>
<option name="BEFORE_PATH" />
<option name="AFTER_PATH" value="src/main/resources/assets/hee/textures/environment/end_sky_blurry.png" />
<option name="SHELVED_PATH" value="$PROJECT_DIR$/.idea/shelf/Territories/end_sky_blurry.png" />
</binary>
<binary>
<option name="BEFORE_PATH" />
<option name="AFTER_PATH" value="src/main/resources/assets/hee/textures/environment/end_sky_smooth.png" />
<option name="SHELVED_PATH" value="$PROJECT_DIR$/.idea/shelf/Territories/end_sky_smooth.png" />
</binary>
</changelist>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

View File

@@ -1,24 +0,0 @@
Index: src/main/java/chylex/hee/game/block/BlockDustyStoneUnstable.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- a/src/main/java/chylex/hee/game/block/BlockDustyStoneUnstable.kt (revision f6f631f6f3dc9b347b19db913cf2be4535813fc7)
+++ b/src/main/java/chylex/hee/game/block/BlockDustyStoneUnstable.kt (date 1590584304217)
@@ -26,7 +26,6 @@
import net.minecraft.util.math.shapes.EntitySelectionContext
import net.minecraft.util.math.shapes.ISelectionContext
import net.minecraft.util.math.shapes.VoxelShape
-import net.minecraft.util.math.shapes.VoxelShapes
import net.minecraft.world.IBlockReader
import net.minecraft.world.World
import java.util.Random
@@ -68,7 +67,7 @@
return if (context is EntitySelectionContext && context.entity is EntityLivingBase)
MagicValues.BLOCK_COLLISION_SHRINK_SHAPE
else
- VoxelShapes.fullCube()
+ MagicValues.BLOCK_COLLISION_SHRINK_SHAPE //VoxelShapes.fullCube()
}
override fun causesSuffocation(state: BlockState, world: IBlockReader, pos: BlockPos): Boolean{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +0,0 @@
<changelist name="Work_on_Ender_Eye_spawn_animation,_movement,_and_attack_logic" date="1601092950910" recycled="true">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Work_on_Ender_Eye_spawn_animation,_movement,_and_attack_logic/shelved.patch" />
<option name="DESCRIPTION" value="Work on Ender Eye spawn animation, movement, and attack logic" />
</changelist>

4
.idea/shelf/thing.xml generated
View File

@@ -1,4 +0,0 @@
<changelist name="thing" date="1608060366436" recycled="false">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/thing/shelved.patch" />
<option name="DESCRIPTION" value="thing" />
</changelist>

View File

@@ -1,74 +0,0 @@
Index: src/main/resources/hee.mixins.json
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
<+>{\n \"required\": true,\n \"minVersion\": \"0.8\",\n \"package\": \"chylex.hee.mixin\",\n \"compatibilityLevel\": \"JAVA_8\",\n \"mixins\": [\n \"HookAnvilRepair\",\n \"HookBlockDrops\",\n \"HookChorusFlowerSoil\",\n \"HookChorusPlantSoil\",\n \"HookEffectCorruption\",\n \"HookEffectInstanceCorruption\",\n \"HookEndBiome\",\n \"HookEndermanParticles\",\n \"HookEndermiteParticles\",\n \"HookEntityHelmetBreaking\",\n \"HookEntityPotionCorruption\",\n \"HookFireSpread\",\n \"HookItemEntityLavaCheck\",\n \"HookLightMapColors\",\n \"HookPlayerInventoryArmorBreaking\",\n \"HookPotionCreativeMenu\",\n \"HookThornsArmorBreaking\"\n ],\n \"injectors\": {\n \"defaultRequire\": 1\n }\n}\n
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/resources/hee.mixins.json b/src/main/resources/hee.mixins.json
--- a/src/main/resources/hee.mixins.json (revision 7f9202bceb9aa7b8fac24437a2190a87857573a7)
+++ b/src/main/resources/hee.mixins.json (date 1608060366293)
@@ -3,25 +3,7 @@
"minVersion": "0.8",
"package": "chylex.hee.mixin",
"compatibilityLevel": "JAVA_8",
- "mixins": [
- "HookAnvilRepair",
- "HookBlockDrops",
- "HookChorusFlowerSoil",
- "HookChorusPlantSoil",
- "HookEffectCorruption",
- "HookEffectInstanceCorruption",
- "HookEndBiome",
- "HookEndermanParticles",
- "HookEndermiteParticles",
- "HookEntityHelmetBreaking",
- "HookEntityPotionCorruption",
- "HookFireSpread",
- "HookItemEntityLavaCheck",
- "HookLightMapColors",
- "HookPlayerInventoryArmorBreaking",
- "HookPotionCreativeMenu",
- "HookThornsArmorBreaking"
- ],
+ "mixins": [ "HookAnvilRepair", "HookBlockDrops", "HookChorusFlowerSoil", "HookChorusPlantSoil", "HookEffectCorruption", "HookEffectInstanceCorruption", "HookElytraBreaking", "HookEndBiome", "HookEndermanParticles", "HookEndermiteParticles", "HookEntityHelmetBreaking", "HookEntityPotionCorruption", "HookFireSpread", "HookItemEntityLavaCheck", "HookLightMapColors", "HookPlayerInventoryArmorBreaking", "HookPotionCreativeMenu", "HookThornsArmorBreaking" ],
"injectors": {
"defaultRequire": 1
}
Index: src/main/java/chylex/hee/mixin/HookElytraBreaking.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/chylex/hee/mixin/HookElytraBreaking.java b/src/main/java/chylex/hee/mixin/HookElytraBreaking.java
new file mode 100644
--- /dev/null (date 1608060322378)
+++ b/src/main/java/chylex/hee/mixin/HookElytraBreaking.java (date 1608060322378)
@@ -0,0 +1,27 @@
+package chylex.hee.mixin;
+
+import chylex.hee.init.ModItems;
+import net.minecraft.entity.LivingEntity;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.item.ElytraItem;
+import net.minecraft.item.ItemStack;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Redirect;
+import java.util.function.Consumer;
+
+@Mixin(ElytraItem.class)
+public abstract class HookElytraBreaking{
+ @Redirect(
+ method = "elytraFlightTick",
+ at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;damageItem(ILnet/minecraft/entity/LivingEntity;Ljava/util/function/Consumer;)V")
+ )
+ public void damageItem(final ItemStack stack, final int amount, final LivingEntity entity, final Consumer<LivingEntity> onBroken){
+ final ItemStack originalStack = stack.copy();
+ stack.damageItem(amount, entity, onBroken);
+
+ if (ElytraItem.isUsable(originalStack) && !ElytraItem.isUsable(stack) && entity instanceof PlayerEntity){
+ ModItems.RING_OF_PRESERVATION.onArmorDestroyed((PlayerEntity)entity, originalStack, stack);
+ }
+ }
+}

4
.idea/shelf/todo1.xml generated
View File

@@ -1,4 +0,0 @@
<changelist name="todo1" date="1601711471885" recycled="true">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/todo1/shelved.patch" />
<option name="DESCRIPTION" value="todo" />
</changelist>

File diff suppressed because one or more lines are too long

View File

@@ -22,7 +22,6 @@ import net.minecraft.block.BlockState
import net.minecraft.enchantment.EnchantmentHelper import net.minecraft.enchantment.EnchantmentHelper
import net.minecraft.enchantment.Enchantments import net.minecraft.enchantment.Enchantments
import net.minecraft.entity.Entity import net.minecraft.entity.Entity
import net.minecraft.entity.EntitySpawnPlacementRegistry.PlacementType
import net.minecraft.entity.EntityType import net.minecraft.entity.EntityType
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockReader import net.minecraft.world.IBlockReader
@@ -48,6 +47,14 @@ class BlockDustyStoneUnstable(builder: BlockBuilder) : BlockDustyStone(builder),
return null return null
} }
private fun isNonCreative(entity: Entity): Boolean {
return entity !is EntityPlayer || !entity.isCreative
}
private fun isLightMob(entity: Entity): Boolean {
return entity.height <= 0.5F || (entity.height <= 1F && entity.width <= 0.5F)
}
} }
override fun canHarvestBlock(state: BlockState, world: IBlockReader, pos: BlockPos, player: EntityPlayer): Boolean { override fun canHarvestBlock(state: BlockState, world: IBlockReader, pos: BlockPos, player: EntityPlayer): Boolean {
@@ -87,7 +94,7 @@ class BlockDustyStoneUnstable(builder: BlockBuilder) : BlockDustyStone(builder),
} }
override fun onEntityCollisionAbove(world: World, pos: BlockPos, entity: Entity) { override fun onEntityCollisionAbove(world: World, pos: BlockPos, entity: Entity) {
if (!world.isRemote && world.totalTime % 4L == 0L && !(entity.height <= 0.5F || (entity.height <= 1F && entity.width <= 0.5F)) && isNonCreative(entity)) { if (!world.isRemote && world.totalTime % 4L == 0L && !isLightMob(entity) && isNonCreative(entity)) {
if (!doCrumbleTest(world, pos)) { if (!doCrumbleTest(world, pos)) {
return return
} }
@@ -103,7 +110,7 @@ class BlockDustyStoneUnstable(builder: BlockBuilder) : BlockDustyStone(builder),
} }
override fun onFallenUpon(world: World, pos: BlockPos, entity: Entity, fallDistance: Float) { override fun onFallenUpon(world: World, pos: BlockPos, entity: Entity, fallDistance: Float) {
if (!world.isRemote && entity is EntityLivingBase && fallDistance > 1.3F && isNonCreative(entity)) { if (!world.isRemote && entity is EntityLivingBase && fallDistance > (if (isLightMob(entity)) 3.3F else 1.3F) && isNonCreative(entity)) {
val rand = world.rand val rand = world.rand
val aabb = entity.boundingBox val aabb = entity.boundingBox
val y = pos.y val y = pos.y
@@ -135,12 +142,8 @@ class BlockDustyStoneUnstable(builder: BlockBuilder) : BlockDustyStone(builder),
super.onFallenUpon(world, pos, entity, fallDistance) super.onFallenUpon(world, pos, entity, fallDistance)
} }
override fun canCreatureSpawn(state: BlockState, world: IBlockReader, pos: BlockPos, placementType: PlacementType, entityType: EntityType<*>?): Boolean { override fun canEntitySpawn(state: BlockState, world: IBlockReader, pos: BlockPos, entityType: EntityType<*>): Boolean {
return super.canCreatureSpawn(state, world, pos, placementType, entityType) && getCrumbleStartPos(world, pos) == null return super.canEntitySpawn(state, world, pos, entityType) && getCrumbleStartPos(world, pos) == null
}
private fun isNonCreative(entity: Entity): Boolean {
return entity !is EntityPlayer || !entity.isCreative
} }
private fun doCrumbleTest(world: World, pos: BlockPos): Boolean { private fun doCrumbleTest(world: World, pos: BlockPos): Boolean {

View File

@@ -9,14 +9,13 @@ import chylex.hee.game.entity.technical.EntityTechnicalTrigger.Types.ENERGY_SHRI
import chylex.hee.game.world.center import chylex.hee.game.world.center
import chylex.hee.game.world.feature.energyshrine.EnergyShrinePieces import chylex.hee.game.world.feature.energyshrine.EnergyShrinePieces
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.entity.EntitySpawnPlacementRegistry.PlacementType
import net.minecraft.entity.EntityType import net.minecraft.entity.EntityType
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockReader import net.minecraft.world.IBlockReader
import net.minecraft.world.IEntityReader import net.minecraft.world.IEntityReader
class BlockGloomrock(builder: BlockBuilder) : BlockSimple(builder) { class BlockGloomrock(builder: BlockBuilder) : BlockSimple(builder) {
override fun canCreatureSpawn(state: BlockState, world: IBlockReader, pos: BlockPos, type: PlacementType, entityType: EntityType<*>?): Boolean { override fun canEntitySpawn(state: BlockState, world: IBlockReader, pos: BlockPos, entityType: EntityType<*>?): Boolean {
if (world !is IEntityReader) { if (world !is IEntityReader) {
HEE.log.warn("[BlockGloomrock] attempted to check spawn on a world != IEntityReader (${world.javaClass})") HEE.log.warn("[BlockGloomrock] attempted to check spawn on a world != IEntityReader (${world.javaClass})")
return false return false

View File

@@ -25,6 +25,7 @@ import chylex.hee.system.random.nextFloat
import chylex.hee.system.random.nextInt import chylex.hee.system.random.nextInt
import net.minecraft.block.Block import net.minecraft.block.Block
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.entity.EntityType
import net.minecraft.item.BlockItemUseContext import net.minecraft.item.BlockItemUseContext
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.state.StateContainer.Builder import net.minecraft.state.StateContainer.Builder
@@ -88,6 +89,12 @@ open class BlockGraveDirt(builder: BlockBuilder) : BlockSimpleShaped(builder, Ax
super.getShape(state, source, pos, context) super.getShape(state, source, pos, context)
} }
// Mobs
override fun canEntitySpawn(state: BlockState, worldIn: IBlockReader, pos: BlockPos, type: EntityType<*>): Boolean {
return true
}
// Explosions // Explosions
override fun canDropFromExplosion(explosion: Explosion): Boolean { override fun canDropFromExplosion(explosion: Explosion): Boolean {

View File

@@ -76,8 +76,8 @@ class EntityMobAngryEnderman(type: EntityType<EntityMobAngryEnderman>, world: Wo
} }
override fun updateAITasks() { override fun updateAITasks() {
teleportHandler.update() teleportHandler.tickServer()
waterHandler.update() waterHandler.tickServer()
val currentTarget = attackTarget val currentTarget = attackTarget

View File

@@ -26,6 +26,10 @@ import chylex.hee.game.mechanics.causatum.events.CausatumEventEndermanKill
import chylex.hee.game.world.playServer import chylex.hee.game.world.playServer
import chylex.hee.init.ModEntities import chylex.hee.init.ModEntities
import chylex.hee.init.ModSounds import chylex.hee.init.ModSounds
import chylex.hee.system.component.EntityComponents
import chylex.hee.system.component.general.deserializeFrom
import chylex.hee.system.component.general.serializeTo
import chylex.hee.system.component.general.tick
import chylex.hee.system.facades.Resource import chylex.hee.system.facades.Resource
import chylex.hee.system.forge.SubscribeAllEvents import chylex.hee.system.forge.SubscribeAllEvents
import chylex.hee.system.forge.SubscribeEvent import chylex.hee.system.forge.SubscribeEvent
@@ -76,8 +80,6 @@ class EntityMobEnderman(type: EntityType<EntityMobEnderman>, world: World) : Ent
@SubscribeAllEvents(modid = HEE.ID) @SubscribeAllEvents(modid = HEE.ID)
companion object { companion object {
private const val TELEPORT_HANDLER_TAG = "Teleport"
private const val WATER_HANDLER_TAG = "Water"
private const val CAN_PICK_UP_BLOCKS_TAG = "CanPickUpBlocks" private const val CAN_PICK_UP_BLOCKS_TAG = "CanPickUpBlocks"
private const val HELD_BLOCK_TIMER_TAG = "HeldBlockTimer" private const val HELD_BLOCK_TIMER_TAG = "HeldBlockTimer"
private const val HELD_BLOCK_DESPAWNS_TAG = "HeldBlockDespawns" private const val HELD_BLOCK_DESPAWNS_TAG = "HeldBlockDespawns"
@@ -202,8 +204,9 @@ class EntityMobEnderman(type: EntityType<EntityMobEnderman>, world: World) : Ent
// Instance // Instance
private lateinit var components: EntityComponents
private lateinit var teleportHandler: EndermanTeleportHandler private lateinit var teleportHandler: EndermanTeleportHandler
private lateinit var waterHandler: EndermanWaterHandler
private lateinit var blockHandler: EndermanBlockHandler private lateinit var blockHandler: EndermanBlockHandler
private lateinit var aiAttackTarget: AIToggle private lateinit var aiAttackTarget: AIToggle
@@ -227,6 +230,13 @@ class EntityMobEnderman(type: EntityType<EntityMobEnderman>, world: World) : Ent
// Initialization // Initialization
override fun registerData() {
super.registerData()
components = EntityComponents()
components.attach(EndermanWaterHandler(this, takeDamageAfterWetTicks = 80))
}
override fun registerAttributes() { override fun registerAttributes() {
super.registerAttributes() super.registerAttributes()
@@ -238,8 +248,7 @@ class EntityMobEnderman(type: EntityType<EntityMobEnderman>, world: World) : Ent
} }
override fun registerGoals() { override fun registerGoals() {
teleportHandler = EndermanTeleportHandler(this) teleportHandler = EndermanTeleportHandler(this).also(components::attach)
waterHandler = EndermanWaterHandler(this, takeDamageAfterWetTicks = 80)
blockHandler = EndermanBlockHandler(this) blockHandler = EndermanBlockHandler(this)
aiWatchTargetInShock = AIWatchTargetInShock(this, maxDistance = 72.0) aiWatchTargetInShock = AIWatchTargetInShock(this, maxDistance = 72.0)
@@ -265,10 +274,9 @@ class EntityMobEnderman(type: EntityType<EntityMobEnderman>, world: World) : Ent
override fun livingTick() { override fun livingTick() {
super.livingTick() super.livingTick()
components.tick(this)
if (!world.isRemote) { if (!world.isRemote) {
teleportHandler.update()
waterHandler.update()
if (heldBlockTimer > 0 && --heldBlockTimer == 0.toShort()) { if (heldBlockTimer > 0 && --heldBlockTimer == 0.toShort()) {
if (heldBlockDespawns || !blockHandler.tryPlaceBlock(allowPlayerProximity = false)) { if (heldBlockDespawns || !blockHandler.tryPlaceBlock(allowPlayerProximity = false)) {
teleportHandler.teleportOutOfWorld(force = rand.nextBoolean()) teleportHandler.teleportOutOfWorld(force = rand.nextBoolean())
@@ -536,8 +544,7 @@ class EntityMobEnderman(type: EntityType<EntityMobEnderman>, world: World) : Ent
override fun writeAdditional(nbt: TagCompound) = nbt.heeTag.use { override fun writeAdditional(nbt: TagCompound) = nbt.heeTag.use {
super.writeAdditional(nbt) super.writeAdditional(nbt)
put(TELEPORT_HANDLER_TAG, teleportHandler.serializeNBT()) components.serializeTo(this)
put(WATER_HANDLER_TAG, waterHandler.serializeNBT())
putBoolean(CAN_PICK_UP_BLOCKS_TAG, aiPickUpBlocks.enabled) putBoolean(CAN_PICK_UP_BLOCKS_TAG, aiPickUpBlocks.enabled)
putShort(HELD_BLOCK_TIMER_TAG, heldBlockTimer) putShort(HELD_BLOCK_TIMER_TAG, heldBlockTimer)
@@ -547,8 +554,7 @@ class EntityMobEnderman(type: EntityType<EntityMobEnderman>, world: World) : Ent
override fun readAdditional(nbt: TagCompound) = nbt.heeTag.use { override fun readAdditional(nbt: TagCompound) = nbt.heeTag.use {
super.readAdditional(nbt) super.readAdditional(nbt)
teleportHandler.deserializeNBT(getCompound(TELEPORT_HANDLER_TAG)) components.deserializeFrom(this)
waterHandler.deserializeNBT(getCompound(WATER_HANDLER_TAG))
aiPickUpBlocks.enabled = getBoolean(CAN_PICK_UP_BLOCKS_TAG) aiPickUpBlocks.enabled = getBoolean(CAN_PICK_UP_BLOCKS_TAG)
heldBlockTimer = getShort(HELD_BLOCK_TIMER_TAG) heldBlockTimer = getShort(HELD_BLOCK_TIMER_TAG)

View File

@@ -56,11 +56,15 @@ import net.minecraft.block.BlockState
import net.minecraft.entity.CreatureAttribute import net.minecraft.entity.CreatureAttribute
import net.minecraft.entity.Entity import net.minecraft.entity.Entity
import net.minecraft.entity.EntityType import net.minecraft.entity.EntityType
import net.minecraft.entity.ILivingEntityData
import net.minecraft.entity.SharedMonsterAttributes.ATTACK_DAMAGE import net.minecraft.entity.SharedMonsterAttributes.ATTACK_DAMAGE
import net.minecraft.entity.SharedMonsterAttributes.FOLLOW_RANGE import net.minecraft.entity.SharedMonsterAttributes.FOLLOW_RANGE
import net.minecraft.entity.SharedMonsterAttributes.MAX_HEALTH import net.minecraft.entity.SharedMonsterAttributes.MAX_HEALTH
import net.minecraft.entity.SharedMonsterAttributes.MOVEMENT_SPEED import net.minecraft.entity.SharedMonsterAttributes.MOVEMENT_SPEED
import net.minecraft.entity.SpawnReason
import net.minecraft.entity.SpawnReason.SPAWNER
import net.minecraft.entity.ai.attributes.AttributeModifier import net.minecraft.entity.ai.attributes.AttributeModifier
import net.minecraft.nbt.CompoundNBT
import net.minecraft.network.IPacket import net.minecraft.network.IPacket
import net.minecraft.network.datasync.DataSerializers import net.minecraft.network.datasync.DataSerializers
import net.minecraft.pathfinding.PathNavigator import net.minecraft.pathfinding.PathNavigator
@@ -76,6 +80,8 @@ import net.minecraft.util.math.RayTraceResult.Type
import net.minecraft.util.math.Vec3d import net.minecraft.util.math.Vec3d
import net.minecraft.world.Difficulty.HARD import net.minecraft.world.Difficulty.HARD
import net.minecraft.world.Difficulty.NORMAL import net.minecraft.world.Difficulty.NORMAL
import net.minecraft.world.DifficultyInstance
import net.minecraft.world.IWorld
import net.minecraft.world.IWorldReader import net.minecraft.world.IWorldReader
import net.minecraft.world.LightType.BLOCK import net.minecraft.world.LightType.BLOCK
import net.minecraft.world.LightType.SKY import net.minecraft.world.LightType.SKY
@@ -213,7 +219,7 @@ class EntityMobSpiderling(type: EntityType<EntityMobSpiderling>, world: World) :
} }
else if (wakeUpTimer > 0) { else if (wakeUpTimer > 0) {
if (--wakeUpTimer == 0) { if (--wakeUpTimer == 0) {
wakeUp(instant = false, preventSleep = false) wakeUp(preventSleep = false)
} }
} }
else if (ticksExisted % 4 == 0) { else if (ticksExisted % 4 == 0) {
@@ -291,10 +297,18 @@ class EntityMobSpiderling(type: EntityType<EntityMobSpiderling>, world: World) :
} }
} }
private fun wakeUp(instant: Boolean, preventSleep: Boolean) { fun wakeUpInstantly(preventSleep: Boolean) {
wakeUp(preventSleep, aiDelayTicks = 1)
}
fun wakeUp(preventSleep: Boolean) {
wakeUp(preventSleep, aiDelayTicks = rand.nextInt(25, 40))
}
fun wakeUp(preventSleep: Boolean, aiDelayTicks: Int) {
if (isSleeping) { if (isSleeping) {
isSleepingProp = false isSleepingProp = false
wakeUpDelayAI = if (instant) 1 else rand.nextInt(25, 40) wakeUpDelayAI = aiDelayTicks
if (preventSleep) { if (preventSleep) {
canSleepAgain = false canSleepAgain = false
@@ -303,7 +317,7 @@ class EntityMobSpiderling(type: EntityType<EntityMobSpiderling>, world: World) :
} }
override fun setFire(seconds: Int) { override fun setFire(seconds: Int) {
wakeUp(instant = true, preventSleep = true) wakeUpInstantly(preventSleep = true)
super.setFire(seconds) super.setFire(seconds)
} }
@@ -314,7 +328,7 @@ class EntityMobSpiderling(type: EntityType<EntityMobSpiderling>, world: World) :
// Behavior (Light) // Behavior (Light)
override fun onLightStartled(): Boolean { override fun onLightStartled(): Boolean {
wakeUp(instant = false, preventSleep = true) wakeUp(preventSleep = true)
if (world.totalTime < lightStartleResetTime) { if (world.totalTime < lightStartleResetTime) {
return false return false
@@ -401,7 +415,7 @@ class EntityMobSpiderling(type: EntityType<EntityMobSpiderling>, world: World) :
return false return false
} }
wakeUp(instant = true, preventSleep = true) wakeUpInstantly(preventSleep = true)
if (!super.attackEntityFrom(source, if (source.isFireDamage) amount * 1.25F else amount)) { if (!super.attackEntityFrom(source, if (source.isFireDamage) amount * 1.25F else amount)) {
return false return false
@@ -445,6 +459,16 @@ class EntityMobSpiderling(type: EntityType<EntityMobSpiderling>, world: World) :
return true return true
} }
// Spawning
override fun onInitialSpawn(world: IWorld, difficulty: DifficultyInstance, reason: SpawnReason, data: ILivingEntityData?, nbt: CompoundNBT?): ILivingEntityData? {
if (reason == SPAWNER) {
wakeUpInstantly(preventSleep = true)
}
return super.onInitialSpawn(world, difficulty, reason, data, nbt)
}
// Despawning // Despawning
override fun isDespawnPeaceful(): Boolean { override fun isDespawnPeaceful(): Boolean {
@@ -515,7 +539,7 @@ class EntityMobSpiderling(type: EntityType<EntityMobSpiderling>, world: World) :
val sleepState = getInt(SLEEP_STATE_TAG) val sleepState = getInt(SLEEP_STATE_TAG)
if (sleepState != 2) { if (sleepState != 2) {
wakeUp(instant = true, preventSleep = sleepState != 1) wakeUpInstantly(preventSleep = sleepState != 1)
} }
lightStartleResetTime = getLong(LIGHT_STARTLE_RESET_TIME_TAG) lightStartleResetTime = getLong(LIGHT_STARTLE_RESET_TIME_TAG)

View File

@@ -137,19 +137,19 @@ class EntityMobUndread(type: EntityType<EntityMobUndread>, world: World) : Entit
super.onDeathUpdate() super.onDeathUpdate()
} }
override fun playStepSound(pos: BlockPos, state: BlockState) { public override fun playStepSound(pos: BlockPos, state: BlockState) {
playSound(Sounds.ENTITY_ZOMBIE_STEP, rand.nextFloat(0.4F, 0.5F), rand.nextFloat(0.9F, 1F)) playSound(Sounds.ENTITY_ZOMBIE_STEP, rand.nextFloat(0.4F, 0.5F), rand.nextFloat(0.9F, 1F))
} }
override fun getHurtSound(source: DamageSource): SoundEvent { public override fun getHurtSound(source: DamageSource): SoundEvent {
return ModSounds.MOB_UNDREAD_HURT return ModSounds.MOB_UNDREAD_HURT
} }
override fun getDeathSound(): SoundEvent { public override fun getDeathSound(): SoundEvent {
return ModSounds.MOB_UNDREAD_DEATH return ModSounds.MOB_UNDREAD_DEATH
} }
override fun getSoundPitch(): Float { public override fun getSoundPitch(): Float {
return rand.nextFloat(0.8F, 1F) return rand.nextFloat(0.8F, 1F)
} }
} }

View File

@@ -7,8 +7,8 @@ import chylex.hee.game.particle.spawner.ParticleSpawnerCustom
import chylex.hee.game.particle.spawner.properties.IShape.Point import chylex.hee.game.particle.spawner.properties.IShape.Point
import chylex.hee.game.world.bottomCenter import chylex.hee.game.world.bottomCenter
import chylex.hee.network.client.PacketClientFX import chylex.hee.network.client.PacketClientFX
import chylex.hee.network.fx.IFxData import chylex.hee.network.fx.FxVecData
import chylex.hee.network.fx.IFxHandler import chylex.hee.network.fx.FxVecHandler
import chylex.hee.system.color.IntColor.Companion.RGB import chylex.hee.system.color.IntColor.Companion.RGB
import chylex.hee.system.math.Vec import chylex.hee.system.math.Vec
import chylex.hee.system.math.Vec3 import chylex.hee.system.math.Vec3
@@ -21,10 +21,7 @@ import chylex.hee.system.serialization.NBTList.Companion.putList
import chylex.hee.system.serialization.NBTObjectList import chylex.hee.system.serialization.NBTObjectList
import chylex.hee.system.serialization.TagCompound import chylex.hee.system.serialization.TagCompound
import chylex.hee.system.serialization.getListOfCompounds import chylex.hee.system.serialization.getListOfCompounds
import chylex.hee.system.serialization.readVec
import chylex.hee.system.serialization.use import chylex.hee.system.serialization.use
import chylex.hee.system.serialization.writeVec
import net.minecraft.network.PacketBuffer
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Vec3d import net.minecraft.util.math.Vec3d
import net.minecraft.world.World import net.minecraft.world.World
@@ -50,15 +47,9 @@ class EnderEyeSpawnerParticles(private val entity: EntityBossEnderEye) : INBTSer
hideOnMinimalSetting = false hideOnMinimalSetting = false
) )
class ParticleData(private val point: Vec3d) : IFxData { val FX_PARTICLE = object : FxVecHandler() {
override fun write(buffer: PacketBuffer) = buffer.use { override fun handle(world: World, rand: Random, vec: Vec3d) {
writeVec(point) PARTICLE_TICK.spawn(Point(vec, 2), rand)
}
}
val FX_PARTICLE = object : IFxHandler<ParticleData> {
override fun handle(buffer: PacketBuffer, world: World, rand: Random) = buffer.use {
PARTICLE_TICK.spawn(Point(readVec(), 2), rand)
} }
} }
} }
@@ -95,7 +86,7 @@ class EnderEyeSpawnerParticles(private val entity: EntityBossEnderEye) : INBTSer
else -> 1.0 else -> 1.0
} }
PacketClientFX(FX_PARTICLE, ParticleData(pos.addY(sqrt(progressCurvePoint) * 6.0))).sendToAllAround(entity.world, pos, 256.0) PacketClientFX(FX_PARTICLE, FxVecData(pos.addY(sqrt(progressCurvePoint) * 6.0))).sendToAllAround(entity.world, pos, 256.0)
} }
if (distSq > prevDistSq || distSq < square(0.15)) { if (distSq > prevDistSq || distSq < square(0.15)) {

View File

@@ -29,6 +29,8 @@ import chylex.hee.network.client.PacketClientFX
import chylex.hee.network.fx.FxEntityData import chylex.hee.network.fx.FxEntityData
import chylex.hee.network.fx.FxEntityHandler import chylex.hee.network.fx.FxEntityHandler
import chylex.hee.system.color.IntColor.Companion.RGB import chylex.hee.system.color.IntColor.Companion.RGB
import chylex.hee.system.component.general.SerializableComponent
import chylex.hee.system.component.general.TickableComponent
import chylex.hee.system.math.Vec import chylex.hee.system.math.Vec
import chylex.hee.system.math.Vec3 import chylex.hee.system.math.Vec3
import chylex.hee.system.math.addY import chylex.hee.system.math.addY
@@ -53,13 +55,12 @@ import net.minecraft.util.SoundCategory
import net.minecraft.util.math.AxisAlignedBB import net.minecraft.util.math.AxisAlignedBB
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Vec3d import net.minecraft.util.math.Vec3d
import net.minecraftforge.common.util.INBTSerializable
import java.util.Random import java.util.Random
import java.util.UUID import java.util.UUID
import kotlin.math.min import kotlin.math.min
import kotlin.math.sqrt import kotlin.math.sqrt
class EndermanTeleportHandler(private val enderman: EntityMobAbstractEnderman) : INBTSerializable<TagCompound> { class EndermanTeleportHandler(private val enderman: EntityMobAbstractEnderman) : TickableComponent, SerializableComponent {
companion object { companion object {
private const val DEFAULT_RESTORE_Y = -256.0 private const val DEFAULT_RESTORE_Y = -256.0
@@ -117,6 +118,9 @@ class EndermanTeleportHandler(private val enderman: EntityMobAbstractEnderman) :
} }
} }
override val serializationKey
get() = "Teleport"
val preventDespawn val preventDespawn
get() = tpDelayTicks > 0 get() = tpDelayTicks > 0
@@ -133,7 +137,7 @@ class EndermanTeleportHandler(private val enderman: EntityMobAbstractEnderman) :
private var lastDodged: UUID? = null private var lastDodged: UUID? = null
fun update() { override fun tickServer() {
if (tpCooldown > 0) { if (tpCooldown > 0) {
--tpCooldown --tpCooldown
} }

View File

@@ -4,15 +4,16 @@ import chylex.hee.game.entity.OPERATION_MUL_INCR_INDIVIDUAL
import chylex.hee.game.entity.living.EntityMobAbstractEnderman import chylex.hee.game.entity.living.EntityMobAbstractEnderman
import chylex.hee.game.entity.tryApplyModifier import chylex.hee.game.entity.tryApplyModifier
import chylex.hee.game.entity.tryRemoveModifier import chylex.hee.game.entity.tryRemoveModifier
import chylex.hee.system.component.general.SerializableComponent
import chylex.hee.system.component.general.TickableComponent
import chylex.hee.system.random.nextInt import chylex.hee.system.random.nextInt
import chylex.hee.system.serialization.TagCompound import chylex.hee.system.serialization.TagCompound
import chylex.hee.system.serialization.use import chylex.hee.system.serialization.use
import net.minecraft.entity.SharedMonsterAttributes.ATTACK_DAMAGE import net.minecraft.entity.SharedMonsterAttributes.ATTACK_DAMAGE
import net.minecraft.entity.ai.attributes.AttributeModifier import net.minecraft.entity.ai.attributes.AttributeModifier
import net.minecraft.util.DamageSource import net.minecraft.util.DamageSource
import net.minecraftforge.common.util.INBTSerializable
class EndermanWaterHandler(private val enderman: EntityMobAbstractEnderman, private val takeDamageAfterWetTicks: Int) : INBTSerializable<TagCompound> { class EndermanWaterHandler(private val enderman: EntityMobAbstractEnderman, private val takeDamageAfterWetTicks: Int) : TickableComponent, SerializableComponent {
private companion object { private companion object {
private val DEBUFF_WEAKNESS = AttributeModifier("Water weakness", -0.5, OPERATION_MUL_INCR_INDIVIDUAL) private val DEBUFF_WEAKNESS = AttributeModifier("Water weakness", -0.5, OPERATION_MUL_INCR_INDIVIDUAL)
@@ -20,10 +21,13 @@ class EndermanWaterHandler(private val enderman: EntityMobAbstractEnderman, priv
private const val DEBUFF_TICKS_TAG = "DebuffTicks" private const val DEBUFF_TICKS_TAG = "DebuffTicks"
} }
override val serializationKey
get() = "Water"
private var wetCounter = 0 private var wetCounter = 0
private var debuffTicks = 0 private var debuffTicks = 0
fun update() { override fun tickServer() {
val isWet = enderman.isWet val isWet = enderman.isWet
if (isWet) { if (isWet) {

View File

@@ -67,7 +67,7 @@ class EntityTechnicalTrigger(type: EntityType<EntityTechnicalTrigger>, world: Wo
STRONGHOLD_TRAP_TALL_INTERSECTION({ StrongholdRoom_Trap_TallIntersection.Trigger }), STRONGHOLD_TRAP_TALL_INTERSECTION({ StrongholdRoom_Trap_TallIntersection.Trigger }),
ENERGY_SHRINE_GENERATOR({ EnergyShrineGenerator.GeneratorTrigger }), ENERGY_SHRINE_GENERATOR({ EnergyShrineGenerator.GeneratorTrigger }),
ENERGY_SHRINE_GLOBAL({ EnergyShrineRoom_Main_Start.Particles }), ENERGY_SHRINE_GLOBAL({ EnergyShrineRoom_Main_Start.Particles }),
TOMB_DUNGEON_UNDREAD_SPAWNER(TombDungeonRoom_Tomb::UndreadSpawnerTrigger), TOMB_DUNGEON_UNDREAD_SPAWNER(TombDungeonRoom_Tomb::MobSpawnerTrigger),
OBSIDIAN_TOWER_TOP_GLOWSTONE(ObsidianTowerLevel_Top::GlowstoneTrigger), OBSIDIAN_TOWER_TOP_GLOWSTONE(ObsidianTowerLevel_Top::GlowstoneTrigger),
OBSIDIAN_TOWER_DEATH_ANIMATION(ObsidianTowerLevel_Top::DeathAnimationTrigger) OBSIDIAN_TOWER_DEATH_ANIMATION(ObsidianTowerLevel_Top::DeathAnimationTrigger)
} }

View File

@@ -3,6 +3,7 @@ package chylex.hee.game.item
import chylex.hee.game.block.entity.TileEntityEnergyCluster import chylex.hee.game.block.entity.TileEntityEnergyCluster
import chylex.hee.game.inventory.heeTag import chylex.hee.game.inventory.heeTag
import chylex.hee.game.inventory.heeTagOrNull import chylex.hee.game.inventory.heeTagOrNull
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.game.mechanics.energy.IEnergyQuantity import chylex.hee.game.mechanics.energy.IEnergyQuantity
import chylex.hee.game.mechanics.energy.IEnergyQuantity.Units import chylex.hee.game.mechanics.energy.IEnergyQuantity.Units
import chylex.hee.game.particle.ParticleEnergyTransferToPlayer import chylex.hee.game.particle.ParticleEnergyTransferToPlayer
@@ -36,11 +37,11 @@ import chylex.hee.system.serialization.use
import chylex.hee.system.serialization.writePos import chylex.hee.system.serialization.writePos
import net.minecraft.client.util.ITooltipFlag import net.minecraft.client.util.ITooltipFlag
import net.minecraft.entity.Entity import net.minecraft.entity.Entity
import net.minecraft.item.Item
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUseContext import net.minecraft.item.ItemUseContext
import net.minecraft.network.PacketBuffer import net.minecraft.network.PacketBuffer
import net.minecraft.util.ActionResultType import net.minecraft.util.ActionResultType
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.MathHelper import net.minecraft.util.math.MathHelper
import net.minecraft.util.text.ITextComponent import net.minecraft.util.text.ITextComponent
import net.minecraft.util.text.TranslationTextComponent import net.minecraft.util.text.TranslationTextComponent
@@ -50,7 +51,7 @@ import java.util.Random
import kotlin.math.max import kotlin.math.max
import kotlin.math.pow import kotlin.math.pow
abstract class ItemAbstractEnergyUser(properties: Properties) : Item(properties) { abstract class ItemAbstractEnergyUser(properties: Properties) : ItemWithComponents(properties), UseOnBlockComponent {
companion object { companion object {
private const val ENERGY_LEVEL_TAG = "EnergyLevel" private const val ENERGY_LEVEL_TAG = "EnergyLevel"
@@ -100,6 +101,8 @@ abstract class ItemAbstractEnergyUser(properties: Properties) : Item(properties)
init { init {
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
require(maxStackSize == 1) { "energy item must have a maximum stack size of 1" } require(maxStackSize == 1) { "energy item must have a maximum stack size of 1" }
components.attach(this)
} }
protected abstract fun getEnergyCapacity(stack: ItemStack): Units protected abstract fun getEnergyCapacity(stack: ItemStack): Units
@@ -163,15 +166,11 @@ abstract class ItemAbstractEnergyUser(properties: Properties) : Item(properties)
// Energy charging // Energy charging
override fun onItemUse(context: ItemUseContext): ActionResultType { override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType? {
val player = context.player ?: return FAIL
val world = context.world
val pos = context.pos
val tile = pos.getTile<TileEntityEnergyCluster>(world) val tile = pos.getTile<TileEntityEnergyCluster>(world)
val stack = player.getHeldItem(context.hand) val stack = player.getHeldItem(ctx.hand)
if (tile == null || !player.canPlayerEdit(pos, context.face, stack)) { if (tile == null || !player.canPlayerEdit(pos, ctx.face, stack)) {
return FAIL return FAIL
} }
else if (world.isRemote) { else if (world.isRemote) {

View File

@@ -13,7 +13,7 @@ import net.minecraft.util.text.StringTextComponent
import net.minecraft.util.text.TranslationTextComponent import net.minecraft.util.text.TranslationTextComponent
import net.minecraft.world.World import net.minecraft.world.World
abstract class ItemAbstractInfusable(properties: Properties) : Item(properties), IInfusableItem { abstract class ItemAbstractInfusable(properties: Properties) : ItemWithComponents(properties), IInfusableItem {
companion object { companion object {
fun onCanApplyInfusion(item: Item, infusion: Infusion): Boolean { fun onCanApplyInfusion(item: Item, infusion: Infusion): Boolean {
return infusion.targetItems.contains(item) return infusion.targetItems.contains(item)

View File

@@ -1,6 +1,7 @@
package chylex.hee.game.item package chylex.hee.game.item
import chylex.hee.game.inventory.size import chylex.hee.game.inventory.size
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.game.world.BlockEditor import chylex.hee.game.world.BlockEditor
import chylex.hee.init.ModItems import chylex.hee.init.ModItems
import chylex.hee.network.client.PacketClientFX import chylex.hee.network.client.PacketClientFX
@@ -15,7 +16,6 @@ import chylex.hee.system.migration.ItemBoneMeal
import net.minecraft.block.DispenserBlock.FACING import net.minecraft.block.DispenserBlock.FACING
import net.minecraft.dispenser.IBlockSource import net.minecraft.dispenser.IBlockSource
import net.minecraft.dispenser.OptionalDispenseBehavior import net.minecraft.dispenser.OptionalDispenseBehavior
import net.minecraft.item.Item
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUseContext import net.minecraft.item.ItemUseContext
import net.minecraft.util.ActionResultType import net.minecraft.util.ActionResultType
@@ -25,7 +25,7 @@ import net.minecraft.world.server.ServerWorld
import net.minecraftforge.common.util.FakePlayerFactory import net.minecraftforge.common.util.FakePlayerFactory
import java.util.Random import java.util.Random
class ItemCompost(properties: Properties) : Item(properties) { class ItemCompost(properties: Properties) : ItemWithComponents(properties) {
companion object { companion object {
private const val BONE_MEAL_EQUIVALENT = 2 private const val BONE_MEAL_EQUIVALENT = 2
@@ -61,6 +61,24 @@ class ItemCompost(properties: Properties) : Item(properties) {
} }
init { init {
components.attach(object : UseOnBlockComponent {
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType {
if (!BlockEditor.canEdit(pos, player, item)) {
return FAIL
}
else if (world.isRemote) {
return SUCCESS
}
if (applyCompost(world, pos, player)) {
item.shrink(1)
return SUCCESS
}
return PASS
}
})
BlockDispenser.registerDispenseBehavior(this, object : OptionalDispenseBehavior() { BlockDispenser.registerDispenseBehavior(this, object : OptionalDispenseBehavior() {
override fun dispenseStack(source: IBlockSource, stack: ItemStack): ItemStack { override fun dispenseStack(source: IBlockSource, stack: ItemStack): ItemStack {
val world = source.world val world = source.world
@@ -77,26 +95,4 @@ class ItemCompost(properties: Properties) : Item(properties) {
} }
}) })
} }
override fun onItemUse(context: ItemUseContext): ActionResultType {
val player = context.player ?: return FAIL
val world = context.world
val pos = context.pos
val heldItem = player.getHeldItem(context.hand)
if (!BlockEditor.canEdit(pos, player, heldItem)) {
return FAIL
}
else if (world.isRemote) {
return SUCCESS
}
if (applyCompost(world, pos, player)) {
heldItem.shrink(1)
return SUCCESS
}
return PASS
}
} }

View File

@@ -2,27 +2,27 @@ package chylex.hee.game.item
import chylex.hee.game.block.IBlockDeathFlowerDecaying import chylex.hee.game.block.IBlockDeathFlowerDecaying
import chylex.hee.game.entity.item.EntityItemCauldronTrigger import chylex.hee.game.entity.item.EntityItemCauldronTrigger
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.game.world.BlockEditor import chylex.hee.game.world.BlockEditor
import chylex.hee.game.world.getBlock import chylex.hee.game.world.getBlock
import chylex.hee.system.migration.ActionResult.FAIL import chylex.hee.system.migration.ActionResult.FAIL
import chylex.hee.system.migration.ActionResult.PASS import chylex.hee.system.migration.ActionResult.PASS
import chylex.hee.system.migration.ActionResult.SUCCESS import chylex.hee.system.migration.ActionResult.SUCCESS
import chylex.hee.system.migration.EntityPlayer
import net.minecraft.entity.Entity import net.minecraft.entity.Entity
import net.minecraft.item.Item
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUseContext import net.minecraft.item.ItemUseContext
import net.minecraft.util.ActionResultType import net.minecraft.util.ActionResultType
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World import net.minecraft.world.World
class ItemEndPowder(properties: Properties) : Item(properties) { class ItemEndPowder(properties: Properties) : ItemWithComponents(properties), UseOnBlockComponent {
override fun onItemUse(context: ItemUseContext): ActionResultType { init {
val player = context.player ?: return FAIL components.attach(this)
val world = context.world }
val pos = context.pos
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType? {
val heldItem = player.getHeldItem(context.hand) if (!BlockEditor.canEdit(pos, player, item)) {
if (!BlockEditor.canEdit(pos, player, heldItem)) {
return FAIL return FAIL
} }
@@ -33,7 +33,7 @@ class ItemEndPowder(properties: Properties) : Item(properties) {
block.healDeathFlower(world, pos) block.healDeathFlower(world, pos)
} }
heldItem.shrink(1) item.shrink(1)
return SUCCESS return SUCCESS
} }

View File

@@ -28,7 +28,6 @@ import chylex.hee.system.math.angleBetween
import chylex.hee.system.math.floorToInt import chylex.hee.system.math.floorToInt
import chylex.hee.system.math.over import chylex.hee.system.math.over
import chylex.hee.system.math.toDegrees import chylex.hee.system.math.toDegrees
import chylex.hee.system.migration.ActionResult.FAIL
import chylex.hee.system.migration.ActionResult.SUCCESS import chylex.hee.system.migration.ActionResult.SUCCESS
import chylex.hee.system.migration.EntityLivingBase import chylex.hee.system.migration.EntityLivingBase
import chylex.hee.system.migration.EntityPlayer import chylex.hee.system.migration.EntityPlayer
@@ -150,17 +149,13 @@ class ItemEnergyOracle(properties: Properties) : ItemAbstractEnergyUser(properti
return ItemAbstractInfusable.onCanApplyInfusion(this, infusion) return ItemAbstractInfusable.onCanApplyInfusion(this, infusion)
} }
override fun onItemUse(context: ItemUseContext): ActionResultType { override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType? {
val player = context.player ?: return FAIL
val world = context.world
val pos = context.pos
if (player.isSneaking && pos.getTile<TileEntityEnergyCluster>(world) != null) { if (player.isSneaking && pos.getTile<TileEntityEnergyCluster>(world) != null) {
if (world.isRemote) { if (world.isRemote) {
return SUCCESS return SUCCESS
} }
val heldItem = player.getHeldItem(context.hand) val heldItem = player.getHeldItem(ctx.hand)
val entry = pos.toLong() val entry = pos.toLong()
with(heldItem.heeTag) { with(heldItem.heeTag) {
@@ -176,7 +171,7 @@ class ItemEnergyOracle(properties: Properties) : ItemAbstractEnergyUser(properti
return SUCCESS return SUCCESS
} }
return super.onItemUse(context) return super.useOnBlock(world, pos, player, item, ctx)
} }
override fun inventoryTick(stack: ItemStack, world: World, entity: Entity, itemSlot: Int, isSelected: Boolean) { override fun inventoryTick(stack: ItemStack, world: World, entity: Entity, itemSlot: Int, isSelected: Boolean) {

View File

@@ -4,6 +4,7 @@ import chylex.hee.client.color.NO_TINT
import chylex.hee.game.block.entity.TileEntityEnergyCluster import chylex.hee.game.block.entity.TileEntityEnergyCluster
import chylex.hee.game.inventory.heeTag import chylex.hee.game.inventory.heeTag
import chylex.hee.game.inventory.heeTagOrNull import chylex.hee.game.inventory.heeTagOrNull
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.game.item.infusion.Infusion.SAFETY import chylex.hee.game.item.infusion.Infusion.SAFETY
import chylex.hee.game.item.infusion.Infusion.STABILITY import chylex.hee.game.item.infusion.Infusion.STABILITY
import chylex.hee.game.item.infusion.InfusionList import chylex.hee.game.item.infusion.InfusionList
@@ -27,10 +28,10 @@ import chylex.hee.system.forge.Side
import chylex.hee.system.forge.Sided import chylex.hee.system.forge.Sided
import chylex.hee.system.migration.ActionResult.FAIL import chylex.hee.system.migration.ActionResult.FAIL
import chylex.hee.system.migration.ActionResult.SUCCESS import chylex.hee.system.migration.ActionResult.SUCCESS
import chylex.hee.system.migration.EntityPlayer
import chylex.hee.system.serialization.TagCompound import chylex.hee.system.serialization.TagCompound
import chylex.hee.system.serialization.getIntegerOrNull import chylex.hee.system.serialization.getIntegerOrNull
import chylex.hee.system.serialization.hasKey import chylex.hee.system.serialization.hasKey
import chylex.hee.system.serialization.use
import net.minecraft.client.renderer.color.IItemColor import net.minecraft.client.renderer.color.IItemColor
import net.minecraft.client.util.ITooltipFlag import net.minecraft.client.util.ITooltipFlag
import net.minecraft.entity.Entity import net.minecraft.entity.Entity
@@ -43,7 +44,7 @@ import net.minecraft.util.text.TranslationTextComponent
import net.minecraft.world.World import net.minecraft.world.World
import kotlin.math.pow import kotlin.math.pow
class ItemEnergyReceptacle(properties: Properties) : ItemAbstractInfusable(properties) { class ItemEnergyReceptacle(properties: Properties) : ItemAbstractInfusable(properties), UseOnBlockComponent {
private companion object { private companion object {
private const val CLUSTER_SNAPSHOT_TAG = "Cluster" private const val CLUSTER_SNAPSHOT_TAG = "Cluster"
private const val UPDATE_TIME_TAG = "UpdateTime" private const val UPDATE_TIME_TAG = "UpdateTime"
@@ -105,18 +106,14 @@ class ItemEnergyReceptacle(properties: Properties) : ItemAbstractInfusable(prope
} }
// POLISH tweak animation // POLISH tweak animation
components.attach(this)
} }
override fun onItemUse(context: ItemUseContext): ActionResultType { override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType? {
val player = context.player ?: return FAIL with(item.heeTag) {
val world = context.world
val pos = context.pos
val stack = player.getHeldItem(context.hand)
stack.heeTag.use {
if (hasKey(CLUSTER_SNAPSHOT_TAG)) { if (hasKey(CLUSTER_SNAPSHOT_TAG)) {
val finalPos = BlockEditor.place(ModBlocks.ENERGY_CLUSTER, player, stack, context) val finalPos = BlockEditor.place(ModBlocks.ENERGY_CLUSTER, player, item, ctx)
if (world.isRemote) { if (world.isRemote) {
return SUCCESS return SUCCESS
@@ -126,7 +123,7 @@ class ItemEnergyReceptacle(properties: Properties) : ItemAbstractInfusable(prope
finalPos.getTile<TileEntityEnergyCluster>(world)?.let { finalPos.getTile<TileEntityEnergyCluster>(world)?.let {
it.loadClusterSnapshot(ClusterSnapshot(getCompound(CLUSTER_SNAPSHOT_TAG)), inactive = false) it.loadClusterSnapshot(ClusterSnapshot(getCompound(CLUSTER_SNAPSHOT_TAG)), inactive = false)
if (shouldLoseHealth(it, this, InfusionTag.getList(stack))) { if (shouldLoseHealth(it, this, InfusionTag.getList(item))) {
it.deteriorateHealth() it.deteriorateHealth()
} }
} }
@@ -141,7 +138,7 @@ class ItemEnergyReceptacle(properties: Properties) : ItemAbstractInfusable(prope
return SUCCESS return SUCCESS
} }
} }
else if (BlockEditor.canEdit(pos, player, stack)) { else if (BlockEditor.canEdit(pos, player, item)) {
if (world.isRemote) { if (world.isRemote) {
return SUCCESS return SUCCESS
} }

View File

@@ -6,6 +6,7 @@ import chylex.hee.game.entity.heeTag
import chylex.hee.game.entity.heeTagOrNull import chylex.hee.game.entity.heeTagOrNull
import chylex.hee.game.entity.posVec import chylex.hee.game.entity.posVec
import chylex.hee.game.inventory.doDamage import chylex.hee.game.inventory.doDamage
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.game.world.BlockEditor import chylex.hee.game.world.BlockEditor
import chylex.hee.game.world.FLAG_NONE import chylex.hee.game.world.FLAG_NONE
import chylex.hee.game.world.getBlock import chylex.hee.game.world.getBlock
@@ -14,7 +15,6 @@ import chylex.hee.game.world.playServer
import chylex.hee.game.world.removeBlock import chylex.hee.game.world.removeBlock
import chylex.hee.game.world.setBlock import chylex.hee.game.world.setBlock
import chylex.hee.init.ModBlocks import chylex.hee.init.ModBlocks
import chylex.hee.system.compatibility.MinecraftForgeEventBus
import chylex.hee.system.forge.EventPriority import chylex.hee.system.forge.EventPriority
import chylex.hee.system.forge.SubscribeAllEvents import chylex.hee.system.forge.SubscribeAllEvents
import chylex.hee.system.forge.SubscribeEvent import chylex.hee.system.forge.SubscribeEvent
@@ -26,7 +26,6 @@ import chylex.hee.system.migration.EntityPlayer
import chylex.hee.system.migration.Sounds import chylex.hee.system.migration.Sounds
import chylex.hee.system.random.nextFloat import chylex.hee.system.random.nextFloat
import net.minecraft.block.Blocks import net.minecraft.block.Blocks
import net.minecraft.item.Item
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUseContext import net.minecraft.item.ItemUseContext
import net.minecraft.util.ActionResultType import net.minecraft.util.ActionResultType
@@ -36,7 +35,7 @@ import net.minecraft.util.math.BlockPos
import net.minecraft.world.World import net.minecraft.world.World
import net.minecraftforge.event.world.ExplosionEvent import net.minecraftforge.event.world.ExplosionEvent
class ItemFlintAndInfernium(properties: Properties) : Item(properties) { class ItemFlintAndInfernium(properties: Properties) : ItemWithComponents(properties), UseOnBlockComponent {
@SubscribeAllEvents(modid = HEE.ID) @SubscribeAllEvents(modid = HEE.ID)
companion object { companion object {
private const val CREEPER_INFERNIUM_TAG = "Infernium" private const val CREEPER_INFERNIUM_TAG = "Infernium"
@@ -55,7 +54,7 @@ class ItemFlintAndInfernium(properties: Properties) : Item(properties) {
} }
init { init {
MinecraftForgeEventBus.register(this) components.attach(this)
} }
fun igniteTNT(world: World, pos: BlockPos, player: EntityPlayer?, ignoreTrap: Boolean) { fun igniteTNT(world: World, pos: BlockPos, player: EntityPlayer?, ignoreTrap: Boolean) {
@@ -67,14 +66,8 @@ class ItemFlintAndInfernium(properties: Properties) : Item(properties) {
pos.removeBlock(world) pos.removeBlock(world)
} }
override fun onItemUse(context: ItemUseContext): ActionResultType { override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType? {
val player = context.player ?: return FAIL if (!BlockEditor.canEdit(pos, player, item)) {
val world = context.world
val pos = context.pos
val heldItem = player.getHeldItem(context.hand)
if (!BlockEditor.canEdit(pos, player, heldItem)) {
return FAIL return FAIL
} }
@@ -85,11 +78,11 @@ class ItemFlintAndInfernium(properties: Properties) : Item(properties) {
igniteTNT(world, pos, player, ignoreTrap = false) igniteTNT(world, pos, player, ignoreTrap = false)
} }
else { else {
BlockEditor.place(ModBlocks.ETERNAL_FIRE, player, heldItem, context) ?: return FAIL BlockEditor.place(ModBlocks.ETERNAL_FIRE, player, item, ctx) ?: return FAIL
} }
Sounds.ITEM_FLINTANDSTEEL_USE.playServer(world, pos, SoundCategory.BLOCKS, volume = 1.1F, pitch = world.rand.nextFloat(0.4F, 0.5F)) Sounds.ITEM_FLINTANDSTEEL_USE.playServer(world, pos, SoundCategory.BLOCKS, volume = 1.1F, pitch = world.rand.nextFloat(0.4F, 0.5F))
heldItem.doDamage(1, player, context.hand) item.doDamage(1, player, ctx.hand)
} }
return SUCCESS return SUCCESS

View File

@@ -9,6 +9,7 @@ import chylex.hee.game.entity.item.EntityTokenHolder
import chylex.hee.game.entity.selectExistingEntities import chylex.hee.game.entity.selectExistingEntities
import chylex.hee.game.inventory.heeTag import chylex.hee.game.inventory.heeTag
import chylex.hee.game.inventory.heeTagOrNull import chylex.hee.game.inventory.heeTagOrNull
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.game.mechanics.portal.DimensionTeleporter import chylex.hee.game.mechanics.portal.DimensionTeleporter
import chylex.hee.game.mechanics.portal.EntityPortalContact import chylex.hee.game.mechanics.portal.EntityPortalContact
import chylex.hee.game.world.BlockEditor import chylex.hee.game.world.BlockEditor
@@ -34,7 +35,6 @@ import chylex.hee.system.serialization.putEnum
import net.minecraft.client.renderer.color.IItemColor import net.minecraft.client.renderer.color.IItemColor
import net.minecraft.client.util.ITooltipFlag import net.minecraft.client.util.ITooltipFlag
import net.minecraft.entity.Entity import net.minecraft.entity.Entity
import net.minecraft.item.Item
import net.minecraft.item.ItemGroup import net.minecraft.item.ItemGroup
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUseContext import net.minecraft.item.ItemUseContext
@@ -43,13 +43,14 @@ import net.minecraft.util.ActionResultType
import net.minecraft.util.Hand import net.minecraft.util.Hand
import net.minecraft.util.NonNullList import net.minecraft.util.NonNullList
import net.minecraft.util.math.AxisAlignedBB import net.minecraft.util.math.AxisAlignedBB
import net.minecraft.util.math.BlockPos
import net.minecraft.util.text.ITextComponent import net.minecraft.util.text.ITextComponent
import net.minecraft.util.text.StringTextComponent import net.minecraft.util.text.StringTextComponent
import net.minecraft.util.text.TranslationTextComponent import net.minecraft.util.text.TranslationTextComponent
import net.minecraft.world.World import net.minecraft.world.World
import net.minecraft.world.dimension.DimensionType import net.minecraft.world.dimension.DimensionType
class ItemPortalToken(properties: Properties) : Item(properties) { class ItemPortalToken(properties: Properties) : ItemWithComponents(properties), UseOnBlockComponent {
companion object { companion object {
private const val TYPE_TAG = "Type" private const val TYPE_TAG = "Type"
private const val TERRITORY_TYPE_TAG = "Territory" private const val TERRITORY_TYPE_TAG = "Territory"
@@ -72,6 +73,8 @@ class ItemPortalToken(properties: Properties) : Item(properties) {
} }
init { init {
components.attach(this)
addPropertyOverride(Resource.Custom("token_type")) { stack, _, _ -> addPropertyOverride(Resource.Custom("token_type")) { stack, _, _ ->
getTokenType(stack).propertyValue + (if (stack.heeTagOrNull.hasKey(IS_CORRUPTED_TAG)) 0.5F else 0F) getTokenType(stack).propertyValue + (if (stack.heeTagOrNull.hasKey(IS_CORRUPTED_TAG)) 0.5F else 0F)
} }
@@ -178,10 +181,7 @@ class ItemPortalToken(properties: Properties) : Item(properties) {
return ActionResult(SUCCESS, heldItem) return ActionResult(SUCCESS, heldItem)
} }
override fun onItemUse(context: ItemUseContext): ActionResultType { override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType {
val player = context.player ?: return FAIL
val world = context.world
if (!player.isCreative || player.isSneaking) { if (!player.isCreative || player.isSneaking) {
return PASS return PASS
} }
@@ -190,16 +190,14 @@ class ItemPortalToken(properties: Properties) : Item(properties) {
return SUCCESS return SUCCESS
} }
val targetPos = context.pos.up() val targetPos = pos.up()
val territoryType = getTerritoryType(item)
val heldItem = player.getHeldItem(context.hand) if (territoryType == null || ctx.face != UP || !BlockEditor.canEdit(targetPos, player, item) || world.selectExistingEntities.inBox<EntityTokenHolder>(AxisAlignedBB(targetPos)).any()) {
val territoryType = getTerritoryType(heldItem)
if (territoryType == null || context.face != UP || !BlockEditor.canEdit(targetPos, player, heldItem) || world.selectExistingEntities.inBox<EntityTokenHolder>(AxisAlignedBB(targetPos)).any()) {
return FAIL return FAIL
} }
world.addEntity(EntityTokenHolder(world, targetPos, getTokenType(heldItem), territoryType)) world.addEntity(EntityTokenHolder(world, targetPos, getTokenType(item), territoryType))
return SUCCESS return SUCCESS
} }

View File

@@ -1,6 +1,7 @@
package chylex.hee.game.item package chylex.hee.game.item
import chylex.hee.game.block.entity.TileEntityMinersBurialAltar import chylex.hee.game.block.entity.TileEntityMinersBurialAltar
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.game.world.BlockEditor import chylex.hee.game.world.BlockEditor
import chylex.hee.game.world.getTile import chylex.hee.game.world.getTile
import chylex.hee.game.world.playUniversal import chylex.hee.game.world.playUniversal
@@ -8,33 +9,34 @@ import chylex.hee.init.ModSounds
import chylex.hee.system.migration.ActionResult.FAIL import chylex.hee.system.migration.ActionResult.FAIL
import chylex.hee.system.migration.ActionResult.PASS import chylex.hee.system.migration.ActionResult.PASS
import chylex.hee.system.migration.ActionResult.SUCCESS import chylex.hee.system.migration.ActionResult.SUCCESS
import net.minecraft.item.Item import chylex.hee.system.migration.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUseContext import net.minecraft.item.ItemUseContext
import net.minecraft.util.ActionResultType import net.minecraft.util.ActionResultType
import net.minecraft.util.SoundCategory import net.minecraft.util.SoundCategory
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
class ItemPuzzleMedallion(properties: Properties) : Item(properties) { class ItemPuzzleMedallion(properties: Properties) : ItemWithComponents(properties) {
override fun onItemUse(context: ItemUseContext): ActionResultType { init {
val player = context.player ?: return FAIL components.attach(object : UseOnBlockComponent {
val world = context.world override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType {
val pos = context.pos if (!BlockEditor.canEdit(pos, player, item)) {
return FAIL
val heldItem = player.getHeldItem(context.hand) }
if (!BlockEditor.canEdit(pos, player, heldItem)) { val tile = pos.getTile<TileEntityMinersBurialAltar>(world)
return FAIL
} if (tile != null && !tile.hasMedallion) {
tile.hasMedallion = true
val tile = pos.getTile<TileEntityMinersBurialAltar>(world) item.shrink(1)
if (tile != null && !tile.hasMedallion) { ModSounds.ITEM_PUZZLE_MEDALLION_INSERT.playUniversal(player, pos, SoundCategory.BLOCKS, volume = 2F, pitch = 0.8F)
tile.hasMedallion = true return SUCCESS
heldItem.shrink(1) }
ModSounds.ITEM_PUZZLE_MEDALLION_INSERT.playUniversal(player, pos, SoundCategory.BLOCKS, volume = 2F, pitch = 0.8F) return PASS
return SUCCESS }
} })
return PASS
} }
} }

View File

@@ -3,6 +3,7 @@ package chylex.hee.game.item
import chylex.hee.client.model.ModelHelper import chylex.hee.client.model.ModelHelper
import chylex.hee.game.block.entity.TileEntityEnergyCluster import chylex.hee.game.block.entity.TileEntityEnergyCluster
import chylex.hee.game.entity.item.EntityItemRevitalizationSubstance import chylex.hee.game.entity.item.EntityItemRevitalizationSubstance
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.game.mechanics.energy.IClusterHealth.HealthOverride.REVITALIZING import chylex.hee.game.mechanics.energy.IClusterHealth.HealthOverride.REVITALIZING
import chylex.hee.game.particle.ParticleSmokeCustom import chylex.hee.game.particle.ParticleSmokeCustom
import chylex.hee.game.particle.spawner.ParticleSpawnerCustom import chylex.hee.game.particle.spawner.ParticleSpawnerCustom
@@ -26,7 +27,6 @@ import chylex.hee.system.serialization.readPos
import chylex.hee.system.serialization.use import chylex.hee.system.serialization.use
import chylex.hee.system.serialization.writePos import chylex.hee.system.serialization.writePos
import net.minecraft.entity.Entity import net.minecraft.entity.Entity
import net.minecraft.item.Item
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUseContext import net.minecraft.item.ItemUseContext
import net.minecraft.network.PacketBuffer import net.minecraft.network.PacketBuffer
@@ -37,7 +37,7 @@ import net.minecraft.util.math.BlockPos
import net.minecraft.world.World import net.minecraft.world.World
import java.util.Random import java.util.Random
class ItemRevitalizationSubstance(properties: Properties) : Item(properties) { class ItemRevitalizationSubstance(properties: Properties) : ItemWithComponents(properties), UseOnBlockComponent {
companion object { companion object {
private val PARTICLE_FAIL = ParticleSpawnerCustom( private val PARTICLE_FAIL = ParticleSpawnerCustom(
type = ParticleSmokeCustom, type = ParticleSmokeCustom,
@@ -70,11 +70,11 @@ class ItemRevitalizationSubstance(properties: Properties) : Item(properties) {
} }
} }
override fun onItemUse(context: ItemUseContext): ActionResultType { init {
val player = context.player ?: return FAIL components.attach(this)
val world = context.world }
val pos = context.pos
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType? {
if (world.isRemote) { if (world.isRemote) {
return FAIL // disable animation return FAIL // disable animation
} }
@@ -83,11 +83,11 @@ class ItemRevitalizationSubstance(properties: Properties) : Item(properties) {
if (cluster.currentHealth != REVITALIZING) { if (cluster.currentHealth != REVITALIZING) {
if (cluster.addRevitalizationSubstance()) { if (cluster.addRevitalizationSubstance()) {
player.getHeldItem(context.hand).shrink(1) player.getHeldItem(ctx.hand).shrink(1)
ModSounds.ITEM_REVITALIZATION_SUBSTANCE_USE_SUCCESS.playServer(world, pos, SoundCategory.BLOCKS, volume = 0.5F) ModSounds.ITEM_REVITALIZATION_SUBSTANCE_USE_SUCCESS.playServer(world, pos, SoundCategory.BLOCKS, volume = 0.5F)
} }
else { else {
PacketClientFX(FX_FAIL, FxUseData(pos, player, context.hand)).sendToAllAround(player, 24.0) PacketClientFX(FX_FAIL, FxUseData(pos, player, ctx.hand)).sendToAllAround(player, 24.0)
} }
} }

View File

@@ -2,33 +2,33 @@ package chylex.hee.game.item
import chylex.hee.game.block.BlockAbstractTableTile import chylex.hee.game.block.BlockAbstractTableTile
import chylex.hee.game.block.BlockTableBase import chylex.hee.game.block.BlockTableBase
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.game.world.BlockEditor import chylex.hee.game.world.BlockEditor
import chylex.hee.game.world.breakBlock import chylex.hee.game.world.breakBlock
import chylex.hee.game.world.getBlock import chylex.hee.game.world.getBlock
import chylex.hee.game.world.setBlock import chylex.hee.game.world.setBlock
import chylex.hee.system.forge.Side import chylex.hee.system.forge.Side
import chylex.hee.system.forge.Sided import chylex.hee.system.forge.Sided
import chylex.hee.system.migration.EntityPlayer
import net.minecraft.client.util.ITooltipFlag import net.minecraft.client.util.ITooltipFlag
import net.minecraft.item.Item
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUseContext import net.minecraft.item.ItemUseContext
import net.minecraft.util.ActionResultType import net.minecraft.util.ActionResultType
import net.minecraft.util.ActionResultType.FAIL import net.minecraft.util.ActionResultType.FAIL
import net.minecraft.util.ActionResultType.PASS import net.minecraft.util.ActionResultType.PASS
import net.minecraft.util.ActionResultType.SUCCESS import net.minecraft.util.ActionResultType.SUCCESS
import net.minecraft.util.math.BlockPos
import net.minecraft.util.text.ITextComponent import net.minecraft.util.text.ITextComponent
import net.minecraft.util.text.TranslationTextComponent import net.minecraft.util.text.TranslationTextComponent
import net.minecraft.world.World import net.minecraft.world.World
class ItemTableCore(private val tableBlocks: Array<BlockAbstractTableTile<*>>, properties: Properties) : Item(properties) { class ItemTableCore(private val tableBlocks: Array<BlockAbstractTableTile<*>>, properties: Properties) : ItemWithComponents(properties), UseOnBlockComponent {
override fun onItemUse(context: ItemUseContext): ActionResultType { init {
val player = context.player ?: return FAIL components.attach(this)
val world = context.world }
val pos = context.pos
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType {
val heldItem = player.getHeldItem(context.hand) if (!BlockEditor.canEdit(pos, player, item)) {
if (!BlockEditor.canEdit(pos, player, heldItem)) {
return FAIL return FAIL
} }
@@ -42,7 +42,7 @@ class ItemTableCore(private val tableBlocks: Array<BlockAbstractTableTile<*>>, p
pos.setBlock(world, table) pos.setBlock(world, table)
} }
heldItem.shrink(1) item.shrink(1)
return SUCCESS return SUCCESS
} }

View File

@@ -12,6 +12,7 @@ import chylex.hee.game.item.ItemTableLink.Companion.SoundType.LINK_FAIL
import chylex.hee.game.item.ItemTableLink.Companion.SoundType.LINK_OUTPUT import chylex.hee.game.item.ItemTableLink.Companion.SoundType.LINK_OUTPUT
import chylex.hee.game.item.ItemTableLink.Companion.SoundType.LINK_RESTART import chylex.hee.game.item.ItemTableLink.Companion.SoundType.LINK_RESTART
import chylex.hee.game.item.ItemTableLink.Companion.SoundType.LINK_SUCCESS import chylex.hee.game.item.ItemTableLink.Companion.SoundType.LINK_SUCCESS
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.game.world.getBlock import chylex.hee.game.world.getBlock
import chylex.hee.game.world.getTile import chylex.hee.game.world.getTile
import chylex.hee.game.world.playClient import chylex.hee.game.world.playClient
@@ -26,6 +27,7 @@ import chylex.hee.system.forge.Sided
import chylex.hee.system.migration.ActionResult.FAIL import chylex.hee.system.migration.ActionResult.FAIL
import chylex.hee.system.migration.ActionResult.SUCCESS import chylex.hee.system.migration.ActionResult.SUCCESS
import chylex.hee.system.migration.EntityItem import chylex.hee.system.migration.EntityItem
import chylex.hee.system.migration.EntityPlayer
import chylex.hee.system.random.nextFloat import chylex.hee.system.random.nextFloat
import chylex.hee.system.serialization.getPos import chylex.hee.system.serialization.getPos
import chylex.hee.system.serialization.hasKey import chylex.hee.system.serialization.hasKey
@@ -34,7 +36,6 @@ import chylex.hee.system.serialization.readPos
import chylex.hee.system.serialization.use import chylex.hee.system.serialization.use
import chylex.hee.system.serialization.writePos import chylex.hee.system.serialization.writePos
import net.minecraft.entity.Entity import net.minecraft.entity.Entity
import net.minecraft.item.Item
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUseContext import net.minecraft.item.ItemUseContext
import net.minecraft.network.PacketBuffer import net.minecraft.network.PacketBuffer
@@ -44,7 +45,7 @@ import net.minecraft.util.math.BlockPos
import net.minecraft.world.World import net.minecraft.world.World
import java.util.Random import java.util.Random
class ItemTableLink(properties: Properties) : Item(properties) { class ItemTableLink(properties: Properties) : ItemWithComponents(properties), UseOnBlockComponent {
companion object { companion object {
private const val POS_TAG = "StoredPos" private const val POS_TAG = "StoredPos"
private const val TIME_TAG = "StoredTime" private const val TIME_TAG = "StoredTime"
@@ -106,11 +107,11 @@ class ItemTableLink(properties: Properties) : Item(properties) {
} }
} }
override fun onItemUse(context: ItemUseContext): ActionResultType { init {
val player = context.player ?: return FAIL components.attach(this)
val world = context.world }
val pos = context.pos
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType? {
if (!player.isSneaking || !isValidTarget(world, pos)) { if (!player.isSneaking || !isValidTarget(world, pos)) {
val pedestal = pos.getTile<TileEntityTablePedestal>(world) val pedestal = pos.getTile<TileEntityTablePedestal>(world)
@@ -131,7 +132,7 @@ class ItemTableLink(properties: Properties) : Item(properties) {
return SUCCESS return SUCCESS
} }
val heldItem = player.getHeldItem(context.hand) val heldItem = player.getHeldItem(ctx.hand)
var newStoredPos = pos var newStoredPos = pos
var soundType = LINK_RESTART var soundType = LINK_RESTART

View File

@@ -21,6 +21,7 @@ import chylex.hee.game.world.structure.trigger.EntityStructureTrigger
import chylex.hee.game.world.territory.TerritoryType import chylex.hee.game.world.territory.TerritoryType
import chylex.hee.init.ModBlocks import chylex.hee.init.ModBlocks
import chylex.hee.network.client.PacketClientFX import chylex.hee.network.client.PacketClientFX
import chylex.hee.network.fx.FxVecData
import chylex.hee.system.facades.Facing4 import chylex.hee.system.facades.Facing4
import chylex.hee.system.math.addY import chylex.hee.system.math.addY
import chylex.hee.system.math.offsetTowards import chylex.hee.system.math.offsetTowards
@@ -145,9 +146,8 @@ abstract class ObsidianTowerLevel_Top(file: String) : ObsidianTowerLevel_General
val offsetProgress = chargeAnim.pow(0.8F).toDouble() val offsetProgress = chargeAnim.pow(0.8F).toDouble()
val particlePos = start.center.offsetTowards(tokenHolder.posVec.addY(tokenHolder.height * 0.5), offsetProgress).addY(progressCurvePoint * 6.0) val particlePos = start.center.offsetTowards(tokenHolder.posVec.addY(tokenHolder.height * 0.5), offsetProgress).addY(progressCurvePoint * 6.0)
val particleData = EnderEyeSpawnerParticles.Companion.ParticleData(particlePos)
PacketClientFX(EnderEyeSpawnerParticles.FX_PARTICLE, particleData).sendToAllAround(entity.world, pos, 256.0) PacketClientFX(EnderEyeSpawnerParticles.FX_PARTICLE, FxVecData(particlePos)).sendToAllAround(entity.world, pos, 256.0)
} }
if (chargeAnim == 1F) { if (chargeAnim == 1F) {

View File

@@ -21,6 +21,7 @@ import chylex.hee.game.world.feature.tombdungeon.piece.TombDungeonAbstractPiece
import chylex.hee.system.math.floorToInt import chylex.hee.system.math.floorToInt
import chylex.hee.system.random.nextFloat import chylex.hee.system.random.nextFloat
import chylex.hee.system.random.nextInt import chylex.hee.system.random.nextInt
import chylex.hee.system.random.nextRounded
import java.util.Random import java.util.Random
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
@@ -110,49 +111,34 @@ enum class TombDungeonLevel(val isFancy: Boolean, private val corridorFactor: In
return when(this) { return when(this) {
FIRST -> when(rand.nextInt(0, 3)) { FIRST -> when(rand.nextInt(0, 3)) {
0 -> MOBS(undreads = rand.nextInt(0, h), spiderlings = 1 + m) 0 -> MOBS(undreads = rand.nextRounded(0.2F), spiderlings = 1 + m + rand.nextInt(0, h))
1 -> MOBS(undreads = rand.nextInt(0, h), spiderlings = 2 + m) 1 -> MOBS(undreads = rand.nextRounded(0.3F * m), spiderlings = 1 + h + rand.nextInt(0, m))
2 -> MOBS(undreads = 1 + h, spiderlings = 0 + rand.nextInt(0, m)) 2 -> MOBS(undreads = rand.nextRounded(0.3F * h), spiderlings = 2 + m)
else -> MOBS(undreads = 1 + h, spiderlings = 1 + rand.nextInt(0, m)) else -> MOBS(undreads = 0, spiderlings = 1 + rand.nextInt(0, 1 + m))
} }
SECOND -> when(rand.nextInt(0, 3)) { SECOND -> when(rand.nextInt(0, 3)) {
0 -> MOBS(undreads = rand.nextInt(0, m + h), spiderlings = 1 + rand.nextInt(0, m + h)) 0 -> MOBS(undreads = rand.nextRounded(0.3F), spiderlings = 1 + m + rand.nextInt(0, h))
1 -> MOBS(undreads = 1 + rand.nextInt(0, m + h), spiderlings = rand.nextInt(0, m + h)) 1 -> MOBS(undreads = rand.nextRounded(0.4F * m), spiderlings = 1 + rand.nextInt(0, 2 * m))
2 -> MOBS(undreads = 1 + m + rand.nextInt(h, h * 2), spiderlings = 0) else -> MOBS(undreads = 0, spiderlings = rand.nextRounded(1.8F + (m * 0.55F) + (h * 0.55F)))
else -> MOBS(undreads = 1 + h, spiderlings = 1 + m + rand.nextInt(h, h * 3))
} }
// TODO THIRD -> when(rand.nextInt(0, 2)) {
0 -> MOBS(undreads = rand.nextInt(0, 1 + h), spiderlings = rand.nextRounded(1.4F + (m * 0.5F)) + rand.nextInt(0, m))
1 -> MOBS(undreads = rand.nextInt(0, 1 + m), spiderlings = rand.nextRounded(1.2F) + rand.nextInt(0, 2 * h))
else -> MOBS(undreads = rand.nextInt(0, 1 + m), spiderlings = 2 + rand.nextInt(0, m + h))
}
else -> 0 to 0 FOURTH -> when(rand.nextInt(0, 5)) {
in 0..1 -> MOBS(undreads = 1 + rand.nextInt(h, 3 + h), spiderlings = rand.nextRounded(0.4F * m) + rand.nextInt(0, m + h))
else -> MOBS(undreads = 2 + rand.nextInt(m, 2 * m), spiderlings = rand.nextRounded(0.3F + (m * 0.1F) + (h * 0.3F)))
}
else -> when(rand.nextInt(0, 2)) {
0 -> MOBS(undreads = 1 + h + rand.nextInt(m, 1 + (m * 2)) + rand.nextInt(h, 1 + h), spiderlings = rand.nextInt(0, m))
else -> MOBS(undreads = 2 + h + rand.nextInt(m, 2 * m), spiderlings = rand.nextRounded(0.2F + (m * 0.2F)))
}
} }
/*
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount
import chylex.hee.system.math.floorToInt
import com.google.common.collect.Comparators
import java.util.Random
val rand = Random()
val level = TombDungeonLevel.FIRST
val reps = 100000
MobAmount.values().map { amount ->
"\n\n" + amount.name + "\n" + "-".repeat(amount.name.length) + "\n" + (1..reps)
.map { level.pickUndreadAndSpiderlingSpawns(rand, amount) }
.groupingBy { it }
.eachCount()
.entries
.map { ((it.value * 100.0) / reps).floorToInt() to it.key }
.sortedWith(compareBy({ it.first }, { it.second.first }, { it.second.second }))
.map { "U = ${it.second.first}, S = ${it.second.second} ... ${it.first} %" }
.joinToString("\n")
}.joinToString("\n")
*/
} }
private fun MOBS(undreads: Int, spiderlings: Int) = undreads to spiderlings private fun MOBS(undreads: Int, spiderlings: Int) = undreads to spiderlings

View File

@@ -1,38 +1,56 @@
package chylex.hee.game.world.feature.tombdungeon.piece package chylex.hee.game.world.feature.tombdungeon.piece
import chylex.hee.game.block.BlockGraveDirt
import chylex.hee.game.entity.living.EntityMobSpiderling
import chylex.hee.game.entity.living.EntityMobUndread
import chylex.hee.game.entity.posVec import chylex.hee.game.entity.posVec
import chylex.hee.game.entity.selectExistingEntities
import chylex.hee.game.entity.selectVulnerableEntities
import chylex.hee.game.entity.technical.EntityTechnicalTrigger import chylex.hee.game.entity.technical.EntityTechnicalTrigger
import chylex.hee.game.entity.technical.EntityTechnicalTrigger.ITriggerHandler import chylex.hee.game.entity.technical.EntityTechnicalTrigger.ITriggerHandler
import chylex.hee.game.entity.technical.EntityTechnicalTrigger.Types.TOMB_DUNGEON_UNDREAD_SPAWNER import chylex.hee.game.entity.technical.EntityTechnicalTrigger.Types.TOMB_DUNGEON_UNDREAD_SPAWNER
import chylex.hee.game.world.Pos import chylex.hee.game.world.Pos
import chylex.hee.game.world.distanceSqTo import chylex.hee.game.world.distanceSqTo
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount
import chylex.hee.game.world.feature.tombdungeon.connection.TombDungeonConnection import chylex.hee.game.world.feature.tombdungeon.connection.TombDungeonConnection
import chylex.hee.game.world.feature.tombdungeon.connection.TombDungeonConnectionType.TOMB_ENTRANCE_INSIDE import chylex.hee.game.world.feature.tombdungeon.connection.TombDungeonConnectionType.TOMB_ENTRANCE_INSIDE
import chylex.hee.game.world.getBlock
import chylex.hee.game.world.getState
import chylex.hee.game.world.isAir import chylex.hee.game.world.isAir
import chylex.hee.game.world.offsetWhile import chylex.hee.game.world.offsetWhile
import chylex.hee.game.world.playClient
import chylex.hee.game.world.structure.IStructureWorld import chylex.hee.game.world.structure.IStructureWorld
import chylex.hee.game.world.structure.piece.IStructurePieceConnection import chylex.hee.game.world.structure.piece.IStructurePieceConnection
import chylex.hee.game.world.structure.trigger.EntityStructureTrigger import chylex.hee.game.world.structure.trigger.EntityStructureTrigger
import chylex.hee.init.ModEntities import chylex.hee.init.ModEntities
import chylex.hee.network.client.PacketClientFX
import chylex.hee.network.fx.FxVecData
import chylex.hee.network.fx.FxVecHandler
import chylex.hee.system.math.Vec
import chylex.hee.system.math.Vec3 import chylex.hee.system.math.Vec3
import chylex.hee.system.math.addY import chylex.hee.system.math.addY
import chylex.hee.system.math.directionTowards
import chylex.hee.system.math.square import chylex.hee.system.math.square
import chylex.hee.system.math.toYaw
import chylex.hee.system.migration.BlockWeb
import chylex.hee.system.migration.EntityLivingBase
import chylex.hee.system.migration.EntityPlayer
import chylex.hee.system.migration.Facing.DOWN import chylex.hee.system.migration.Facing.DOWN
import chylex.hee.system.migration.Facing.NORTH import chylex.hee.system.migration.Facing.NORTH
import chylex.hee.system.migration.Facing.SOUTH import chylex.hee.system.migration.Facing.SOUTH
import chylex.hee.system.random.nextFloat import chylex.hee.system.random.nextFloat
import chylex.hee.system.random.nextInt
import chylex.hee.system.random.nextItem
import chylex.hee.system.serialization.TagCompound import chylex.hee.system.serialization.TagCompound
import chylex.hee.system.serialization.use import chylex.hee.system.serialization.use
import net.minecraft.entity.EntitySpawnPlacementRegistry import net.minecraft.entity.EntitySpawnPlacementRegistry
import net.minecraft.entity.SpawnReason.SPAWNER import net.minecraft.entity.SpawnReason.STRUCTURE
import net.minecraft.particles.RedstoneParticleData import net.minecraft.util.Direction.Axis
import net.minecraft.util.Direction.EAST
import net.minecraft.util.Direction.WEST
import net.minecraft.util.math.AxisAlignedBB import net.minecraft.util.math.AxisAlignedBB
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Vec3d
import net.minecraft.world.World import net.minecraft.world.World
import net.minecraft.world.server.ServerWorld
import java.util.Random import java.util.Random
abstract class TombDungeonRoom_Tomb(file: String, entranceY: Int, allowSecrets: Boolean, isFancy: Boolean) : TombDungeonRoom(file, isFancy) { abstract class TombDungeonRoom_Tomb(file: String, entranceY: Int, allowSecrets: Boolean, isFancy: Boolean) : TombDungeonRoom(file, isFancy) {
@@ -43,8 +61,6 @@ abstract class TombDungeonRoom_Tomb(file: String, entranceY: Int, allowSecrets:
TombDungeonConnection(TOMB_ENTRANCE_INSIDE, Pos(centerX, entranceY, maxZ), SOUTH) TombDungeonConnection(TOMB_ENTRANCE_INSIDE, Pos(centerX, entranceY, maxZ), SOUTH)
) )
protected abstract val mobAmount: MobAmount?
override fun generate(world: IStructureWorld, instance: Instance) { override fun generate(world: IStructureWorld, instance: Instance) {
super.generate(world, instance) super.generate(world, instance)
generateSpawnerTrigger(world, instance) generateSpawnerTrigger(world, instance)
@@ -52,19 +68,16 @@ abstract class TombDungeonRoom_Tomb(file: String, entranceY: Int, allowSecrets:
protected open fun generateSpawnerTrigger(world: IStructureWorld, instance: Instance) { protected open fun generateSpawnerTrigger(world: IStructureWorld, instance: Instance) {
val rand = world.rand val rand = world.rand
val level = instance.context val level = instance.context ?: return
val mobAmount = getSpawnerTriggerMobAmount(rand, level) ?: return
if (rand.nextInt(3) == 0 && level != null) { val (undreads, spiderlings) = level.pickUndreadAndSpiderlingSpawns(rand, mobAmount)
val mobAmount = mobAmount MobSpawnerTrigger.place(world, entrance = connections.first().offset, width = maxX, depth = maxZ, undreads, spiderlings)
if (mobAmount != null) {
val (undreads, spiderlings) = level.pickUndreadAndSpiderlingSpawns(rand, mobAmount)
UndreadSpawnerTrigger.place(world, entrance = connections.first().offset, width = maxX, depth = maxZ, undreads, spiderlings)
}
}
} }
class UndreadSpawnerTrigger() : ITriggerHandler { protected abstract fun getSpawnerTriggerMobAmount(rand: Random, level: TombDungeonLevel): MobAmount?
class MobSpawnerTrigger() : ITriggerHandler {
companion object { companion object {
private const val WIDTH_TAG = "Width" private const val WIDTH_TAG = "Width"
private const val DEPTH_TAG = "Depth" private const val DEPTH_TAG = "Depth"
@@ -72,12 +85,32 @@ abstract class TombDungeonRoom_Tomb(file: String, entranceY: Int, allowSecrets:
private const val SPIDERLINGS_TAG = "Spiderlings" private const val SPIDERLINGS_TAG = "Spiderlings"
fun place(world: IStructureWorld, entrance: BlockPos, width: Int, depth: Int, undreads: Int, spiderlings: Int) { fun place(world: IStructureWorld, entrance: BlockPos, width: Int, depth: Int, undreads: Int, spiderlings: Int) {
val nbt = UndreadSpawnerTrigger(width - 1.0, depth - 1.0, undreads, spiderlings).serializeNBT() val nbt = MobSpawnerTrigger(width - 1.0, depth - 1.0, undreads, spiderlings).serializeNBT()
world.addTrigger(entrance, EntityStructureTrigger({ wrld -> world.addTrigger(entrance, EntityStructureTrigger({ wrld ->
EntityTechnicalTrigger(wrld, TOMB_DUNGEON_UNDREAD_SPAWNER, nbt).apply { rotationYaw = NORTH.horizontalAngle } EntityTechnicalTrigger(wrld, TOMB_DUNGEON_UNDREAD_SPAWNER, nbt).apply { rotationYaw = NORTH.horizontalAngle }
}, yOffset = 0.5)) }, yOffset = 0.5))
} }
val FX_SPAWN_UNDREAD = object : FxVecHandler() {
override fun handle(world: World, rand: Random, vec: Vec3d) {
EntityMobUndread(world).apply {
setLocationAndAngles(vec.x, vec.y, vec.z, 0F, 0F)
spawnExplosionParticle()
deathSound.playClient(vec, soundCategory, volume = 1.2F, pitch = soundPitch * 0.7F)
}
}
}
val FX_SPAWN_SPIDERLING = object : FxVecHandler() {
override fun handle(world: World, rand: Random, vec: Vec3d) {
EntityMobSpiderling(world).apply {
setLocationAndAngles(vec.x, vec.y, vec.z, 0F, 0F)
spawnExplosionParticle()
ambientSound.playClient(vec, soundCategory, volume = 1F, pitch = soundPitch)
}
}
}
} }
private var width = 0.0 private var width = 0.0
@@ -108,46 +141,71 @@ abstract class TombDungeonRoom_Tomb(file: String, entranceY: Int, allowSecrets:
vecR.scale(width * 0.5).add(vecF.scale(depth)).addY(2.5) vecR.scale(width * 0.5).add(vecF.scale(depth)).addY(2.5)
).offset(entity.posVec) ).offset(entity.posVec)
repeat(10) { val nearbyPlayers = world.selectVulnerableEntities.inBox<EntityPlayer>(aabb)
(world as ServerWorld).spawnParticle(RedstoneParticleData(if (facing == NORTH || facing == EAST) 1F else 0F, if (facing == SOUTH || facing == EAST) 1F else 0F, if (facing == WEST) 1F else 0F, 1F), if (nearbyPlayers.isEmpty()) {
world.rand.nextFloat(aabb.minX, aabb.maxX),
world.rand.nextFloat(aabb.minY, aabb.maxY),
world.rand.nextFloat(aabb.minZ, aabb.maxZ),
1, 0.0, 0.0, 0.0, 0.0
)
}//TODO
if (world.players.none { aabb.contains(it.posVec) }) {
return return
} }
val rand = world.rand val rand = world.rand
val minPlayerDist = ((depth * 0.4) + (width * 0.16)).coerceIn(1.5, 3.5)
for((entityCount, entityType) in listOf( for((entityCount, entityType, spawnParticle) in listOf(
undreads to ModEntities.UNDREAD, Triple(undreads, ModEntities.UNDREAD, FX_SPAWN_UNDREAD),
spiderlings to ModEntities.SPIDERLING Triple(spiderlings, ModEntities.SPIDERLING, FX_SPAWN_SPIDERLING)
)) { )) {
repeat(entityCount) { repeat(entityCount) {
for(attempt in 1..20) { var bestPos: BlockPos? = null
for(attempt in 1..75) {
val pos = Pos( val pos = Pos(
rand.nextFloat(aabb.minX, aabb.maxX), rand.nextFloat(aabb.minX, aabb.maxX),
rand.nextFloat(aabb.minY, aabb.maxY) + 0.5, rand.nextFloat(aabb.minY, aabb.maxY) + 0.5,
rand.nextFloat(aabb.minZ, aabb.maxZ), rand.nextFloat(aabb.minZ, aabb.maxZ),
).offsetWhile(DOWN, 1..3) { ).offsetWhile(DOWN, 1..3) {
it.isAir(world) it.isAir(world) || it.getBlock(world) is BlockWeb
} }
if (EntitySpawnPlacementRegistry.func_223515_a(entityType, world, SPAWNER, pos, rand) && val collisionCheckAABB = entityType.getBoundingBoxWithSizeApplied(pos.x + 0.5, pos.y.toDouble(), pos.z + 0.5).grow(0.2, 0.0, 0.2)
world.hasNoCollisions(entityType.getBoundingBoxWithSizeApplied(pos.x + 0.5, pos.y.toDouble(), pos.z + 0.5)) &&
world.players.none { pos.distanceSqTo(it) < square(2.75) } if (EntitySpawnPlacementRegistry.func_223515_a(entityType, world, STRUCTURE, pos, rand) &&
world.hasNoCollisions(collisionCheckAABB) &&
world.selectExistingEntities.inBox<EntityLivingBase>(collisionCheckAABB.grow(0.4, 0.0, 0.4)).isEmpty() &&
world.players.none { pos.distanceSqTo(it) < square(minPlayerDist) }
) { ) {
entityType.create(world)?.apply { bestPos = pos
setLocationAndAngles(pos.x + 0.5, pos.y.toDouble(), pos.z + 0.5, rand.nextFloat(0F, 360F), 0F)
spawnExplosionParticle() if (entityType === ModEntities.UNDREAD) {
world.addEntity(this) if (rand.nextInt(5) == 0 || pos.down().getBlock(world) is BlockGraveDirt) {
break
}
}
else {
break
}
}
}
if (bestPos != null) {
val x = bestPos.x + rand.nextFloat(0.35, 0.65)
val y = bestPos.y + bestPos.down().getState(world).getCollisionShape(world, bestPos).getEnd(Axis.Y) - 1.0
val z = bestPos.z + rand.nextFloat(0.35, 0.65)
val vec = Vec(x, y, z)
val target = rand.nextItem(nearbyPlayers)
entityType.create(world)?.apply {
setLocationAndAngles(x, y, z, vec.directionTowards(target.posVec).toYaw(), 0F)
rotationYawHead = rotationYaw
attackTarget = target
onGround = true // allow instant pathfinding in MeleeAttackGoal
if (this is EntityMobSpiderling) {
wakeUp(preventSleep = true, aiDelayTicks = if (rand.nextInt(10) == 0) rand.nextInt(4, 6) else rand.nextInt(11, 18))
} }
break onInitialSpawn(world, world.getDifficultyForLocation(bestPos), STRUCTURE, null, null)
world.addEntity(this)
PacketClientFX(spawnParticle, FxVecData(vec)).sendToAllAround(this, 24.0)
} }
} }
} }

View File

@@ -2,11 +2,12 @@ package chylex.hee.game.world.feature.tombdungeon.piece
import chylex.hee.game.block.BlockGraveDirt import chylex.hee.game.block.BlockGraveDirt
import chylex.hee.game.world.Pos import chylex.hee.game.world.Pos
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount
import chylex.hee.game.world.feature.tombdungeon.TombDungeonPieces import chylex.hee.game.world.feature.tombdungeon.TombDungeonPieces
import chylex.hee.game.world.feature.tombdungeon.connection.TombDungeonConnection import chylex.hee.game.world.feature.tombdungeon.connection.TombDungeonConnection
import chylex.hee.game.world.feature.tombdungeon.connection.TombDungeonConnectionType.TOMB_ENTRANCE_INSIDE import chylex.hee.game.world.feature.tombdungeon.connection.TombDungeonConnectionType.TOMB_ENTRANCE_INSIDE
import chylex.hee.game.world.feature.tombdungeon.piece.TombDungeonRoom_Tomb.UndreadSpawnerTrigger import chylex.hee.game.world.feature.tombdungeon.piece.TombDungeonRoom_Tomb.MobSpawnerTrigger
import chylex.hee.game.world.generation.IBlockPicker.Single import chylex.hee.game.world.generation.IBlockPicker.Single
import chylex.hee.game.world.generation.IBlockPicker.Single.Air import chylex.hee.game.world.generation.IBlockPicker.Single.Air
import chylex.hee.game.world.math.Size import chylex.hee.game.world.math.Size
@@ -41,12 +42,6 @@ class TombDungeonRoom_Tomb_Mass(width: Int, depth: Int, private val border: Bool
val maxY = size.maxY val maxY = size.maxY
val maxZ = size.maxZ val maxZ = size.maxZ
if (rand.nextInt(3) != 0 && level != null) {
val area = (size.x - 2) * (size.z - 2)
val (undreads, spiderlings) = level.pickUndreadAndSpiderlingSpawns(rand, if (area <= 30) MobAmount.LOW else MobAmount.MEDIUM)
UndreadSpawnerTrigger.place(world, entrance = connections.first().offset, width = maxX, depth = maxZ, undreads, spiderlings)
}
val distance = if (border) 2 else 1 val distance = if (border) 2 else 1
val palette = if (isFancy) TombDungeonPieces.PALETTE_ENTRY_FANCY_GRAVE else TombDungeonPieces.PALETTE_ENTRY_PLAIN_GRAVE val palette = if (isFancy) TombDungeonPieces.PALETTE_ENTRY_FANCY_GRAVE else TombDungeonPieces.PALETTE_ENTRY_PLAIN_GRAVE
@@ -66,8 +61,21 @@ class TombDungeonRoom_Tomb_Mass(width: Int, depth: Int, private val border: Bool
if (rand.nextInt(6) == 0 && (border || split)) { if (rand.nextInt(6) == 0 && (border || split)) {
placeJars(world, instance, listOf(Pos(centerX, 2, 1))) placeJars(world, instance, listOf(Pos(centerX, 2, 1)))
if (level != null && rand.nextInt(9) != 0) {
placeSpawnerTrigger(world, level)
}
}
else if (level != null && rand.nextInt(3) != 0) {
placeSpawnerTrigger(world, level)
} }
placeCobwebs(world, instance) placeCobwebs(world, instance)
} }
private fun placeSpawnerTrigger(world: IStructureWorld, level: TombDungeonLevel) {
val area = (size.x - 2) * (size.z - 2)
val (undreads, spiderlings) = level.pickUndreadAndSpiderlingSpawns(world.rand, if (area <= 30) MobAmount.LOW else MobAmount.MEDIUM)
MobSpawnerTrigger.place(world, entrance = connections.first().offset, width = size.maxX, depth = size.maxZ, undreads, spiderlings)
}
} }

View File

@@ -6,11 +6,9 @@ import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount
import chylex.hee.game.world.structure.IStructureWorld import chylex.hee.game.world.structure.IStructureWorld
import chylex.hee.system.migration.Facing.NORTH import chylex.hee.system.migration.Facing.NORTH
import chylex.hee.system.random.nextInt import chylex.hee.system.random.nextInt
import java.util.Random
class TombDungeonRoom_Tomb_MassSpacious(file: String, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb(file, entranceY, allowSecrets = false, isFancy) { class TombDungeonRoom_Tomb_MassSpacious(file: String, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb(file, entranceY, allowSecrets = false, isFancy) {
override val mobAmount
get() = MobAmount.MEDIUM
override fun generate(world: IStructureWorld, instance: Instance) { override fun generate(world: IStructureWorld, instance: Instance) {
super.generate(world, instance) super.generate(world, instance)
@@ -36,4 +34,8 @@ class TombDungeonRoom_Tomb_MassSpacious(file: String, entranceY: Int, isFancy: B
placeJars(world, instance, listOf(Pos(jarX, 3, maxZ - 2))) placeJars(world, instance, listOf(Pos(jarX, 3, maxZ - 2)))
} }
} }
override fun getSpawnerTriggerMobAmount(rand: Random, level: TombDungeonLevel): MobAmount? {
return MobAmount.HIGH.takeIf { rand.nextInt(11) < (if (level <= TombDungeonLevel.SECOND) 7 else 4) }
}
} }

View File

@@ -2,21 +2,16 @@ package chylex.hee.game.world.feature.tombdungeon.piece
import chylex.hee.game.block.BlockGraveDirt import chylex.hee.game.block.BlockGraveDirt
import chylex.hee.game.world.Pos import chylex.hee.game.world.Pos
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount
import chylex.hee.game.world.structure.IStructureWorld import chylex.hee.game.world.structure.IStructureWorld
import chylex.hee.system.migration.Facing.EAST import chylex.hee.system.migration.Facing.EAST
import chylex.hee.system.migration.Facing.WEST import chylex.hee.system.migration.Facing.WEST
import chylex.hee.system.random.nextInt import chylex.hee.system.random.nextInt
import chylex.hee.system.random.nextRounded import chylex.hee.system.random.nextRounded
import java.util.Random
class TombDungeonRoom_Tomb_MultiDeep(file: String, private val tombsPerColumn: Int, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb(file, entranceY, allowSecrets = false, isFancy) { class TombDungeonRoom_Tomb_MultiDeep(file: String, private val tombsPerColumn: Int, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb(file, entranceY, allowSecrets = false, isFancy) {
override val mobAmount
get() = when {
tombsPerColumn <= 5 -> MobAmount.LOW
tombsPerColumn <= 7 -> MobAmount.MEDIUM
else -> MobAmount.HIGH
}
override fun generate(world: IStructureWorld, instance: Instance) { override fun generate(world: IStructureWorld, instance: Instance) {
super.generate(world, instance) super.generate(world, instance)
@@ -45,4 +40,15 @@ class TombDungeonRoom_Tomb_MultiDeep(file: String, private val tombsPerColumn: I
}) })
} }
} }
override fun getSpawnerTriggerMobAmount(rand: Random, level: TombDungeonLevel): MobAmount? {
if (rand.nextBoolean()) {
return null
}
return when {
tombsPerColumn <= 6 -> MobAmount.MEDIUM
else -> MobAmount.HIGH
}
}
} }

View File

@@ -1,17 +1,12 @@
package chylex.hee.game.world.feature.tombdungeon.piece package chylex.hee.game.world.feature.tombdungeon.piece
import chylex.hee.game.world.Pos import chylex.hee.game.world.Pos
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount
import chylex.hee.game.world.structure.IStructureWorld import chylex.hee.game.world.structure.IStructureWorld
import java.util.Random
class TombDungeonRoom_Tomb_MultiNarrow(file: String, private val tombsPerColumn: Int, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb(file, entranceY, allowSecrets = false, isFancy) { class TombDungeonRoom_Tomb_MultiNarrow(file: String, private val tombsPerColumn: Int, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb(file, entranceY, allowSecrets = false, isFancy) {
override val mobAmount
get() = when {
tombsPerColumn <= 5 -> MobAmount.LOW
tombsPerColumn <= 7 -> MobAmount.MEDIUM
else -> MobAmount.HIGH
}
override fun generate(world: IStructureWorld, instance: Instance) { override fun generate(world: IStructureWorld, instance: Instance) {
super.generate(world, instance) super.generate(world, instance)
@@ -26,4 +21,16 @@ class TombDungeonRoom_Tomb_MultiNarrow(file: String, private val tombsPerColumn:
}) })
} }
} }
override fun getSpawnerTriggerMobAmount(rand: Random, level: TombDungeonLevel): MobAmount? {
if (rand.nextInt(10) >= if (level.isFancy) 3 else 5) {
return null
}
return when {
tombsPerColumn <= 4 -> MobAmount.LOW
tombsPerColumn <= 6 -> MobAmount.MEDIUM
else -> MobAmount.HIGH
}
}
} }

View File

@@ -2,21 +2,16 @@ package chylex.hee.game.world.feature.tombdungeon.piece
import chylex.hee.game.block.BlockGraveDirt import chylex.hee.game.block.BlockGraveDirt
import chylex.hee.game.world.Pos import chylex.hee.game.world.Pos
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount
import chylex.hee.game.world.structure.IStructureWorld import chylex.hee.game.world.structure.IStructureWorld
import chylex.hee.system.migration.Facing.EAST import chylex.hee.system.migration.Facing.EAST
import chylex.hee.system.migration.Facing.WEST import chylex.hee.system.migration.Facing.WEST
import chylex.hee.system.random.nextInt import chylex.hee.system.random.nextInt
import chylex.hee.system.random.nextRounded import chylex.hee.system.random.nextRounded
import java.util.Random
class TombDungeonRoom_Tomb_MultiSpacious(file: String, private val tombsPerColumn: Int, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb(file, entranceY, allowSecrets = false, isFancy) { class TombDungeonRoom_Tomb_MultiSpacious(file: String, private val tombsPerColumn: Int, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb(file, entranceY, allowSecrets = false, isFancy) {
override val mobAmount
get() = when {
tombsPerColumn <= 5 -> MobAmount.LOW
tombsPerColumn <= 7 -> MobAmount.MEDIUM
else -> MobAmount.HIGH
}
override fun generate(world: IStructureWorld, instance: Instance) { override fun generate(world: IStructureWorld, instance: Instance) {
super.generate(world, instance) super.generate(world, instance)
@@ -45,4 +40,15 @@ class TombDungeonRoom_Tomb_MultiSpacious(file: String, private val tombsPerColum
}) })
} }
} }
override fun getSpawnerTriggerMobAmount(rand: Random, level: TombDungeonLevel): MobAmount? {
if (rand.nextInt(10) >= 6) {
return null
}
return when {
tombsPerColumn <= 6 -> MobAmount.MEDIUM
else -> MobAmount.HIGH
}
}
} }

View File

@@ -0,0 +1,26 @@
package chylex.hee.game.world.feature.tombdungeon.piece
import chylex.hee.game.world.Pos
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount
import chylex.hee.game.world.structure.IStructureWorld
import chylex.hee.system.migration.Facing.SOUTH
import java.util.Random
abstract class TombDungeonRoom_Tomb_Single(file: String, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb(file, entranceY, allowSecrets = false, isFancy) {
override fun generate(world: IStructureWorld, instance: Instance) {
super.generate(world, instance)
if (world.rand.nextInt(10) < 3) {
placeChest(world, instance, Pos(centerX, 1, maxZ - 4), SOUTH)
}
}
final override fun getSpawnerTriggerMobAmount(rand: Random, level: TombDungeonLevel): MobAmount? {
return null
}
protected fun placeSingleTombUndreadSpawner(world: IStructureWorld) {
MobSpawnerTrigger.place(world, entrance = connections.first().offset, width = maxX, depth = maxZ, undreads = 1, spiderlings = 0)
}
}

View File

@@ -1,19 +1,13 @@
package chylex.hee.game.world.feature.tombdungeon.piece package chylex.hee.game.world.feature.tombdungeon.piece
import chylex.hee.game.world.Pos
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount
import chylex.hee.game.world.structure.IStructureWorld import chylex.hee.game.world.structure.IStructureWorld
import chylex.hee.system.migration.Facing.SOUTH
open class TombDungeonRoom_Tomb_SingleNarrow(file: String, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb(file, entranceY, allowSecrets = false, isFancy) { class TombDungeonRoom_Tomb_SingleNarrow(file: String, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb_Single(file, entranceY, isFancy) {
override val mobAmount: MobAmount?
get() = null
override fun generate(world: IStructureWorld, instance: Instance) { override fun generate(world: IStructureWorld, instance: Instance) {
super.generate(world, instance) super.generate(world, instance)
if (world.rand.nextInt(10) < 3) { if (world.rand.nextInt(5) == 0) {
placeChest(world, instance, Pos(centerX, 1, maxZ - 4), SOUTH) placeSingleTombUndreadSpawner(world)
} }
} }
} }

View File

@@ -1,13 +1,9 @@
package chylex.hee.game.world.feature.tombdungeon.piece package chylex.hee.game.world.feature.tombdungeon.piece
import chylex.hee.game.world.Pos import chylex.hee.game.world.Pos
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount
import chylex.hee.game.world.structure.IStructureWorld import chylex.hee.game.world.structure.IStructureWorld
class TombDungeonRoom_Tomb_SingleSpacious(file: String, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb_SingleNarrow(file, entranceY, isFancy) { class TombDungeonRoom_Tomb_SingleSpacious(file: String, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb_Single(file, entranceY, isFancy) {
override val mobAmount: MobAmount?
get() = null
override fun generate(world: IStructureWorld, instance: Instance) { override fun generate(world: IStructureWorld, instance: Instance) {
super.generate(world, instance) super.generate(world, instance)
@@ -18,6 +14,11 @@ class TombDungeonRoom_Tomb_SingleSpacious(file: String, entranceY: Int, isFancy:
Pos(centerX - 2, 4, if (rand.nextBoolean()) maxZ - 3 else maxZ - 4), Pos(centerX - 2, 4, if (rand.nextBoolean()) maxZ - 3 else maxZ - 4),
Pos(centerX + 2, 4, if (rand.nextBoolean()) maxZ - 3 else maxZ - 4), Pos(centerX + 2, 4, if (rand.nextBoolean()) maxZ - 3 else maxZ - 4),
)) ))
placeSingleTombUndreadSpawner(world)
}
else if (rand.nextInt(10) < 4) {
placeSingleTombUndreadSpawner(world)
} }
} }
} }

View File

@@ -28,6 +28,7 @@ import chylex.hee.game.item.ItemTableLink
import chylex.hee.game.mechanics.scorching.ScorchingHelper import chylex.hee.game.mechanics.scorching.ScorchingHelper
import chylex.hee.game.mechanics.table.TableParticleHandler import chylex.hee.game.mechanics.table.TableParticleHandler
import chylex.hee.game.potion.PotionBanishment import chylex.hee.game.potion.PotionBanishment
import chylex.hee.game.world.feature.tombdungeon.piece.TombDungeonRoom_Tomb
import chylex.hee.network.BaseClientPacket import chylex.hee.network.BaseClientPacket
import chylex.hee.network.fx.IFxData import chylex.hee.network.fx.IFxData
import chylex.hee.network.fx.IFxHandler import chylex.hee.network.fx.IFxHandler
@@ -79,7 +80,9 @@ class PacketClientFX<T : IFxData>() : BaseClientPacket() {
EnderEyeSpawnerParticles.FX_PARTICLE, EnderEyeSpawnerParticles.FX_PARTICLE,
EndermanTeleportHandler.FX_TELEPORT_FAIL, EndermanTeleportHandler.FX_TELEPORT_FAIL,
EndermanTeleportHandler.FX_TELEPORT_OUT_OF_WORLD, EndermanTeleportHandler.FX_TELEPORT_OUT_OF_WORLD,
PotionBanishment.FX_BANISH PotionBanishment.FX_BANISH,
TombDungeonRoom_Tomb.MobSpawnerTrigger.FX_SPAWN_UNDREAD,
TombDungeonRoom_Tomb.MobSpawnerTrigger.FX_SPAWN_SPIDERLING,
) )
} }

View File

@@ -0,0 +1,18 @@
package chylex.hee.game.item
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.system.component.EntityComponents
import net.minecraft.item.Item
import net.minecraft.item.ItemUseContext
import net.minecraft.util.ActionResultType
import net.minecraft.util.ActionResultType.FAIL
import net.minecraft.util.ActionResultType.PASS
open class ItemWithComponents(properties: Properties) : Item(properties) {
val components = EntityComponents()
final override fun onItemUse(context: ItemUseContext): ActionResultType {
val player = context.player ?: return FAIL
return components.handle<UseOnBlockComponent, ActionResultType> { useOnBlock(context.world, context.pos, player, context.item, context) } ?: PASS
}
}

View File

@@ -0,0 +1,12 @@
package chylex.hee.game.item.components
import chylex.hee.system.migration.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUseContext
import net.minecraft.util.ActionResultType
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
interface UseOnBlockComponent { // TODO use as objects instead of inheriting the interface on Item
fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType?
}

View File

@@ -10,24 +10,6 @@ class RandomBiasedValueRange(range: ClosedFloatingPointRange<Float>, private val
require(highestChanceValue in min..max) { "highestChanceValue must be between min and max" } require(highestChanceValue in min..max) { "highestChanceValue must be between min and max" }
} }
/*
import java.util.Random
import chylex.hee.system.random.nextBiasedFloat
import kotlin.math.roundToInt
val rand = Random()
(1..100000).map {
val min = 3F
val max = 10F
val highestChanceValue = 6.5F
val biasSoftener = 3F
(highestChanceValue + (rand.nextBiasedFloat(biasSoftener) * (0.5F + max - highestChanceValue)) - (rand.nextBiasedFloat(biasSoftener) * (0.5F + highestChanceValue - min))).roundToInt()
}.groupBy { it }.mapValues { it.value.size }.toList().sortedBy { it.first }
*/
override fun generateInt(rand: Random): Int { override fun generateInt(rand: Random): Int {
return (highestChanceValue + (rand.nextBiasedFloat(biasSoftener) * (0.5F + max - highestChanceValue)) - (rand.nextBiasedFloat(biasSoftener) * (0.5F + highestChanceValue - min))).roundToInt() return (highestChanceValue + (rand.nextBiasedFloat(biasSoftener) * (0.5F + max - highestChanceValue)) - (rand.nextBiasedFloat(biasSoftener) * (0.5F + highestChanceValue - min))).roundToInt()
} }

View File

@@ -0,0 +1,12 @@
package chylex.hee.network.fx
import chylex.hee.system.serialization.use
import chylex.hee.system.serialization.writeVec
import net.minecraft.network.PacketBuffer
import net.minecraft.util.math.Vec3d
class FxVecData(private val vec: Vec3d) : IFxData {
override fun write(buffer: PacketBuffer) = buffer.use {
writeVec(vec)
}
}

View File

@@ -0,0 +1,16 @@
package chylex.hee.network.fx
import chylex.hee.system.serialization.readVec
import chylex.hee.system.serialization.use
import net.minecraft.network.PacketBuffer
import net.minecraft.util.math.Vec3d
import net.minecraft.world.World
import java.util.Random
abstract class FxVecHandler : IFxHandler<FxVecData> {
override fun handle(buffer: PacketBuffer, world: World, rand: Random) = buffer.use {
handle(world, rand, readVec())
}
abstract fun handle(world: World, rand: Random, vec: Vec3d)
}

View File

@@ -0,0 +1,8 @@
package chylex.hee.system.component
abstract class AbstractAwareComponent {
var entityComponents: EntityComponents? = null
open fun onComponentAttached() {}
open fun onComponentDetached() {}
}

View File

@@ -0,0 +1,56 @@
package chylex.hee.system.component
class EntityComponents {
private val mutableComponents = mutableListOf<Any>()
val components: List<Any>
get() = mutableComponents
fun attach(component: Any) {
require(!mutableComponents.contains(component)) { "[EntityComponents] component must not be registered twice" }
mutableComponents.add(component)
if (component is AbstractAwareComponent) {
require(component.entityComponents === null) { "[EntityComponents] component must not be registered in two entities" }
component.entityComponents = this
component.onComponentAttached()
}
}
fun detach(component: Any) {
if (!mutableComponents.remove(component)) {
return
}
if (component is AbstractAwareComponent) {
require(component.entityComponents === this) { "[EntityComponents] component was not registered correctly" }
component.onComponentDetached()
component.entityComponents = null
}
}
inline fun <reified T> on(f: T.() -> Unit) {
for(component in components) {
if (component is T) {
f(component)
}
}
}
inline fun <reified T, U> handle(f: T.() -> U?): U? {
for(component in components) {
if (component is T) {
val result = f(component)
if (result != null) {
return result
}
}
}
return null
}
inline fun <reified T> list(): List<T> {
return components.filterIsInstance<T>()
}
}

View File

@@ -0,0 +1,20 @@
package chylex.hee.system.component.general
import chylex.hee.system.component.EntityComponents
import chylex.hee.system.serialization.TagCompound
import net.minecraftforge.common.util.INBTSerializable
interface SerializableComponent : INBTSerializable<TagCompound> {
val serializationKey: String
}
fun EntityComponents.serializeTo(tag: TagCompound) {
this.on<SerializableComponent> {
require(!tag.contains(serializationKey)) { "[SerializableComponent] cannot serialize duplicate key: $serializationKey" }
tag.put(serializationKey, serializeNBT())
}
}
fun EntityComponents.deserializeFrom(tag: TagCompound) {
this.on<SerializableComponent> { deserializeNBT(tag.getCompound(serializationKey)) }
}

View File

@@ -0,0 +1,19 @@
package chylex.hee.system.component.general
import chylex.hee.system.component.EntityComponents
import net.minecraft.entity.Entity
interface TickableComponent {
@JvmDefault fun tickClient() {}
@JvmDefault fun tickServer() {}
}
@JvmName("tickEntity")
fun <T : Entity> EntityComponents.tick(entity: T) {
if (entity.world.isRemote) {
this.on(TickableComponent::tickClient)
}
else {
this.on(TickableComponent::tickServer)
}
}

View File

@@ -0,0 +1,28 @@
package chylex.hee.test.main
import chylex.hee.game.loot.rng.RandomBiasedValueRange
import java.util.Random
import kotlin.math.roundToInt
fun main() {
val min = 3F
val max = 10F
val highestChanceValue = 6.5F
val biasSoftener = 3F
val rand = Random()
val generator = RandomBiasedValueRange(min..max, highestChanceValue, biasSoftener)
val reps = 100000
val results = (1..reps).map { generator.generateInt(rand) }
.groupBy { it }
.mapValues { it.value.size }
.toList()
.sortedBy { it.first }
val pad1 = results.maxOf { it.first.toString().length }
val pad2 = results.maxOf { it.second.toString().length }
println(results.joinToString("\n") {
"${it.first.toString().padStart(pad1)} | ${it.second.toString().padStart(pad2)} | ${((it.second * 100.0) / reps).roundToInt().toString().padStart(2)} %"
})
}

View File

@@ -0,0 +1,35 @@
package chylex.hee.test.main
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount
import java.util.Locale.ROOT
import java.util.Random
import kotlin.math.roundToInt
fun main() {
val rand = Random()
for(level in TombDungeonLevel.values()) {
val reps = 100000
println()
println("== ${level.name} ${"=".repeat(24 - level.name.length)}")
for(amount in MobAmount.values()) {
println()
println(" ${amount.name}")
println()
val results = (1..reps)
.map { level.pickUndreadAndSpiderlingSpawns(rand, amount) }
.groupingBy { it }
.eachCount()
.entries
.map { ((it.value * 100.0) / reps).roundToInt() to it.key }
.sortedWith(compareBy({ -it.first }, { -it.second.first }, { -it.second.second }))
println(results.joinToString("\n") { " U = ${it.second.first} S = ${it.second.second} ${it.first.toString().padStart(2)} %" })
println(" U ~ ${"%.1f".format(ROOT, results.sumBy { it.second.first * it.first } * 0.01)} S ~ ${"%.1f".format(ROOT, results.sumBy { it.second.second * it.first } * 0.01)}")
}
}
}

View File

@@ -1,4 +1,4 @@
package chylex.hee.test.mechanics.damage package chylex.hee.test.unit.mechanics.damage
import chylex.hee.game.mechanics.damage.DamageProperties import chylex.hee.game.mechanics.damage.DamageProperties
import chylex.hee.game.mechanics.damage.DamageType import chylex.hee.game.mechanics.damage.DamageType

View File

@@ -1,4 +1,4 @@
package chylex.hee.test.mechanics.energy package chylex.hee.test.unit.mechanics.energy
import chylex.hee.game.mechanics.energy.IEnergyQuantity.Floating import chylex.hee.game.mechanics.energy.IEnergyQuantity.Floating
import chylex.hee.game.mechanics.energy.IEnergyQuantity.Internal import chylex.hee.game.mechanics.energy.IEnergyQuantity.Internal

View File

@@ -1,4 +1,4 @@
package chylex.hee.test.system.util package chylex.hee.test.unit.system
import chylex.hee.game.world.Pos import chylex.hee.game.world.Pos
import chylex.hee.system.math.Vec import chylex.hee.system.math.Vec

View File

@@ -1,4 +1,4 @@
package chylex.hee.test.system.util package chylex.hee.test.unit.system
import chylex.hee.game.inventory.cleanupNBT import chylex.hee.game.inventory.cleanupNBT
import chylex.hee.game.inventory.heeTag import chylex.hee.game.inventory.heeTag