Merge branch 'mc1.20.1/feature-dev' into mc1.21.1/dev

This commit is contained in:
IThundxr 2025-02-23 21:05:45 -05:00
commit 052dc90bfe
Failed to generate hash of commit
97 changed files with 2050 additions and 1558 deletions

View file

@ -149,3 +149,6 @@ _Now using Flywheel 1.0_
- Synced AllPortalTracks with Create Fabric
- Implemented DyeHelper api (#7265)
- Implemented api to add custom block train conductors (#7030)
- Convert Potato Cannon project types into a dynamic registry
- Everything can be done with datapacks now, and there is no need to write a mod unless you need to add new
Render Modes, Entity Hit Actions or Block Hit Actions

View file

@ -1,4 +1,29 @@
// 1.21.1 2025-02-05T22:51:51.328399 Create's Generated Registry Entries
// 1.21.1 2025-02-23T21:05:27.700364514 Create's Generated Registry Entries
abb9dd2c98388abb430343d4ac02d460e5edc086 data/create/create/potato_projectile/type/apple.json
1a20cb4e64dc07918a28fbccc73102bca3560f16 data/create/create/potato_projectile/type/baked_potato.json
8450576952f7723d22250da6f554dd0fda4e9fce data/create/create/potato_projectile/type/beetroot.json
9d927ec9c8b76a093e7ff8ff8f81be3a438d4aba data/create/create/potato_projectile/type/blaze_cake.json
46ccaf468caaa4faaca4f1494f60e99cd00785c9 data/create/create/potato_projectile/type/cake.json
22e0f5befe5835c7a9a6448e17e73e6fb7d0fb9c data/create/create/potato_projectile/type/carrot.json
af17d72549ee9421d2643a215ffc2291874fff93 data/create/create/potato_projectile/type/chocolate_berry.json
8cb4811601d46db5fdc0291edce3ec2f3a64e902 data/create/create/potato_projectile/type/chorus_fruit.json
69138506c1b02aa4e2456cc1912ddb70f8a1e42a data/create/create/potato_projectile/type/enchanted_golden_apple.json
e3ab3c4bd70ad742d37091ae05774aadffb1d1d5 data/create/create/potato_projectile/type/fallback.json
98bf0ce51484c5a9709fc69d046d0c70d987cfdd data/create/create/potato_projectile/type/fish.json
afe4e7cc87110d6f045f6672fb312a09290ca04a data/create/create/potato_projectile/type/glistering_melon.json
050c9333d41efd2577e1e597c7c68b00436b0963 data/create/create/potato_projectile/type/glow_berry.json
52046463af1abc92c5257992c302d7ab26c63e28 data/create/create/potato_projectile/type/golden_apple.json
c6234751ccad5111857b0ae9e297e42f529ad32a data/create/create/potato_projectile/type/golden_carrot.json
583b75978a4f920c2969473e5353fcc89886b612 data/create/create/potato_projectile/type/honeyed_apple.json
7a269ded36d1397f86f23c4c431c7a99fea74446 data/create/create/potato_projectile/type/melon_block.json
352402ba2fff3f23af178d15d61b0ba0a151097a data/create/create/potato_projectile/type/melon_slice.json
cbfd3028ad878bddbdaeb0eec0cd5a1c50d4c901 data/create/create/potato_projectile/type/poison_potato.json
b58e779803d29d4b36ecf79fde4e918577c71748 data/create/create/potato_projectile/type/potato.json
3ba8dbd239452eb2531d8f13332a37bc1ffa3616 data/create/create/potato_projectile/type/pufferfish.json
0c099b5f1bd7ba3832ea2d29e8c1c22c83ed1c3d data/create/create/potato_projectile/type/pumpkin_block.json
7d58a0671c55e40cdb728c60152665c89209fb91 data/create/create/potato_projectile/type/pumpkin_pie.json
30bf0b35aeff136251d3bfe2af04fd89ccf953de data/create/create/potato_projectile/type/suspicious_stew.json
b4a7c10bd9cdcfe67df2a5766e5ec2e35a3f9b24 data/create/create/potato_projectile/type/sweet_berry.json
030ede1044384c4117ac1e491bf5c78bbd2842f5 data/create/damage_type/crush.json
92b0416950ffeb3ba68811e587177c2f8811c2c5 data/create/damage_type/cuckoo_surprise.json
d2a4fdb64f4ba817e13a7b20c73fd1ca34b825fc data/create/damage_type/fan_fire.json

View file

@ -0,0 +1,10 @@
{
"damage": 5,
"items": "minecraft:apple",
"knockback": 0.5,
"render_mode": {
"type": "create:tumble"
},
"sound_pitch": 1.1,
"velocity_multiplier": 1.45
}

View file

@ -0,0 +1,14 @@
{
"damage": 5,
"items": "minecraft:baked_potato",
"knockback": 0.5,
"pre_entity_hit": {
"type": "create:set_on_fire",
"ticks": 60
},
"reload_ticks": 15,
"render_mode": {
"type": "create:tumble"
},
"velocity_multiplier": 1.25
}

View file

@ -0,0 +1,13 @@
{
"damage": 2,
"items": "minecraft:beetroot",
"knockback": 0.1,
"reload_ticks": 5,
"render_mode": {
"type": "create:toward_motion",
"spin": 2.0,
"sprite_angle_offset": 140
},
"sound_pitch": 1.6,
"velocity_multiplier": 1.6
}

View file

@ -0,0 +1,15 @@
{
"damage": 15,
"items": "create:blaze_cake",
"knockback": 0.3,
"pre_entity_hit": {
"type": "create:set_on_fire",
"ticks": 240
},
"reload_ticks": 20,
"render_mode": {
"type": "create:tumble"
},
"sticky": true,
"velocity_multiplier": 1.1
}

View file

@ -0,0 +1,11 @@
{
"damage": 8,
"items": "minecraft:cake",
"knockback": 0.1,
"reload_ticks": 15,
"render_mode": {
"type": "create:tumble"
},
"sticky": true,
"velocity_multiplier": 1.1
}

View file

@ -0,0 +1,17 @@
{
"damage": 4,
"items": "minecraft:carrot",
"knockback": 0.3,
"on_entity_hit": {
"type": "create:plant_crop",
"block": "minecraft:carrots"
},
"reload_ticks": 12,
"render_mode": {
"type": "create:toward_motion",
"spin": 1.0,
"sprite_angle_offset": 140
},
"sound_pitch": 1.5,
"velocity_multiplier": 1.45
}

View file

@ -0,0 +1,11 @@
{
"damage": 4,
"items": "create:chocolate_glazed_berries",
"knockback": 0.2,
"render_mode": {
"type": "create:tumble"
},
"sound_pitch": 1.25,
"split": 3,
"velocity_multiplier": 1.05
}

View file

@ -0,0 +1,14 @@
{
"damage": 3,
"items": "minecraft:chorus_fruit",
"knockback": 0.05,
"on_entity_hit": {
"type": "create:chorus_teleport",
"teleport_diameter": 20.0
},
"reload_ticks": 15,
"render_mode": {
"type": "create:tumble"
},
"velocity_multiplier": 1.2
}

View file

@ -0,0 +1,67 @@
{
"items": "minecraft:enchanted_golden_apple",
"knockback": 0.05,
"on_entity_hit": {
"type": "create:food_effects",
"food_property": {
"can_always_eat": true,
"effects": [
{
"effect": {
"amplifier": 1,
"duration": 400,
"id": "minecraft:regeneration",
"neoforge:cures": [
"protected_by_totem",
"milk"
],
"show_icon": true
}
},
{
"effect": {
"duration": 6000,
"id": "minecraft:resistance",
"neoforge:cures": [
"protected_by_totem",
"milk"
],
"show_icon": true
}
},
{
"effect": {
"duration": 6000,
"id": "minecraft:fire_resistance",
"neoforge:cures": [
"protected_by_totem",
"milk"
],
"show_icon": true
}
},
{
"effect": {
"amplifier": 3,
"duration": 2400,
"id": "minecraft:absorption",
"neoforge:cures": [
"protected_by_totem",
"milk"
],
"show_icon": true
}
}
],
"nutrition": 4,
"saturation": 9.6
},
"recoverable": false
},
"reload_ticks": 100,
"render_mode": {
"type": "create:tumble"
},
"sound_pitch": 1.1,
"velocity_multiplier": 1.45
}

View file

@ -0,0 +1,4 @@
{
"damage": 0,
"items": []
}

View file

@ -0,0 +1,19 @@
{
"damage": 4,
"items": [
"minecraft:cod",
"minecraft:cooked_cod",
"minecraft:salmon",
"minecraft:cooked_salmon",
"minecraft:tropical_fish"
],
"knockback": 0.6,
"render_mode": {
"type": "create:toward_motion",
"spin": 1.0,
"sprite_angle_offset": 140
},
"sound_pitch": 1.3,
"sticky": true,
"velocity_multiplier": 1.3
}

View file

@ -0,0 +1,18 @@
{
"damage": 5,
"items": "minecraft:glistering_melon_slice",
"knockback": 0.1,
"on_entity_hit": {
"type": "create:potion_effect",
"effect": "minecraft:glowing",
"level": 1,
"recoverable": true,
"ticks": 100
},
"reload_ticks": 8,
"render_mode": {
"type": "create:tumble"
},
"sound_pitch": 1.5,
"velocity_multiplier": 1.45
}

View file

@ -0,0 +1,18 @@
{
"damage": 2,
"items": "minecraft:glow_berries",
"knockback": 0.05,
"on_entity_hit": {
"type": "create:potion_effect",
"effect": "minecraft:glowing",
"level": 1,
"recoverable": false,
"ticks": 200
},
"render_mode": {
"type": "create:tumble"
},
"sound_pitch": 1.2,
"split": 2,
"velocity_multiplier": 1.05
}

View file

@ -0,0 +1,13 @@
{
"items": "minecraft:golden_apple",
"knockback": 0.05,
"on_entity_hit": {
"type": "create:cure_zombie_villager"
},
"reload_ticks": 100,
"render_mode": {
"type": "create:tumble"
},
"sound_pitch": 1.1,
"velocity_multiplier": 1.45
}

View file

@ -0,0 +1,13 @@
{
"damage": 12,
"items": "minecraft:golden_carrot",
"knockback": 0.5,
"reload_ticks": 15,
"render_mode": {
"type": "create:toward_motion",
"spin": 2.0,
"sprite_angle_offset": 140
},
"sound_pitch": 1.5,
"velocity_multiplier": 1.45
}

View file

@ -0,0 +1,18 @@
{
"damage": 6,
"items": "create:honeyed_apple",
"knockback": 0.1,
"on_entity_hit": {
"type": "create:potion_effect",
"effect": "minecraft:slowness",
"level": 2,
"recoverable": true,
"ticks": 160
},
"reload_ticks": 15,
"render_mode": {
"type": "create:tumble"
},
"sound_pitch": 1.1,
"velocity_multiplier": 1.35
}

View file

@ -0,0 +1,15 @@
{
"damage": 8,
"items": "minecraft:melon",
"knockback": 2.0,
"on_entity_hit": {
"type": "create:place_block_on_ground",
"block": "minecraft:melon"
},
"reload_ticks": 20,
"render_mode": {
"type": "create:tumble"
},
"sound_pitch": 0.9,
"velocity_multiplier": 0.95
}

View file

@ -0,0 +1,11 @@
{
"damage": 3,
"items": "minecraft:melon_slice",
"knockback": 0.1,
"reload_ticks": 8,
"render_mode": {
"type": "create:tumble"
},
"sound_pitch": 1.5,
"velocity_multiplier": 1.45
}

View file

@ -0,0 +1,17 @@
{
"damage": 5,
"items": "minecraft:poisonous_potato",
"knockback": 0.05,
"on_entity_hit": {
"type": "create:potion_effect",
"effect": "minecraft:poison",
"level": 1,
"recoverable": true,
"ticks": 160
},
"reload_ticks": 15,
"render_mode": {
"type": "create:tumble"
},
"velocity_multiplier": 1.25
}

View file

@ -0,0 +1,14 @@
{
"damage": 5,
"items": "minecraft:potato",
"knockback": 1.5,
"on_entity_hit": {
"type": "create:plant_crop",
"block": "minecraft:potatoes"
},
"reload_ticks": 15,
"render_mode": {
"type": "create:tumble"
},
"velocity_multiplier": 1.25
}

View file

@ -0,0 +1,59 @@
{
"damage": 4,
"items": "minecraft:pufferfish",
"knockback": 0.4,
"on_entity_hit": {
"type": "create:food_effects",
"food_property": {
"effects": [
{
"effect": {
"amplifier": 1,
"duration": 1200,
"id": "minecraft:poison",
"neoforge:cures": [
"protected_by_totem",
"milk",
"honey"
],
"show_icon": true
}
},
{
"effect": {
"amplifier": 2,
"duration": 300,
"id": "minecraft:hunger",
"neoforge:cures": [
"protected_by_totem",
"milk"
],
"show_icon": true
}
},
{
"effect": {
"duration": 300,
"id": "minecraft:nausea",
"neoforge:cures": [
"protected_by_totem",
"milk"
],
"show_icon": true
}
}
],
"nutrition": 1,
"saturation": 0.2
},
"recoverable": false
},
"render_mode": {
"type": "create:toward_motion",
"spin": 1.0,
"sprite_angle_offset": 140
},
"sound_pitch": 1.1,
"sticky": true,
"velocity_multiplier": 1.1
}

View file

@ -0,0 +1,15 @@
{
"damage": 6,
"items": "minecraft:pumpkin",
"knockback": 2.0,
"on_entity_hit": {
"type": "create:place_block_on_ground",
"block": "minecraft:pumpkin"
},
"reload_ticks": 15,
"render_mode": {
"type": "create:tumble"
},
"sound_pitch": 0.9,
"velocity_multiplier": 0.95
}

View file

@ -0,0 +1,12 @@
{
"damage": 7,
"items": "minecraft:pumpkin_pie",
"knockback": 0.05,
"reload_ticks": 15,
"render_mode": {
"type": "create:tumble"
},
"sound_pitch": 1.1,
"sticky": true,
"velocity_multiplier": 1.1
}

View file

@ -0,0 +1,19 @@
{
"damage": 3,
"drop_stack": {
"count": 1,
"id": "minecraft:bowl"
},
"items": "minecraft:suspicious_stew",
"knockback": 0.2,
"on_entity_hit": {
"type": "create:suspicious_stew"
},
"reload_ticks": 40,
"render_mode": {
"type": "create:toward_motion",
"spin": 1.0,
"sprite_angle_offset": 140
},
"velocity_multiplier": 0.8
}

View file

@ -0,0 +1,11 @@
{
"damage": 3,
"items": "minecraft:sweet_berries",
"knockback": 0.1,
"render_mode": {
"type": "create:tumble"
},
"sound_pitch": 1.25,
"split": 3,
"velocity_multiplier": 1.05
}

View file

@ -19,6 +19,7 @@ import static com.simibubi.create.foundation.data.TagGen.tagBlockAndItem;
import com.simibubi.create.AllTags.AllBlockTags;
import com.simibubi.create.AllTags.AllItemTags;
import com.simibubi.create.api.behaviour.interaction.ConductorBlockInteractionBehavior;
import com.simibubi.create.api.stress.BlockStressValues;
import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsBlock;
import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovement;
import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovingInteraction;
@ -110,7 +111,6 @@ import com.simibubi.create.content.fluids.tank.FluidTankGenerator;
import com.simibubi.create.content.fluids.tank.FluidTankItem;
import com.simibubi.create.content.fluids.tank.FluidTankModel;
import com.simibubi.create.content.fluids.tank.FluidTankMovementBehavior;
import com.simibubi.create.content.kinetics.BlockStressDefaults;
import com.simibubi.create.content.kinetics.belt.BeltBlock;
import com.simibubi.create.content.kinetics.belt.BeltGenerator;
import com.simibubi.create.content.kinetics.belt.BeltModel;
@ -272,6 +272,7 @@ import com.simibubi.create.foundation.item.UncontainableBlockItem;
import com.simibubi.create.foundation.mixin.accessor.BlockLootSubProviderAccessor;
import com.simibubi.create.foundation.utility.ColorHandlers;
import com.simibubi.create.foundation.utility.DyeHelper;
import com.simibubi.create.infrastructure.config.CStress;
import com.tterrag.registrate.providers.RegistrateRecipeProvider;
import com.tterrag.registrate.util.DataIngredient;
import com.tterrag.registrate.util.entry.BlockEntry;
@ -367,7 +368,7 @@ public class AllBlocks {
public static final BlockEntry<ShaftBlock> SHAFT = REGISTRATE.block("shaft", ShaftBlock::new)
.initialProperties(SharedProperties::stone)
.properties(p -> p.mapColor(MapColor.METAL).forceSolidOff())
.transform(BlockStressDefaults.setNoImpact())
.transform(CStress.setNoImpact())
.transform(pickaxeOnly())
.blockstate(BlockStateGen.axisBlockProvider(false))
.onRegister(CreateRegistrate.blockModel(() -> BracketedKineticBlockModel::new))
@ -378,7 +379,7 @@ public class AllBlocks {
.initialProperties(SharedProperties::stone)
.properties(p -> p.sound(SoundType.WOOD)
.mapColor(MapColor.DIRT))
.transform(BlockStressDefaults.setNoImpact())
.transform(CStress.setNoImpact())
.transform(axeOrPickaxe())
.blockstate(BlockStateGen.axisBlockProvider(false))
.onRegister(CreateRegistrate.blockModel(() -> BracketedKineticBlockModel::new))
@ -392,7 +393,7 @@ public class AllBlocks {
.properties(p -> p.sound(SoundType.WOOD)
.mapColor(MapColor.DIRT))
.transform(axeOrPickaxe())
.transform(BlockStressDefaults.setNoImpact())
.transform(CStress.setNoImpact())
.blockstate(BlockStateGen.axisBlockProvider(false))
.onRegister(CreateRegistrate.blockModel(() -> BracketedKineticBlockModel::new))
.item(CogwheelBlockItem::new)
@ -458,7 +459,7 @@ public class AllBlocks {
.initialProperties(SharedProperties::stone)
.properties(p -> p.noOcclusion()
.mapColor(MapColor.PODZOL))
.transform(BlockStressDefaults.setNoImpact())
.transform(CStress.setNoImpact())
.transform(axeOrPickaxe())
.onRegister(CreateRegistrate.connectedTextures(() -> new EncasedCTBehaviour(AllSpriteShifts.ANDESITE_CASING)))
.onRegister(CreateRegistrate.casingConnectivity((block, cc) -> cc.make(block, AllSpriteShifts.ANDESITE_CASING,
@ -473,7 +474,7 @@ public class AllBlocks {
.properties(p -> p.noOcclusion()
.mapColor(MapColor.PODZOL))
.addLayer(() -> RenderType::cutoutMipped)
.transform(BlockStressDefaults.setNoImpact())
.transform(CStress.setNoImpact())
.transform(axeOrPickaxe())
.blockstate((c, p) -> BlockStateGen.axisBlock(c, p, AssetLookup.forPowered(c, p)))
.item()
@ -485,7 +486,7 @@ public class AllBlocks {
.properties(p -> p.noOcclusion()
.mapColor(MapColor.PODZOL))
.addLayer(() -> RenderType::cutoutMipped)
.transform(BlockStressDefaults.setNoImpact())
.transform(CStress.setNoImpact())
.transform(axeOrPickaxe())
.blockstate((c, p) -> BlockStateGen.axisBlock(c, p, AssetLookup.forPowered(c, p)))
.item()
@ -497,7 +498,7 @@ public class AllBlocks {
.initialProperties(SharedProperties::stone)
.properties(p -> p.noOcclusion()
.mapColor(MapColor.PODZOL))
.transform(BlockStressDefaults.setNoImpact())
.transform(CStress.setNoImpact())
.transform(axeOrPickaxe())
.blockstate((c, p) -> new ChainDriveGenerator((state, suffix) -> p.models()
.getExistingFile(p.modLoc("block/" + c.getName() + "/" + suffix))).generate(c, p))
@ -510,7 +511,7 @@ public class AllBlocks {
.initialProperties(SharedProperties::stone)
.properties(p -> p.noOcclusion()
.mapColor(MapColor.NETHER))
.transform(BlockStressDefaults.setNoImpact())
.transform(CStress.setNoImpact())
.transform(axeOrPickaxe())
.blockstate((c, p) -> new ChainDriveGenerator((state, suffix) -> {
String powered = state.getValue(ChainGearshiftBlock.POWERED) ? "_powered" : "";
@ -532,7 +533,7 @@ public class AllBlocks {
.addLayer(() -> RenderType::cutoutMipped)
.transform(axeOrPickaxe())
.blockstate(new BeltGenerator()::generate)
.transform(BlockStressDefaults.setImpact(0))
.transform(CStress.setNoImpact())
.transform(displaySource(AllDisplaySources.ITEM_NAMES))
.onRegister(CreateRegistrate.blockModel(() -> BeltModel::new))
.clientExtension(() -> () -> new BeltBlock.RenderProperties())
@ -544,7 +545,8 @@ public class AllBlocks {
.properties(p -> p.noOcclusion()
.mapColor(MapColor.PODZOL))
.transform(axeOrPickaxe())
.transform(BlockStressDefaults.setImpact(1))
.transform(CStress.setImpact(1))
.transform(CStress.setImpact(1))
.blockstate((c, p) -> p.simpleBlock(c.getEntry(), AssetLookup.partialBaseModel(c, p)))
.item()
.transform(customItemModel())
@ -558,8 +560,8 @@ public class AllBlocks {
.tag(AllBlockTags.SAFE_NBT.tag)
.transform(pickaxeOnly())
.blockstate(new CreativeMotorGenerator()::generate)
.transform(BlockStressDefaults.setCapacity(16384.0))
.transform(BlockStressDefaults.setGeneratorSpeed(() -> Couple.create(0, 256)))
.transform(CStress.setCapacity(16384.0))
.onRegister(BlockStressValues.setGeneratorSpeed(256, true))
.item()
.properties(p -> p.rarity(Rarity.EPIC))
.transform(customItemModel())
@ -573,8 +575,8 @@ public class AllBlocks {
.blockstate(
(c, p) -> BlockStateGen.directionalBlockIgnoresWaterlogged(c, p, s -> AssetLookup.partialBaseModel(c, p)))
.addLayer(() -> RenderType::cutoutMipped)
.transform(BlockStressDefaults.setCapacity(32.0))
.transform(BlockStressDefaults.setGeneratorSpeed(WaterWheelBlock::getSpeedRange))
.transform(CStress.setCapacity(32))
.onRegister(BlockStressValues.setGeneratorSpeed(8))
.item()
.transform(customItemModel())
.register();
@ -588,8 +590,8 @@ public class AllBlocks {
.blockstate((c, p) -> axisBlock(c, p,
s -> s.getValue(LargeWaterWheelBlock.EXTENSION) ? AssetLookup.partialBaseModel(c, p, "extension")
: AssetLookup.partialBaseModel(c, p)))
.transform(BlockStressDefaults.setCapacity(128.0))
.transform(BlockStressDefaults.setGeneratorSpeed(LargeWaterWheelBlock::getSpeedRange))
.transform(CStress.setCapacity(128.0))
.onRegister(BlockStressValues.setGeneratorSpeed(4))
.item(LargeWaterWheelBlockItem::new)
.transform(customItemModel())
.register();
@ -612,7 +614,7 @@ public class AllBlocks {
.blockstate(BlockStateGen.directionalBlockProvider(true))
.addLayer(() -> RenderType::cutoutMipped)
.transform(axeOrPickaxe())
.transform(BlockStressDefaults.setImpact(2.0))
.transform(CStress.setImpact(2.0))
.item()
.transform(customItemModel())
.register();
@ -633,7 +635,7 @@ public class AllBlocks {
.properties(p -> p.mapColor(MapColor.PODZOL))
.transform(axeOrPickaxe())
.blockstate((c, p) -> p.simpleBlock(c.getEntry(), AssetLookup.standardModel(c, p)))
.transform(BlockStressDefaults.setImpact(4.0))
.transform(CStress.setImpact(4.0))
.simpleItem()
.register();
@ -642,8 +644,8 @@ public class AllBlocks {
.properties(p -> p.mapColor(MapColor.PODZOL))
.transform(axeOrPickaxe())
.blockstate(BlockStateGen.directionalBlockProvider(true))
.transform(BlockStressDefaults.setCapacity(8.0))
.transform(BlockStressDefaults.setGeneratorSpeed(HandCrankBlock::getSpeedRange))
.transform(CStress.setCapacity(8.0))
.onRegister(BlockStressValues.setGeneratorSpeed(32))
.tag(AllBlockTags.BRITTLE.tag)
.onRegister(ItemUseOverrides::addBlock)
.item()
@ -673,7 +675,7 @@ public class AllBlocks {
.properties(p -> p.mapColor(MapColor.METAL))
.transform(pickaxeOnly())
.blockstate((c, p) -> p.simpleBlock(c.getEntry(), AssetLookup.partialBaseModel(c, p)))
.transform(BlockStressDefaults.setImpact(4.0))
.transform(CStress.setImpact(4.0))
.item()
.transform(customItemModel())
.register();
@ -686,7 +688,7 @@ public class AllBlocks {
.transform(pickaxeOnly())
.blockstate((c, p) -> BlockStateGen.axisBlock(c, p, s -> AssetLookup.partialBaseModel(c, p)))
.addLayer(() -> RenderType::cutoutMipped)
.transform(BlockStressDefaults.setImpact(8.0))
.transform(CStress.setImpact(8.0))
.item()
.transform(customItemModel())
.register();
@ -710,7 +712,7 @@ public class AllBlocks {
.mapColor(MapColor.PODZOL))
.transform(axeOrPickaxe())
.blockstate(BlockStateGen.horizontalBlockProvider(true))
.transform(BlockStressDefaults.setImpact(8.0))
.transform(CStress.setImpact(8.0))
.item(AssemblyOperatorBlockItem::new)
.transform(customItemModel())
.register();
@ -723,7 +725,7 @@ public class AllBlocks {
.transform(axeOrPickaxe())
.blockstate((c, p) -> p.simpleBlock(c.getEntry(), AssetLookup.partialBaseModel(c, p)))
.addLayer(() -> RenderType::cutoutMipped)
.transform(BlockStressDefaults.setImpact(4.0))
.transform(CStress.setImpact(4.0))
.item(AssemblyOperatorBlockItem::new)
.transform(customItemModel())
.register();
@ -797,7 +799,7 @@ public class AllBlocks {
.mapColor(MapColor.COLOR_GRAY))
.transform(axeOrPickaxe())
.blockstate((c, p) -> p.horizontalBlock(c.getEntry(), AssetLookup.partialBaseModel(c, p), 180))
.transform(BlockStressDefaults.setImpact(2.0))
.transform(CStress.setImpact(2.0))
.transform(displaySource(AllDisplaySources.ITEM_NAMES))
.item(EjectorItem::new)
.transform(customItemModel())
@ -837,7 +839,7 @@ public class AllBlocks {
.initialProperties(SharedProperties::wooden)
.properties(p -> p.mapColor(MapColor.PODZOL))
.transform(axeOrPickaxe())
.transform(BlockStressDefaults.setNoImpact())
.transform(CStress.setNoImpact())
.blockstate(new GaugeGenerator()::generate)
.transform(displaySource(AllDisplaySources.KINETIC_SPEED))
.item()
@ -848,7 +850,7 @@ public class AllBlocks {
.initialProperties(SharedProperties::wooden)
.properties(p -> p.mapColor(MapColor.PODZOL))
.transform(axeOrPickaxe())
.transform(BlockStressDefaults.setNoImpact())
.transform(CStress.setNoImpact())
.blockstate(new GaugeGenerator()::generate)
.transform(displaySource(AllDisplaySources.KINETIC_STRESS))
.item()
@ -929,7 +931,7 @@ public class AllBlocks {
.transform(pickaxeOnly())
.blockstate(BlockStateGen.directionalBlockProviderIgnoresWaterlogged(true))
.onRegister(CreateRegistrate.blockModel(() -> PipeAttachmentModel::withoutAO))
.transform(BlockStressDefaults.setImpact(4.0))
.transform(CStress.setImpact(4.0))
.item()
.transform(customItemModel())
.register();
@ -961,7 +963,7 @@ public class AllBlocks {
REGISTRATE.block("copper_valve_handle", ValveHandleBlock::copper)
.transform(pickaxeOnly())
.transform(BuilderTransformers.valveHandle(null))
.transform(BlockStressDefaults.setCapacity(8.0))
.transform(CStress.setCapacity(8.0))
.register();
public static final DyedBlockList<ValveHandleBlock> DYED_VALVE_HANDLES = new DyedBlockList<>(colour -> {
@ -1022,7 +1024,7 @@ public class AllBlocks {
.addLayer(() -> RenderType::cutoutMipped)
.transform(pickaxeOnly())
.blockstate(BlockStateGen.horizontalBlockProvider(true))
.transform(BlockStressDefaults.setImpact(4.0))
.transform(CStress.setImpact(4.0))
.item()
.transform(customItemModel())
.register();
@ -1061,8 +1063,8 @@ public class AllBlocks {
.initialProperties(SharedProperties::copperMetal)
.transform(pickaxeOnly())
.blockstate((c, p) -> p.horizontalFaceBlock(c.get(), AssetLookup.partialBaseModel(c, p)))
.transform(BlockStressDefaults.setCapacity(1024.0))
.transform(BlockStressDefaults.setGeneratorSpeed(SteamEngineBlock::getSpeedRange))
.transform(CStress.setCapacity(1024.0))
.onRegister(BlockStressValues.setGeneratorSpeed(64, true))
.item()
.transform(customItemModel())
.register();
@ -1168,7 +1170,7 @@ public class AllBlocks {
existing.getLocation())
.texture("2", p.modLoc("block/" + c.getName() + powered + flipped));
}))
.transform(BlockStressDefaults.setNoImpact())
.transform(CStress.setNoImpact())
.item()
.transform(customItemModel("_", "block_single"))
.register();
@ -1178,8 +1180,8 @@ public class AllBlocks {
.transform(axeOrPickaxe())
.properties(p -> p.mapColor(MapColor.PODZOL))
.transform(BuilderTransformers.bearing("windmill", "gearbox"))
.transform(BlockStressDefaults.setCapacity(512.0))
.transform(BlockStressDefaults.setGeneratorSpeed(WindmillBearingBlock::getSpeedRange))
.transform(CStress.setCapacity(512.0))
.onRegister(BlockStressValues.setGeneratorSpeed(16, true))
.tag(AllBlockTags.SAFE_NBT.tag)
.register();
@ -1188,7 +1190,7 @@ public class AllBlocks {
.properties(p -> p.mapColor(MapColor.PODZOL))
.transform(axeOrPickaxe())
.transform(BuilderTransformers.bearing("mechanical", "gearbox"))
.transform(BlockStressDefaults.setImpact(4.0))
.transform(CStress.setImpact(4.0))
.tag(AllBlockTags.SAFE_NBT.tag)
.onRegister(movementBehaviour(new StabilizedBearingMovementBehaviour()))
.register();
@ -1198,7 +1200,7 @@ public class AllBlocks {
.properties(p -> p.mapColor(MapColor.TERRACOTTA_BROWN))
.transform(axeOrPickaxe())
.transform(BuilderTransformers.bearing("clockwork", "brass_gearbox"))
.transform(BlockStressDefaults.setImpact(4.0))
.transform(CStress.setImpact(4.0))
.tag(AllBlockTags.SAFE_NBT.tag)
.register();
@ -1210,7 +1212,7 @@ public class AllBlocks {
.transform(axeOrPickaxe())
.tag(AllBlockTags.SAFE_NBT.tag)
.blockstate(BlockStateGen.horizontalAxisBlockProvider(true))
.transform(BlockStressDefaults.setImpact(4.0))
.transform(CStress.setImpact(4.0))
.item()
.transform(customItemModel())
.register();
@ -1239,7 +1241,7 @@ public class AllBlocks {
.properties(p -> p.mapColor(MapColor.TERRACOTTA_BROWN))
.transform(axeOrPickaxe())
.blockstate(BlockStateGen.horizontalBlockProvider(true))
.transform(BlockStressDefaults.setImpact(4.0))
.transform(CStress.setImpact(4.0))
.item()
.transform(customItemModel())
.register();
@ -1343,7 +1345,7 @@ public class AllBlocks {
.properties(p -> p.mapColor(MapColor.PODZOL))
.transform(axeOrPickaxe())
.blockstate(BlockStateGen.directionalBlockProvider(true))
.transform(BlockStressDefaults.setImpact(4.0))
.transform(CStress.setImpact(4.0))
.onRegister(movementBehaviour(new DrillMovementBehaviour()))
.item()
.tag(AllItemTags.CONTRAPTION_CONTROLLED.tag)
@ -1356,7 +1358,7 @@ public class AllBlocks {
.properties(p -> p.mapColor(MapColor.PODZOL))
.transform(axeOrPickaxe())
.blockstate(new SawGenerator()::generate)
.transform(BlockStressDefaults.setImpact(4.0))
.transform(CStress.setImpact(4.0))
.onRegister(movementBehaviour(new SawMovementBehaviour()))
.addLayer(() -> RenderType::cutoutMipped)
.item()
@ -1369,7 +1371,7 @@ public class AllBlocks {
.properties(p -> p.mapColor(MapColor.PODZOL))
.transform(axeOrPickaxe())
.blockstate(BlockStateGen.directionalAxisBlockProvider())
.transform(BlockStressDefaults.setImpact(4.0))
.transform(CStress.setImpact(4.0))
.onRegister(movementBehaviour(new DeployerMovementBehaviour()))
.onRegister(interactionBehaviour(new DeployerMovingInteraction()))
.item(AssemblyOperatorBlockItem::new)
@ -1544,7 +1546,7 @@ public class AllBlocks {
.mapColor(MapColor.TERRACOTTA_YELLOW))
.transform(axeOrPickaxe())
.blockstate(BlockStateGen.horizontalBlockProvider(true))
.transform(BlockStressDefaults.setImpact(2.0))
.transform(CStress.setImpact(2.0))
.onRegister(CreateRegistrate.connectedTextures(CrafterCTBehaviour::new))
.addLayer(() -> RenderType::cutoutMipped)
.item()
@ -1558,7 +1560,7 @@ public class AllBlocks {
.transform(axeOrPickaxe())
.tag(AllBlockTags.SAFE_NBT.tag)
.properties(BlockBehaviour.Properties::noOcclusion)
.transform(BlockStressDefaults.setNoImpact())
.transform(CStress.setNoImpact())
.blockstate(new SequencedGearshiftGenerator()::generate)
.item()
.transform(customItemModel())
@ -1569,7 +1571,7 @@ public class AllBlocks {
.properties(p -> p.noOcclusion()
.mapColor(MapColor.TERRACOTTA_YELLOW))
.transform(axeOrPickaxe())
.transform(BlockStressDefaults.setNoImpact())
.transform(CStress.setNoImpact())
.blockstate(BlockStateGen.axisBlockProvider(true))
.item()
.transform(customItemModel())
@ -1581,7 +1583,7 @@ public class AllBlocks {
.properties(p -> p.mapColor(MapColor.TERRACOTTA_YELLOW))
.transform(axeOrPickaxe())
.tag(AllBlockTags.SAFE_NBT.tag)
.transform(BlockStressDefaults.setNoImpact())
.transform(CStress.setNoImpact())
.blockstate(BlockStateGen.horizontalAxisBlockProvider(true))
.item()
.transform(customItemModel())
@ -1598,7 +1600,7 @@ public class AllBlocks {
.modelFile(AssetLookup.partialBaseModel(c, p))
.rotationX(s.getValue(ArmBlock.CEILING) ? 180 : 0)
.build()))
.transform(BlockStressDefaults.setImpact(2.0))
.transform(CStress.setImpact(2.0))
.item(ArmItem::new)
.transform(customItemModel())
.register();
@ -2037,7 +2039,7 @@ public class AllBlocks {
.properties(p -> p.mapColor(MapColor.COLOR_GRAY))
.addLayer(() -> RenderType::cutoutMipped)
.transform(pickaxeOnly())
.transform(BlockStressDefaults.setImpact(0))
.transform(CStress.setNoImpact())
.blockstate((c, p) -> p.horizontalBlock(c.get(), AssetLookup.partialBaseModel(c, p)))
.transform(displayTarget(AllDisplayTargets.DISPLAY_BOARD))
.lang("Display Board")

View file

@ -1,7 +1,5 @@
package com.simibubi.create;
import com.simibubi.create.content.equipment.potatoCannon.PotatoProjectileTypeManager;
import net.minecraft.advancements.critereon.ItemPredicate;
import net.minecraft.core.HolderGetter;
import net.minecraft.core.HolderSet;
@ -45,9 +43,7 @@ public class AllEnchantments {
EnchantmentEffectComponents.AMMO_USE,
new SetValue(LevelBasedValue.perLevel(0.0F, 33.3333333333F)),
MatchTool.toolMatches(
ItemPredicate.Builder.item().of(
PotatoProjectileTypeManager.getItems().toArray(Item[]::new)
)
ItemPredicate.Builder.item().of() // TODO - Fix potato recovery
)
)
);

View file

@ -1,6 +1,6 @@
package com.simibubi.create;
import net.neoforged.fml.common.EventBusSubscriber;
import java.util.function.BiConsumer;
import org.lwjgl.glfw.GLFW;
@ -9,12 +9,12 @@ import com.mojang.blaze3d.platform.InputConstants;
import net.minecraft.client.KeyMapping;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent;
import java.util.function.BiConsumer;
@EventBusSubscriber(value = Dist.CLIENT, bus = EventBusSubscriber.Bus.MOD)
public enum AllKeys {

View file

@ -35,7 +35,6 @@ import com.simibubi.create.content.equipment.blueprint.BlueprintAssignCompleteRe
import com.simibubi.create.content.equipment.clipboard.ClipboardEditPacket;
import com.simibubi.create.content.equipment.extendoGrip.ExtendoGripInteractionPacket;
import com.simibubi.create.content.equipment.potatoCannon.PotatoCannonPacket;
import com.simibubi.create.content.equipment.potatoCannon.PotatoProjectileTypeManager;
import com.simibubi.create.content.equipment.symmetryWand.ConfigureSymmetryWandPacket;
import com.simibubi.create.content.equipment.symmetryWand.SymmetryEffectPacket;
import com.simibubi.create.content.equipment.tool.KnockbackPacket;
@ -208,7 +207,6 @@ public enum AllPackets implements BasePacketPayload.PacketTypeProvider {
POTATO_CANNON(PotatoCannonPacket.class, PotatoCannonPacket.STREAM_CODEC),
SOUL_PULSE(SoulPulseEffectPacket.class, SoulPulseEffectPacket.STREAM_CODEC),
PERSISTENT_DATA(ISyncPersistentData.PersistentDataPacket.class, ISyncPersistentData.PersistentDataPacket.STREAM_CODEC),
SYNC_POTATO_PROJECTILE_TYPES(PotatoProjectileTypeManager.SyncPacket.class, PotatoProjectileTypeManager.SyncPacket.STREAM_CODEC),
SYNC_RAIL_GRAPH(TrackGraphSyncPacket.class, TrackGraphSyncPacket.STREAM_CODEC),
SYNC_EDGE_GROUP(SignalEdgeGroupPacket.class, SignalEdgeGroupPacket.STREAM_CODEC),
ADD_TRAIN(AddTrainPacket.class, AddTrainPacket.STREAM_CODEC),

View file

@ -2,14 +2,6 @@ package com.simibubi.create;
import java.util.Random;
import com.simibubi.create.content.equipment.armor.AllArmorMaterials;
import com.simibubi.create.content.logistics.packagePort.AllPackagePortTargetTypes;
import com.simibubi.create.foundation.recipe.AllIngredients;
import net.minecraft.core.registries.BuiltInRegistries;
import net.neoforged.neoforge.registries.RegisterEvent;
import org.slf4j.Logger;
import com.google.gson.Gson;
@ -20,12 +12,16 @@ import com.simibubi.create.compat.Mods;
import com.simibubi.create.compat.computercraft.ComputerCraftProxy;
import com.simibubi.create.compat.curios.Curios;
import com.simibubi.create.content.decoration.palettes.AllPaletteBlocks;
import com.simibubi.create.content.equipment.potatoCannon.BuiltinPotatoProjectileTypes;
import com.simibubi.create.content.equipment.armor.AllArmorMaterials;
import com.simibubi.create.content.equipment.potatoCannon.AllPotatoProjectileBlockHitActions;
import com.simibubi.create.content.equipment.potatoCannon.AllPotatoProjectileEntityHitActions;
import com.simibubi.create.content.equipment.potatoCannon.AllPotatoProjectileRenderModes;
import com.simibubi.create.content.fluids.tank.BoilerHeaters;
import com.simibubi.create.content.kinetics.TorquePropagator;
import com.simibubi.create.content.kinetics.fan.processing.AllFanProcessingTypes;
import com.simibubi.create.content.kinetics.mechanicalArm.AllArmInteractionPointTypes;
import com.simibubi.create.content.logistics.item.filter.attribute.AllItemAttributeTypes;
import com.simibubi.create.content.logistics.packagePort.AllPackagePortTargetTypes;
import com.simibubi.create.content.logistics.packagerLink.GlobalLogisticsManager;
import com.simibubi.create.content.redstone.link.RedstoneLinkNetworkHandler;
import com.simibubi.create.content.schematics.ServerSchematicLoader;
@ -38,6 +34,7 @@ import com.simibubi.create.foundation.data.CreateRegistrate;
import com.simibubi.create.foundation.item.ItemDescription;
import com.simibubi.create.foundation.item.KineticStats;
import com.simibubi.create.foundation.item.TooltipModifier;
import com.simibubi.create.foundation.recipe.AllIngredients;
import com.simibubi.create.foundation.utility.CreateNBTProcessors;
import com.simibubi.create.infrastructure.command.ServerLagger;
import com.simibubi.create.infrastructure.config.AllConfigs;
@ -47,13 +44,13 @@ import com.simibubi.create.infrastructure.worldgen.AllPlacementModifiers;
import net.createmod.catnip.lang.FontHelper;
import net.createmod.catnip.lang.LangBuilder;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.level.Level;
import net.neoforged.bus.api.EventPriority;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.fml.ModContainer;
@ -61,6 +58,7 @@ import net.neoforged.fml.ModLoadingContext;
import net.neoforged.fml.common.Mod;
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
import net.neoforged.neoforge.common.NeoForgeMod;
import net.neoforged.neoforge.registries.RegisterEvent;
@Mod(Create.ID)
public class Create {
@ -73,7 +71,9 @@ public class Create {
.disableHtmlEscaping()
.create();
/** Use the {@link Random} of a local {@link Level} or {@link Entity} or create one */
/**
* Use the {@link Random} of a local {@link Level} or {@link Entity} or create one
*/
@Deprecated
public static final Random RANDOM = new Random();
@ -87,7 +87,7 @@ public class Create {
static {
REGISTRATE.setTooltipModifierFactory(item ->
new ItemDescription.Modifier(item, FontHelper.Palette.STANDARD_CREATE)
.andThen(TooltipModifier.mapNull(KineticStats.create(item)))
.andThen(TooltipModifier.mapNull(KineticStats.create(item)))
);
}
@ -136,6 +136,7 @@ public class Create {
AllConfigs.register(modLoadingContext, modContainer);
// TODO - Make these use Registry.register and move them into the RegisterEvent
AllArmInteractionPointTypes.register(modEventBus);
AllFanProcessingTypes.register(modEventBus);
AllItemAttributeTypes.register(modEventBus);
@ -152,7 +153,7 @@ public class Create {
NeoForgeMod.enableMilkFluid();
modEventBus.addListener(Create::init);
modEventBus.addListener(Create::registerAdvancements);
modEventBus.addListener(Create::onRegister);
modEventBus.addListener(AllEntityTypes::registerEntityAttributes);
modEventBus.addListener(EventPriority.LOWEST, CreateDatagen::gatherData);
modEventBus.addListener(AllSoundEvents::register);
@ -169,7 +170,6 @@ public class Create {
// TODO: custom registration should all happen in one place
// Most registration happens in the constructor.
// These registrations use Create's registered objects directly so they must run after registration has finished.
BuiltinPotatoProjectileTypes.register();
BoilerHeaters.registerDefaults();
AllPortalTracks.registerDefaults();
BlockSpoutingBehaviour.registerDefaults();
@ -182,7 +182,11 @@ public class Create {
});
}
public static void registerAdvancements(final RegisterEvent event) {
public static void onRegister(final RegisterEvent event) {
AllPotatoProjectileRenderModes.init();
AllPotatoProjectileEntityHitActions.init();
AllPotatoProjectileBlockHitActions.init();
if (event.getRegistry() == BuiltInRegistries.TRIGGER_TYPES) {
AllAdvancements.register();
AllTriggers.register();

View file

@ -0,0 +1,230 @@
package com.simibubi.create.api.equipment.potatoCannon;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.jetbrains.annotations.Nullable;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileEntityHitAction.Type;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileRenderMode.Billboard;
import com.simibubi.create.api.registry.CreateRegistries;
import net.minecraft.core.Holder;
import net.minecraft.core.Holder.Reference;
import net.minecraft.core.HolderSet;
import net.minecraft.core.RegistryCodecs;
import net.minecraft.core.registries.Registries;
import net.minecraft.data.worldgen.BootstrapContext;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.EntityHitResult;
public record PotatoCannonProjectileType(HolderSet<Item> items, int reloadTicks, int damage, int split, float knockback,
float drag, float velocityMultiplier, float gravityMultiplier,
float soundPitch, boolean sticky, ItemStack dropStack,
PotatoProjectileRenderMode renderMode,
Optional<PotatoProjectileEntityHitAction> preEntityHit,
Optional<PotatoProjectileEntityHitAction> onEntityHit,
Optional<PotatoProjectileBlockHitAction> onBlockHit) {
public static final Codec<PotatoCannonProjectileType> CODEC = RecordCodecBuilder.create(i -> i.group(
RegistryCodecs.homogeneousList(Registries.ITEM).fieldOf("items").forGetter(PotatoCannonProjectileType::items),
Codec.INT.optionalFieldOf("reload_ticks", 10).forGetter(PotatoCannonProjectileType::reloadTicks),
Codec.INT.optionalFieldOf("damage", 1).forGetter(PotatoCannonProjectileType::damage),
Codec.INT.optionalFieldOf("split", 1).forGetter(PotatoCannonProjectileType::split),
Codec.FLOAT.optionalFieldOf("knockback", 1f).forGetter(PotatoCannonProjectileType::knockback),
Codec.FLOAT.optionalFieldOf("drag", .99f).forGetter(PotatoCannonProjectileType::drag),
Codec.FLOAT.optionalFieldOf("velocity_multiplier", 1f).forGetter(PotatoCannonProjectileType::velocityMultiplier),
Codec.FLOAT.optionalFieldOf("gravity_multiplier", 1f).forGetter(PotatoCannonProjectileType::gravityMultiplier),
Codec.FLOAT.optionalFieldOf("sound_pitch", 1f).forGetter(PotatoCannonProjectileType::soundPitch),
Codec.BOOL.optionalFieldOf("sticky", false).forGetter(PotatoCannonProjectileType::sticky),
ItemStack.CODEC.optionalFieldOf("drop_stack", ItemStack.EMPTY).forGetter(PotatoCannonProjectileType::dropStack),
PotatoProjectileRenderMode.CODEC.optionalFieldOf("render_mode", Billboard.INSTANCE).forGetter(PotatoCannonProjectileType::renderMode),
PotatoProjectileEntityHitAction.CODEC.optionalFieldOf("pre_entity_hit").forGetter(p -> p.preEntityHit),
PotatoProjectileEntityHitAction.CODEC.optionalFieldOf("on_entity_hit").forGetter(p -> p.onEntityHit),
PotatoProjectileBlockHitAction.CODEC.optionalFieldOf("on_entity_hit").forGetter(p -> p.onBlockHit)
).apply(i, PotatoCannonProjectileType::new));
@Nullable
public static PotatoCannonProjectileType getTypeForItem(Level level, Item item) {
// Cache this if it causes performance issues, but it probably won't
List<PotatoCannonProjectileType> types = level.registryAccess()
.lookupOrThrow(CreateRegistries.POTATO_PROJECTILE_TYPE)
.listElements()
.map(Reference::value)
.toList();
for (PotatoCannonProjectileType type : types)
if (type.items.contains(item.builtInRegistryHolder()))
return type;
return null;
}
public static Optional<PotatoCannonProjectileType> getTypeForStack(Level level, ItemStack item) {
if (item.isEmpty())
return Optional.empty();
return Optional.ofNullable(getTypeForItem(level, item.getItem()));
}
public boolean preEntityHit(ItemStack stack, EntityHitResult ray) {
return preEntityHit.map(i -> i.execute(stack, ray, Type.PRE_HIT)).orElse(false);
}
public boolean onEntityHit(ItemStack stack, EntityHitResult ray) {
return onEntityHit.map(i -> i.execute(stack, ray, Type.ON_HIT)).orElse(false);
}
public boolean onBlockHit(LevelAccessor level, ItemStack stack, BlockHitResult ray) {
return onBlockHit.map(i -> i.execute(level, stack, ray)).orElse(false);
}
public static class Builder {
private ResourceLocation id;
private final List<Holder<Item>> items = new ArrayList<>();
private int reloadTicks = 10;
private int damage = 1;
private int split = 1;
private float knockback = 1f;
private float drag = 0.99f;
private float velocityMultiplier = 1f;
private float gravityMultiplier = 1f;
private float soundPitch = 1f;
private boolean sticky = false;
private ItemStack dropStack = ItemStack.EMPTY;
private PotatoProjectileRenderMode renderMode = Billboard.INSTANCE;
private PotatoProjectileEntityHitAction preEntityHit = null;
private PotatoProjectileEntityHitAction onEntityHit = null;
private PotatoProjectileBlockHitAction onBlockHit = null;
public Builder(ResourceLocation id) {
this.id = id;
}
public Builder reloadTicks(int reload) {
this.reloadTicks = reload;
return this;
}
public Builder damage(int damage) {
this.damage = damage;
return this;
}
public Builder splitInto(int split) {
this.split = split;
return this;
}
public Builder knockback(float knockback) {
this.knockback = knockback;
return this;
}
public Builder drag(float drag) {
this.drag = drag;
return this;
}
public Builder velocity(float velocity) {
this.velocityMultiplier = velocity;
return this;
}
public Builder gravity(float modifier) {
this.gravityMultiplier = modifier;
return this;
}
public Builder soundPitch(float pitch) {
this.soundPitch = pitch;
return this;
}
public Builder sticky() {
this.sticky = true;
return this;
}
public Builder dropStack(ItemStack stack) {
this.dropStack = stack;
return this;
}
public Builder renderMode(PotatoProjectileRenderMode renderMode) {
this.renderMode = renderMode;
return this;
}
public Builder renderBillboard() {
renderMode(PotatoProjectileRenderMode.Billboard.INSTANCE);
return this;
}
public Builder renderTumbling() {
renderMode(PotatoProjectileRenderMode.Tumble.INSTANCE);
return this;
}
public Builder renderTowardMotion(int spriteAngle, float spin) {
renderMode(new PotatoProjectileRenderMode.TowardMotion(spriteAngle, spin));
return this;
}
public Builder preEntityHit(PotatoProjectileEntityHitAction entityHitAction) {
this.preEntityHit = entityHitAction;
return this;
}
public Builder onEntityHit(PotatoProjectileEntityHitAction entityHitAction) {
this.onEntityHit = entityHitAction;
return this;
}
public Builder onBlockHit(PotatoProjectileBlockHitAction blockHitAction) {
this.onBlockHit = blockHitAction;
return this;
}
public Builder addItems(ItemLike... items) {
for (ItemLike provider : items)
this.items.add(provider.asItem().builtInRegistryHolder());
return this;
}
public void register(BootstrapContext<PotatoCannonProjectileType> ctx) {
PotatoCannonProjectileType type = new PotatoCannonProjectileType(
HolderSet.direct(items),
reloadTicks,
damage,
split,
knockback,
drag,
velocityMultiplier,
gravityMultiplier,
soundPitch,
sticky,
dropStack,
renderMode,
Optional.ofNullable(preEntityHit),
Optional.ofNullable(onEntityHit),
Optional.ofNullable(onBlockHit)
);
ctx.register(ResourceKey.create(CreateRegistries.POTATO_PROJECTILE_TYPE, id), type);
}
public void registerAndAssign(BootstrapContext<PotatoCannonProjectileType> ctx, ItemLike... items) {
addItems(items);
register(ctx);
}
}
}

View file

@ -0,0 +1,116 @@
package com.simibubi.create.api.equipment.potatoCannon;
import java.util.function.Function;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import com.simibubi.create.api.registry.CreateBuiltInRegistries;
import com.simibubi.create.foundation.mixin.accessor.FallingBlockEntityAccessor;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.world.entity.item.FallingBlockEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.phys.BlockHitResult;
import net.neoforged.neoforge.common.SpecialPlantable;
public interface PotatoProjectileBlockHitAction {
Codec<PotatoProjectileBlockHitAction> CODEC = CreateBuiltInRegistries.POTATO_PROJECTILE_BLOCK_HIT_ACTION.byNameCodec()
.dispatch(PotatoProjectileBlockHitAction::codec, Function.identity());
boolean execute(LevelAccessor level, ItemStack projectile, BlockHitResult ray);
MapCodec<? extends PotatoProjectileBlockHitAction> codec();
record PlantCrop(Holder<Block> cropBlock) implements PotatoProjectileBlockHitAction {
public static final MapCodec<PlantCrop> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
BuiltInRegistries.BLOCK.holderByNameCodec().fieldOf("block").forGetter(PlantCrop::cropBlock)
).apply(instance, PlantCrop::new));
public PlantCrop(Block cropBlock) {
this(cropBlock.builtInRegistryHolder());
}
@Override
public boolean execute(LevelAccessor level, ItemStack projectile, BlockHitResult ray) {
if (level.isClientSide())
return true;
BlockPos hitPos = ray.getBlockPos();
if (level instanceof Level l && !l.isLoaded(hitPos))
return true;
Direction face = ray.getDirection();
if (face != Direction.UP)
return false;
BlockPos placePos = hitPos.relative(face);
if (!level.getBlockState(placePos)
.canBeReplaced())
return false;
if (!(cropBlock.value() instanceof SpecialPlantable specialPlantable))
return false;
if (specialPlantable.canPlacePlantAtPosition(projectile, level, placePos, null))
specialPlantable.spawnPlantAtPosition(projectile, level, placePos, null);
return true;
}
@Override
public MapCodec<? extends PotatoProjectileBlockHitAction> codec() {
return CODEC;
}
}
record PlaceBlockOnGround(Holder<Block> block) implements PotatoProjectileBlockHitAction {
public static final MapCodec<PlaceBlockOnGround> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
BuiltInRegistries.BLOCK.holderByNameCodec().fieldOf("block").forGetter(PlaceBlockOnGround::block)
).apply(instance, PlaceBlockOnGround::new));
public PlaceBlockOnGround(Block block) {
this(block.builtInRegistryHolder());
}
@Override
public boolean execute(LevelAccessor levelAccessor, ItemStack projectile, BlockHitResult ray) {
if (levelAccessor.isClientSide())
return true;
BlockPos hitPos = ray.getBlockPos();
if (levelAccessor instanceof Level l && !l.isLoaded(hitPos))
return true;
Direction face = ray.getDirection();
BlockPos placePos = hitPos.relative(face);
if (!levelAccessor.getBlockState(placePos)
.canBeReplaced())
return false;
if (face == Direction.UP) {
levelAccessor.setBlock(placePos, block.value()
.defaultBlockState(), 3);
} else if (levelAccessor instanceof Level level) {
double y = ray.getLocation().y - 0.5;
if (!level.isEmptyBlock(placePos.above()))
y = Math.min(y, placePos.getY());
if (!level.isEmptyBlock(placePos.below()))
y = Math.max(y, placePos.getY());
FallingBlockEntity falling = FallingBlockEntityAccessor.create$callInit(level, placePos.getX() + 0.5, y,
placePos.getZ() + 0.5, block.value().defaultBlockState());
falling.time = 1;
level.addFreshEntity(falling);
}
return true;
}
@Override
public MapCodec<? extends PotatoProjectileBlockHitAction> codec() {
return CODEC;
}
}
}

View file

@ -0,0 +1,252 @@
package com.simibubi.create.api.equipment.potatoCannon;
import java.util.UUID;
import java.util.function.Function;
import com.mojang.authlib.GameProfile;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import com.simibubi.create.api.registry.CreateBuiltInRegistries;
import com.simibubi.create.foundation.codec.CreateCodecs;
import net.createmod.catnip.data.WorldAttached;
import net.minecraft.core.Holder;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.util.Mth;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.animal.Fox;
import net.minecraft.world.entity.monster.ZombieVillager;
import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.food.FoodProperties.PossibleEffect;
import net.minecraft.world.food.Foods;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.component.SuspiciousStewEffects;
import net.minecraft.world.item.component.SuspiciousStewEffects.Entry;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.Vec3;
import net.neoforged.neoforge.common.util.FakePlayer;
import net.neoforged.neoforge.event.EventHooks;
import net.neoforged.neoforge.event.entity.EntityTeleportEvent;
public interface PotatoProjectileEntityHitAction {
Codec<PotatoProjectileEntityHitAction> CODEC = CreateBuiltInRegistries.POTATO_PROJECTILE_ENTITY_HIT_ACTION.byNameCodec()
.dispatch(PotatoProjectileEntityHitAction::codec, Function.identity());
enum Type {
PRE_HIT,
ON_HIT
}
/**
* @return true if the hit should be canceled if the type is {@link Type#PRE_HIT PRE_HIT},
* true if this shouldn't recover the projectile if the type is {@link Type#ON_HIT ON_HIT}
*/
boolean execute(ItemStack projectile, EntityHitResult ray, Type type);
MapCodec<? extends PotatoProjectileEntityHitAction> codec();
record SetOnFire(int ticks) implements PotatoProjectileEntityHitAction {
public static final MapCodec<SetOnFire> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
ExtraCodecs.POSITIVE_INT.fieldOf("ticks").forGetter(SetOnFire::ticks)
).apply(instance, SetOnFire::new));
public static SetOnFire seconds(int seconds) {
return new SetOnFire(seconds * 20);
}
@Override
public boolean execute(ItemStack projectile, EntityHitResult ray, Type type) {
ray.getEntity()
.setRemainingFireTicks(ticks);
return false;
}
@Override
public MapCodec<? extends PotatoProjectileEntityHitAction> codec() {
return CODEC;
}
}
record PotionEffect(Holder<MobEffect> effect, int level, int ticks,
boolean recoverable) implements PotatoProjectileEntityHitAction {
public static final MapCodec<PotionEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
BuiltInRegistries.MOB_EFFECT.holderByNameCodec().fieldOf("effect").forGetter(PotionEffect::effect),
ExtraCodecs.POSITIVE_INT.fieldOf("level").forGetter(PotionEffect::level),
ExtraCodecs.POSITIVE_INT.fieldOf("ticks").forGetter(PotionEffect::ticks),
Codec.BOOL.fieldOf("recoverable").forGetter(PotionEffect::recoverable)
).apply(instance, PotionEffect::new));
@Override
public boolean execute(ItemStack projectile, EntityHitResult ray, Type type) {
Entity entity = ray.getEntity();
if (entity.level().isClientSide)
return true;
if (entity instanceof LivingEntity)
applyEffect((LivingEntity) entity, new MobEffectInstance(effect, ticks, level - 1));
return !recoverable;
}
@Override
public MapCodec<? extends PotatoProjectileEntityHitAction> codec() {
return CODEC;
}
}
record FoodEffects(FoodProperties foodProperty, boolean recoverable) implements PotatoProjectileEntityHitAction {
public static final MapCodec<FoodEffects> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
FoodProperties.DIRECT_CODEC.fieldOf("food_property").forGetter(FoodEffects::foodProperty),
Codec.BOOL.fieldOf("recoverable").forGetter(FoodEffects::recoverable)
).apply(instance, FoodEffects::new));
@Override
public boolean execute(ItemStack projectile, EntityHitResult ray, Type type) {
Entity entity = ray.getEntity();
if (entity.level().isClientSide)
return true;
if (entity instanceof LivingEntity livingEntity) {
for (PossibleEffect possibleEffect : foodProperty.effects()) {
if (livingEntity.getRandom().nextFloat() < possibleEffect.probability())
applyEffect(livingEntity, new MobEffectInstance(possibleEffect.effect()));
}
}
return !recoverable;
}
@Override
public MapCodec<? extends PotatoProjectileEntityHitAction> codec() {
return CODEC;
}
}
record ChorusTeleport(double teleportDiameter) implements PotatoProjectileEntityHitAction {
public static final MapCodec<ChorusTeleport> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
CreateCodecs.POSITIVE_DOUBLE.fieldOf("teleport_diameter").forGetter(ChorusTeleport::teleportDiameter)
).apply(instance, ChorusTeleport::new));
@Override
public boolean execute(ItemStack projectile, EntityHitResult ray, Type type) {
Entity entity = ray.getEntity();
Level level = entity.getCommandSenderWorld();
if (level.isClientSide)
return true;
if (!(entity instanceof LivingEntity livingEntity))
return false;
double entityX = livingEntity.getX();
double entityY = livingEntity.getY();
double entityZ = livingEntity.getZ();
for (int teleportTry = 0; teleportTry < 16; ++teleportTry) {
double teleportX = entityX + (livingEntity.getRandom()
.nextDouble() - 0.5D) * teleportDiameter;
double teleportY = Mth.clamp(entityY + (livingEntity.getRandom()
.nextInt((int) teleportDiameter) - (int) (teleportDiameter / 2)), 0.0D, level.getHeight() - 1);
double teleportZ = entityZ + (livingEntity.getRandom()
.nextDouble() - 0.5D) * teleportDiameter;
EntityTeleportEvent.ChorusFruit event =
EventHooks.onChorusFruitTeleport(livingEntity, teleportX, teleportY, teleportZ);
if (event.isCanceled())
return false;
if (livingEntity.randomTeleport(event.getTargetX(), event.getTargetY(), event.getTargetZ(), true)) {
if (livingEntity.isPassenger())
livingEntity.stopRiding();
SoundEvent soundevent =
livingEntity instanceof Fox ? SoundEvents.FOX_TELEPORT : SoundEvents.CHORUS_FRUIT_TELEPORT;
level.playSound(null, entityX, entityY, entityZ, soundevent, SoundSource.PLAYERS, 1.0F, 1.0F);
livingEntity.playSound(soundevent, 1.0F, 1.0F);
livingEntity.setDeltaMovement(Vec3.ZERO);
return true;
}
}
return false;
}
@Override
public MapCodec<? extends PotatoProjectileEntityHitAction> codec() {
return CODEC;
}
}
enum CureZombieVillager implements PotatoProjectileEntityHitAction {
INSTANCE;
private static final FoodEffects EFFECT = new FoodEffects(Foods.GOLDEN_APPLE, false);
private static final GameProfile ZOMBIE_CONVERTER_NAME =
new GameProfile(UUID.fromString("be12d3dc-27d3-4992-8c97-66be53fd49c5"), "Converter");
private static final WorldAttached<FakePlayer> ZOMBIE_CONVERTERS =
new WorldAttached<>(w -> new FakePlayer((ServerLevel) w, ZOMBIE_CONVERTER_NAME));
public static final MapCodec<CureZombieVillager> CODEC = MapCodec.unit(INSTANCE);
@Override
public boolean execute(ItemStack projectile, EntityHitResult ray, Type type) {
Entity entity = ray.getEntity();
Level world = entity.level();
if (!(entity instanceof ZombieVillager zombieVillager) || !zombieVillager.hasEffect(MobEffects.WEAKNESS))
return EFFECT.execute(projectile, ray, type);
if (world.isClientSide)
return false;
FakePlayer dummy = ZOMBIE_CONVERTERS.get(world);
dummy.setItemInHand(InteractionHand.MAIN_HAND, new ItemStack(Items.GOLDEN_APPLE, 1));
zombieVillager.mobInteract(dummy, InteractionHand.MAIN_HAND);
return true;
}
@Override
public MapCodec<? extends PotatoProjectileEntityHitAction> codec() {
return CODEC;
}
}
enum SuspiciousStew implements PotatoProjectileEntityHitAction {
INSTANCE;
public static final MapCodec<SuspiciousStew> CODEC = MapCodec.unit(INSTANCE);
@Override
public boolean execute(ItemStack projectile, EntityHitResult ray, Type type) {
if (ray.getEntity() instanceof LivingEntity livingEntity) {
SuspiciousStewEffects effects = projectile.getOrDefault(DataComponents.SUSPICIOUS_STEW_EFFECTS, SuspiciousStewEffects.EMPTY);
for (Entry effect : effects.effects())
livingEntity.addEffect(effect.createEffectInstance());
}
return true;
}
@Override
public MapCodec<? extends PotatoProjectileEntityHitAction> codec() {
return CODEC;
}
}
private static void applyEffect(LivingEntity entity, MobEffectInstance effect) {
if (effect.getEffect().value().isInstantenous()) {
effect.getEffect().value()
.applyInstantenousEffect(null, null, entity, effect.getDuration(), 1.0);
} else {
entity.addEffect(effect);
}
}
}

View file

@ -1,8 +1,15 @@
package com.simibubi.create.content.equipment.potatoCannon;
package com.simibubi.create.api.equipment.potatoCannon;
import static com.simibubi.create.content.equipment.potatoCannon.PotatoProjectileRenderMode.entityRandom;
import static com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileRenderMode.entityRandom;
import java.util.function.Function;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import com.simibubi.create.api.registry.CreateBuiltInRegistries;
import com.simibubi.create.content.equipment.potatoCannon.PotatoProjectileEntity;
import dev.engine_room.flywheel.lib.transform.TransformStack;
import net.createmod.catnip.math.AngleHelper;
@ -10,17 +17,23 @@ import net.minecraft.client.Minecraft;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.Vec3;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.api.distmarker.OnlyIn;
public interface PotatoProjectileRenderMode {
Codec<PotatoProjectileRenderMode> CODEC = CreateBuiltInRegistries.POTATO_PROJECTILE_RENDER_MODE.byNameCodec()
.dispatch(PotatoProjectileRenderMode::codec, Function.identity());
@OnlyIn(Dist.CLIENT)
void transform(PoseStack ms, PotatoProjectileEntity entity, float pt);
public static class Billboard implements PotatoProjectileRenderMode {
MapCodec<? extends PotatoProjectileRenderMode> codec();
public static final Billboard INSTANCE = new Billboard();
enum Billboard implements PotatoProjectileRenderMode {
INSTANCE;
public static final MapCodec<Billboard> CODEC = MapCodec.unit(INSTANCE);
@Override
@OnlyIn(Dist.CLIENT)
@ -37,32 +50,37 @@ public interface PotatoProjectileRenderMode {
.rotateXDegrees(AngleHelper.deg(Mth.atan2(diff.y, Mth.sqrt((float) (diff.x * diff.x + diff.z * diff.z)))));
}
@Override
public MapCodec<? extends PotatoProjectileRenderMode> codec() {
return CODEC;
}
}
public static class Tumble extends Billboard {
enum Tumble implements PotatoProjectileRenderMode {
INSTANCE;
public static final Tumble INSTANCE = new Tumble();
public static final MapCodec<Tumble> CODEC = MapCodec.unit(INSTANCE);
@Override
@OnlyIn(Dist.CLIENT)
public void transform(PoseStack ms, PotatoProjectileEntity entity, float pt) {
super.transform(ms, entity, pt);
Billboard.INSTANCE.transform(ms, entity, pt);
TransformStack.of(ms)
.rotateZDegrees((entity.tickCount + pt) * 2 * entityRandom(entity, 16))
.rotateXDegrees((entity.tickCount + pt) * entityRandom(entity, 32));
}
@Override
public MapCodec<? extends PotatoProjectileRenderMode> codec() {
return CODEC;
}
}
public static class TowardMotion implements PotatoProjectileRenderMode {
private int spriteAngleOffset;
private float spin;
public TowardMotion(int spriteAngleOffset, float spin) {
this.spriteAngleOffset = spriteAngleOffset;
this.spin = spin;
}
record TowardMotion(int spriteAngleOffset, float spin) implements PotatoProjectileRenderMode {
public static final MapCodec<TowardMotion> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
Codec.INT.fieldOf("sprite_angle_offset").forGetter(i -> i.spriteAngleOffset),
Codec.FLOAT.fieldOf("spin").forGetter(i -> i.spin)
).apply(instance, TowardMotion::new));
@Override
@OnlyIn(Dist.CLIENT)
@ -77,15 +95,16 @@ public interface PotatoProjectileRenderMode {
.rotateZDegrees(-spriteAngleOffset);
}
@Override
public MapCodec<? extends PotatoProjectileRenderMode> codec() {
return CODEC;
}
}
public static class StuckToEntity implements PotatoProjectileRenderMode {
private Vec3 offset;
public StuckToEntity(Vec3 offset) {
this.offset = offset;
}
record StuckToEntity(Vec3 offset) implements PotatoProjectileRenderMode {
public static final MapCodec<StuckToEntity> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
Vec3.CODEC.fieldOf("offset").forGetter(i -> i.offset)
).apply(instance, StuckToEntity::new));
@Override
@OnlyIn(Dist.CLIENT)
@ -93,10 +112,13 @@ public interface PotatoProjectileRenderMode {
TransformStack.of(ms).rotateYDegrees(AngleHelper.deg(Mth.atan2(offset.x, offset.z)));
}
@Override
public MapCodec<? extends PotatoProjectileRenderMode> codec() {
return CODEC;
}
}
public static int entityRandom(Entity entity, int maxValue) {
static int entityRandom(Entity entity, int maxValue) {
return (System.identityHashCode(entity) * 31) % maxValue;
}
}

View file

@ -5,11 +5,16 @@ import java.util.Set;
import org.jetbrains.annotations.ApiStatus.Internal;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.simibubi.create.api.behaviour.display.DisplaySource;
import com.simibubi.create.api.behaviour.display.DisplayTarget;
import com.simibubi.create.api.contraption.ContraptionType;
import com.simibubi.create.api.contraption.storage.fluid.MountedFluidStorageType;
import com.simibubi.create.api.contraption.storage.item.MountedItemStorageType;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileBlockHitAction;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileEntityHitAction;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileRenderMode;
import com.simibubi.create.content.kinetics.fan.processing.FanProcessingType;
import com.simibubi.create.content.kinetics.mechanicalArm.ArmInteractionPointType;
import com.simibubi.create.content.logistics.item.filter.attribute.ItemAttributeType;
@ -44,6 +49,9 @@ public class CreateBuiltInRegistries {
public static final Registry<MountedFluidStorageType<?>> MOUNTED_FLUID_STORAGE_TYPE = simple(CreateRegistries.MOUNTED_FLUID_STORAGE_TYPE);
public static final Registry<ContraptionType> CONTRAPTION_TYPE = withIntrusiveHolders(CreateRegistries.CONTRAPTION_TYPE);
public static final Registry<PackagePortTargetType> PACKAGE_PORT_TARGET_TYPE = simple(CreateRegistries.PACKAGE_PORT_TARGET_TYPE);
public static final Registry<MapCodec<? extends PotatoProjectileRenderMode>> POTATO_PROJECTILE_RENDER_MODE = simple(CreateRegistries.POTATO_PROJECTILE_RENDER_MODE);
public static final Registry<MapCodec<? extends PotatoProjectileEntityHitAction>> POTATO_PROJECTILE_ENTITY_HIT_ACTION = simple(CreateRegistries.POTATO_PROJECTILE_ENTITY_HIT_ACTION);
public static final Registry<MapCodec<? extends PotatoProjectileBlockHitAction>> POTATO_PROJECTILE_BLOCK_HIT_ACTION = simple(CreateRegistries.POTATO_PROJECTILE_BLOCK_HIT_ACTION);
private static <T> Registry<T> simple(ResourceKey<Registry<T>> key) {
Registry<T> registry = new RegistryBuilder<>(key)

View file

@ -1,11 +1,18 @@
package com.simibubi.create.api.registry;
import org.jetbrains.annotations.ApiStatus.Internal;
import com.mojang.serialization.MapCodec;
import com.simibubi.create.Create;
import com.simibubi.create.api.behaviour.display.DisplaySource;
import com.simibubi.create.api.behaviour.display.DisplayTarget;
import com.simibubi.create.api.contraption.ContraptionType;
import com.simibubi.create.api.contraption.storage.fluid.MountedFluidStorageType;
import com.simibubi.create.api.contraption.storage.item.MountedItemStorageType;
import com.simibubi.create.api.equipment.potatoCannon.PotatoCannonProjectileType;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileBlockHitAction;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileEntityHitAction;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileRenderMode;
import com.simibubi.create.content.kinetics.fan.processing.FanProcessingType;
import com.simibubi.create.content.kinetics.mechanicalArm.ArmInteractionPointType;
import com.simibubi.create.content.logistics.item.filter.attribute.ItemAttributeType;
@ -14,10 +21,17 @@ import com.simibubi.create.content.logistics.packagePort.PackagePortTargetType;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.fml.common.EventBusSubscriber.Bus;
import net.neoforged.neoforge.registries.DataPackRegistryEvent;
/**
* Keys for registries added by Create.
*
* @see CreateBuiltInRegistries
*/
@EventBusSubscriber(bus = Bus.MOD)
public class CreateRegistries {
public static final ResourceKey<Registry<ArmInteractionPointType>> ARM_INTERACTION_POINT_TYPE = key("arm_interaction_point_type");
public static final ResourceKey<Registry<FanProcessingType>> FAN_PROCESSING_TYPE = key("fan_processing_type");
@ -28,8 +42,22 @@ public class CreateRegistries {
public static final ResourceKey<Registry<MountedFluidStorageType<?>>> MOUNTED_FLUID_STORAGE_TYPE = key("mounted_fluid_storage_type");
public static final ResourceKey<Registry<ContraptionType>> CONTRAPTION_TYPE = key("contraption_type");
public static final ResourceKey<Registry<PackagePortTargetType>> PACKAGE_PORT_TARGET_TYPE = key("package_port_target_type");
public static final ResourceKey<Registry<PotatoCannonProjectileType>> POTATO_PROJECTILE_TYPE = key("potato_projectile/type");
public static final ResourceKey<Registry<MapCodec<? extends PotatoProjectileRenderMode>>> POTATO_PROJECTILE_RENDER_MODE = key("potato_projectile/render_mode");
public static final ResourceKey<Registry<MapCodec<? extends PotatoProjectileEntityHitAction>>> POTATO_PROJECTILE_ENTITY_HIT_ACTION = key("potato_projectile/entity_hit_action");
public static final ResourceKey<Registry<MapCodec<? extends PotatoProjectileBlockHitAction>>> POTATO_PROJECTILE_BLOCK_HIT_ACTION = key("potato_projectile/block_hit_action");
private static <T> ResourceKey<Registry<T>> key(String name) {
return ResourceKey.createRegistryKey(Create.asResource(name));
}
@Internal
@SubscribeEvent
public static void registerDatapackRegistries(DataPackRegistryEvent.NewRegistry event) {
event.dataPackRegistry(
POTATO_PROJECTILE_TYPE,
PotatoCannonProjectileType.CODEC,
PotatoCannonProjectileType.CODEC
);
}
}

View file

@ -0,0 +1,50 @@
package com.simibubi.create.api.stress;
import java.util.function.DoubleSupplier;
import com.simibubi.create.api.registry.SimpleRegistry;
import com.tterrag.registrate.util.nullness.NonNullConsumer;
import net.minecraft.world.level.block.Block;
public class BlockStressValues {
/**
* Registry for suppliers of stress impacts. Determine the base impact at 1 RPM.
*/
public static final SimpleRegistry<Block, DoubleSupplier> IMPACTS = SimpleRegistry.create();
/**
* Registry for suppliers of stress capacities. Determine the base capacity at 1 RPM.
*/
public static final SimpleRegistry<Block, DoubleSupplier> CAPACITIES = SimpleRegistry.create();
/**
* Registry for generator RPM values. This is only used for tooltips; actual functionality is determined by the block.
*/
public static final SimpleRegistry<Block, GeneratedRpm> RPM = SimpleRegistry.create();
public static double getImpact(Block block) {
DoubleSupplier supplier = IMPACTS.get(block);
return supplier == null ? 0 : supplier.getAsDouble();
}
public static double getCapacity(Block block) {
DoubleSupplier supplier = CAPACITIES.get(block);
return supplier == null ? 0 : supplier.getAsDouble();
}
/**
* Shortcut for when a generator always generates the same RPM.
*/
public static NonNullConsumer<Block> setGeneratorSpeed(int value) {
return block -> RPM.register(block, new GeneratedRpm(value, false));
}
/**
* Utility for Registrate. Registers the given RPM generation info to blocks passed to the returned consumer.
*/
public static NonNullConsumer<Block> setGeneratorSpeed(int value, boolean mayGenerateLess) {
return block -> RPM.register(block, new GeneratedRpm(value, mayGenerateLess));
}
public record GeneratedRpm(int value, boolean mayGenerateLess) {
}
}

View file

@ -4,8 +4,6 @@ import java.util.Map;
import javax.annotation.Nullable;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import org.jetbrains.annotations.NotNull;
import com.simibubi.create.compat.computercraft.implementation.CreateLuaTable;
@ -29,6 +27,7 @@ import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.NumericTag;
import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component;
public class StationPeripheral extends SyncedPeripheral<StationBlockEntity> {
@ -128,7 +127,7 @@ public class StationPeripheral extends SyncedPeripheral<StationBlockEntity> {
@LuaFunction(mainThread = true)
public final void setTrainName(String name) throws LuaException {
Train train = getTrainOrThrow();
train.name = Component.literal(name);
train.name = Component.literal(name);
CatnipServices.NETWORK.sendToAllClients(new TrainEditPacket.TrainEditReturnPacket(train.id, name, train.icon.getId(), train.mapColorIndex));
}
@ -209,8 +208,8 @@ public class StationPeripheral extends SyncedPeripheral<StationBlockEntity> {
for (String compoundKey : compoundTag.getAllKeys()) {
table.put(
StringHelper.camelCaseToSnakeCase(compoundKey),
fromNBTTag(compoundKey, compoundTag.get(compoundKey))
StringHelper.camelCaseToSnakeCase(compoundKey),
fromNBTTag(compoundKey, compoundTag.get(compoundKey))
);
}
@ -254,11 +253,11 @@ public class StationPeripheral extends SyncedPeripheral<StationBlockEntity> {
throw new LuaException("table key is not of type string");
compound.put(
// Items serialize their resource location as "id" and not as "Id".
// This check is needed to see if the 'i' should be left lowercase or not.
// Items store "count" in the same compound tag, so we can check for its presence to see if this is a serialized item
compoundKey.equals("id") && v.containsKey("count") ? "id" : StringHelper.snakeCaseToCamelCase(compoundKey),
toNBTTag(compoundKey, v.get(compoundKey))
// Items serialize their resource location as "id" and not as "Id".
// This check is needed to see if the 'i' should be left lowercase or not.
// Items store "count" in the same compound tag, so we can check for its presence to see if this is a serialized item
compoundKey.equals("id") && v.containsKey("count") ? "id" : StringHelper.snakeCaseToCamelCase(compoundKey),
toNBTTag(compoundKey, v.get(compoundKey))
);
}

View file

@ -3,7 +3,6 @@ package com.simibubi.create.content.contraptions.bearing;
import com.simibubi.create.AllBlockEntityTypes;
import com.simibubi.create.foundation.block.IBE;
import net.createmod.catnip.data.Couple;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
@ -51,9 +50,4 @@ public class WindmillBearingBlock extends BearingBlock implements IBE<WindmillBe
public BlockEntityType<? extends WindmillBearingBlockEntity> getBlockEntityType() {
return AllBlockEntityTypes.WINDMILL_BEARING.get();
}
public static Couple<Integer> getSpeedRange() {
return Couple.create(1, 16);
}
}

View file

@ -1,7 +1,6 @@
package com.simibubi.create.content.contraptions.pulley;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllPartialModels;
import com.simibubi.create.AllSpriteShifts;
import com.simibubi.create.content.processing.burner.ScrollInstance;
@ -13,7 +12,6 @@ import dev.engine_room.flywheel.lib.instance.InstanceTypes;
import dev.engine_room.flywheel.lib.instance.TransformedInstance;
import dev.engine_room.flywheel.lib.model.Models;
import net.createmod.catnip.render.SpriteShiftEntry;
import net.createmod.ponder.render.VirtualRenderHelper;
public class RopePulleyVisual extends AbstractPulleyVisual<PulleyBlockEntity> {
public RopePulleyVisual(VisualizationContext context, PulleyBlockEntity blockEntity, float partialTick) {

View file

@ -244,6 +244,7 @@ public class ExtendoGripItem extends Item {
if (lastActiveDamageSource == null)
return;
Entity entity = lastActiveDamageSource.getDirectEntity();
lastActiveDamageSource = null;
if (!(entity instanceof Player player))
return;
if (!isHoldingExtendoGrip(player))

View file

@ -0,0 +1,21 @@
package com.simibubi.create.content.equipment.potatoCannon;
import com.mojang.serialization.MapCodec;
import com.simibubi.create.Create;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileBlockHitAction;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileBlockHitAction.PlaceBlockOnGround;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileBlockHitAction.PlantCrop;
import com.simibubi.create.api.registry.CreateBuiltInRegistries;
import net.minecraft.core.Registry;
public class AllPotatoProjectileBlockHitActions {
public static void init() {
register("plant_crop", PlantCrop.CODEC);
register("place_block_on_ground", PlaceBlockOnGround.CODEC);
}
private static void register(String name, MapCodec<? extends PotatoProjectileBlockHitAction> codec) {
Registry.register(CreateBuiltInRegistries.POTATO_PROJECTILE_BLOCK_HIT_ACTION, Create.asResource(name), codec);
}
}

View file

@ -0,0 +1,29 @@
package com.simibubi.create.content.equipment.potatoCannon;
import com.mojang.serialization.MapCodec;
import com.simibubi.create.Create;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileEntityHitAction;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileEntityHitAction.ChorusTeleport;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileEntityHitAction.CureZombieVillager;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileEntityHitAction.FoodEffects;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileEntityHitAction.PotionEffect;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileEntityHitAction.SetOnFire;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileEntityHitAction.SuspiciousStew;
import com.simibubi.create.api.registry.CreateBuiltInRegistries;
import net.minecraft.core.Registry;
public class AllPotatoProjectileEntityHitActions {
public static void init() {
register("set_on_fire", SetOnFire.CODEC);
register("potion_effect", PotionEffect.CODEC);
register("food_effects", FoodEffects.CODEC);
register("chorus_teleport", ChorusTeleport.CODEC);
register("cure_zombie_villager", CureZombieVillager.CODEC);
register("suspicious_stew", SuspiciousStew.CODEC);
}
private static void register(String name, MapCodec<? extends PotatoProjectileEntityHitAction> codec) {
Registry.register(CreateBuiltInRegistries.POTATO_PROJECTILE_ENTITY_HIT_ACTION, Create.asResource(name), codec);
}
}

View file

@ -0,0 +1,26 @@
package com.simibubi.create.content.equipment.potatoCannon;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.simibubi.create.Create;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileRenderMode;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileRenderMode.Billboard;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileRenderMode.StuckToEntity;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileRenderMode.TowardMotion;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileRenderMode.Tumble;
import com.simibubi.create.api.registry.CreateBuiltInRegistries;
import net.minecraft.core.Registry;
public class AllPotatoProjectileRenderModes {
public static void init() {
register("billboard", Billboard.CODEC);
register("tumble", Tumble.CODEC);
register("toward_motion", TowardMotion.CODEC);
register("stuck_to_entity", StuckToEntity.CODEC);
}
private static void register(String name, MapCodec<? extends PotatoProjectileRenderMode> codec) {
Registry.register(CreateBuiltInRegistries.POTATO_PROJECTILE_RENDER_MODE, Create.asResource(name), codec);
}
}

View file

@ -0,0 +1,266 @@
package com.simibubi.create.content.equipment.potatoCannon;
import com.simibubi.create.AllItems;
import com.simibubi.create.Create;
import com.simibubi.create.api.equipment.potatoCannon.PotatoCannonProjectileType;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileBlockHitAction.PlaceBlockOnGround;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileBlockHitAction.PlantCrop;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileEntityHitAction.ChorusTeleport;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileEntityHitAction.CureZombieVillager;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileEntityHitAction.FoodEffects;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileEntityHitAction.PotionEffect;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileEntityHitAction.SetOnFire;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileEntityHitAction.SuspiciousStew;
import com.simibubi.create.api.registry.CreateRegistries;
import net.minecraft.data.worldgen.BootstrapContext;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.food.Foods;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.Blocks;
public class AllPotatoProjectileTypes {
public static ResourceKey<PotatoCannonProjectileType> FALLBACK = ResourceKey.create(CreateRegistries.POTATO_PROJECTILE_TYPE, Create.asResource("fallback"));
public static void bootstrap(BootstrapContext<PotatoCannonProjectileType> ctx) {
create("fallback")
.damage(0)
.register(ctx);
create("potato")
.damage(5)
.reloadTicks(15)
.velocity(1.25f)
.knockback(1.5f)
.renderTumbling()
.onBlockHit(new PlantCrop(Blocks.POTATOES))
.registerAndAssign(ctx, Items.POTATO);
create("baked_potato")
.damage(5)
.reloadTicks(15)
.velocity(1.25f)
.knockback(0.5f)
.renderTumbling()
.preEntityHit(SetOnFire.seconds(3))
.registerAndAssign(ctx, Items.BAKED_POTATO);
create("carrot")
.damage(4)
.reloadTicks(12)
.velocity(1.45f)
.knockback(0.3f)
.renderTowardMotion(140, 1)
.soundPitch(1.5f)
.onBlockHit(new PlantCrop(Blocks.CARROTS))
.registerAndAssign(ctx, Items.CARROT);
create("golden_carrot")
.damage(12)
.reloadTicks(15)
.velocity(1.45f)
.knockback(0.5f)
.renderTowardMotion(140, 2)
.soundPitch(1.5f)
.registerAndAssign(ctx, Items.GOLDEN_CARROT);
create("sweet_berry")
.damage(3)
.reloadTicks(10)
.knockback(0.1f)
.velocity(1.05f)
.renderTumbling()
.splitInto(3)
.soundPitch(1.25f)
.registerAndAssign(ctx, Items.SWEET_BERRIES);
create("glow_berry")
.damage(2)
.reloadTicks(10)
.knockback(0.05f)
.velocity(1.05f)
.renderTumbling()
.splitInto(2)
.soundPitch(1.2f)
.onEntityHit(new PotionEffect(MobEffects.GLOWING, 1, 200, false))
.registerAndAssign(ctx, Items.GLOW_BERRIES);
create("chocolate_berry")
.damage(4)
.reloadTicks(10)
.knockback(0.2f)
.velocity(1.05f)
.renderTumbling()
.splitInto(3)
.soundPitch(1.25f)
.registerAndAssign(ctx, AllItems.CHOCOLATE_BERRIES.get());
create("poison_potato")
.damage(5)
.reloadTicks(15)
.knockback(0.05f)
.velocity(1.25f)
.renderTumbling()
.onEntityHit(new PotionEffect(MobEffects.POISON, 1, 160, true))
.registerAndAssign(ctx, Items.POISONOUS_POTATO);
create("chorus_fruit")
.damage(3)
.reloadTicks(15)
.velocity(1.20f)
.knockback(0.05f)
.renderTumbling()
.onEntityHit(new ChorusTeleport(20))
.registerAndAssign(ctx, Items.CHORUS_FRUIT);
create("apple")
.damage(5)
.reloadTicks(10)
.velocity(1.45f)
.knockback(0.5f)
.renderTumbling()
.soundPitch(1.1f)
.registerAndAssign(ctx, Items.APPLE);
create("honeyed_apple")
.damage(6)
.reloadTicks(15)
.velocity(1.35f)
.knockback(0.1f)
.renderTumbling()
.soundPitch(1.1f)
.onEntityHit(new PotionEffect(MobEffects.MOVEMENT_SLOWDOWN, 2, 160, true))
.registerAndAssign(ctx, AllItems.HONEYED_APPLE.get());
create("golden_apple")
.damage(1)
.reloadTicks(100)
.velocity(1.45f)
.knockback(0.05f)
.renderTumbling()
.soundPitch(1.1f)
.onEntityHit(CureZombieVillager.INSTANCE)
.registerAndAssign(ctx, Items.GOLDEN_APPLE);
create("enchanted_golden_apple")
.damage(1)
.reloadTicks(100)
.velocity(1.45f)
.knockback(0.05f)
.renderTumbling()
.soundPitch(1.1f)
.onEntityHit(new FoodEffects(Foods.ENCHANTED_GOLDEN_APPLE, false))
.registerAndAssign(ctx, Items.ENCHANTED_GOLDEN_APPLE);
create("beetroot")
.damage(2)
.reloadTicks(5)
.velocity(1.6f)
.knockback(0.1f)
.renderTowardMotion(140, 2)
.soundPitch(1.6f)
.registerAndAssign(ctx, Items.BEETROOT);
create("melon_slice")
.damage(3)
.reloadTicks(8)
.knockback(0.1f)
.velocity(1.45f)
.renderTumbling()
.soundPitch(1.5f)
.registerAndAssign(ctx, Items.MELON_SLICE);
create("glistering_melon")
.damage(5)
.reloadTicks(8)
.knockback(0.1f)
.velocity(1.45f)
.renderTumbling()
.soundPitch(1.5f)
.onEntityHit(new PotionEffect(MobEffects.GLOWING, 1, 100, true))
.registerAndAssign(ctx, Items.GLISTERING_MELON_SLICE);
create("melon_block")
.damage(8)
.reloadTicks(20)
.knockback(2.0f)
.velocity(0.95f)
.renderTumbling()
.soundPitch(0.9f)
.onBlockHit(new PlaceBlockOnGround(Blocks.MELON))
.registerAndAssign(ctx, Blocks.MELON);
create("pumpkin_block")
.damage(6)
.reloadTicks(15)
.knockback(2.0f)
.velocity(0.95f)
.renderTumbling()
.soundPitch(0.9f)
.onBlockHit(new PlaceBlockOnGround(Blocks.PUMPKIN))
.registerAndAssign(ctx, Blocks.PUMPKIN);
create("pumpkin_pie")
.damage(7)
.reloadTicks(15)
.knockback(0.05f)
.velocity(1.1f)
.renderTumbling()
.sticky()
.soundPitch(1.1f)
.registerAndAssign(ctx, Items.PUMPKIN_PIE);
create("cake")
.damage(8)
.reloadTicks(15)
.knockback(0.1f)
.velocity(1.1f)
.renderTumbling()
.sticky()
.registerAndAssign(ctx, Items.CAKE);
create("blaze_cake")
.damage(15)
.reloadTicks(20)
.knockback(0.3f)
.velocity(1.1f)
.renderTumbling()
.sticky()
.preEntityHit(SetOnFire.seconds(12))
.registerAndAssign(ctx, AllItems.BLAZE_CAKE.get());
create("fish")
.damage(4)
.knockback(0.6f)
.velocity(1.3f)
.renderTowardMotion(140, 1)
.sticky()
.soundPitch(1.3f)
.registerAndAssign(ctx, Items.COD, Items.COOKED_COD, Items.SALMON, Items.COOKED_SALMON, Items.TROPICAL_FISH);
create("pufferfish")
.damage(4)
.knockback(0.4f)
.velocity(1.1f)
.renderTowardMotion(140, 1)
.sticky()
.onEntityHit(new FoodEffects(Foods.PUFFERFISH, false))
.soundPitch(1.1f)
.registerAndAssign(ctx, Items.PUFFERFISH);
create("suspicious_stew")
.damage(3)
.reloadTicks(40)
.knockback(0.2f)
.velocity(0.8f)
.renderTowardMotion(140, 1)
.dropStack(Items.BOWL.getDefaultInstance())
.onEntityHit(SuspiciousStew.INSTANCE)
.registerAndAssign(ctx, Items.SUSPICIOUS_STEW);
}
private static PotatoCannonProjectileType.Builder create(String name) {
return new PotatoCannonProjectileType.Builder(Create.asResource(name));
}
}

View file

@ -1,420 +0,0 @@
package com.simibubi.create.content.equipment.potatoCannon;
import java.util.UUID;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
import java.util.function.Supplier;
import com.mojang.authlib.GameProfile;
import com.mojang.datafixers.util.Pair;
import com.simibubi.create.AllItems;
import com.simibubi.create.Create;
import com.simibubi.create.foundation.mixin.accessor.FallingBlockEntityAccessor;
import net.createmod.catnip.data.WorldAttached;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Holder;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.Mth;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.animal.Fox;
import net.minecraft.world.entity.item.FallingBlockEntity;
import net.minecraft.world.entity.monster.ZombieVillager;
import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.food.Foods;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.Vec3;
import net.neoforged.neoforge.common.SpecialPlantable;
import net.neoforged.neoforge.common.util.FakePlayer;
import net.neoforged.neoforge.common.util.TriState;
import net.neoforged.neoforge.event.EventHooks;
import net.neoforged.neoforge.event.entity.EntityTeleportEvent;
public class BuiltinPotatoProjectileTypes {
private static final GameProfile ZOMBIE_CONVERTER_NAME =
new GameProfile(UUID.fromString("be12d3dc-27d3-4992-8c97-66be53fd49c5"), "Converter");
private static final WorldAttached<FakePlayer> ZOMBIE_CONVERTERS =
new WorldAttached<>(w -> new FakePlayer((ServerLevel) w, ZOMBIE_CONVERTER_NAME));
public static final PotatoCannonProjectileType
FALLBACK = create("fallback").damage(0)
.register(),
POTATO = create("potato").damage(5)
.reloadTicks(15)
.velocity(1.25f)
.knockback(1.5f)
.renderTumbling()
.onBlockHit(plantCrop(Blocks.POTATOES))
.registerAndAssign(Items.POTATO),
BAKED_POTATO = create("baked_potato").damage(5)
.reloadTicks(15)
.velocity(1.25f)
.knockback(0.5f)
.renderTumbling()
.preEntityHit(setFire(3))
.registerAndAssign(Items.BAKED_POTATO),
CARROT = create("carrot").damage(4)
.reloadTicks(12)
.velocity(1.45f)
.knockback(0.3f)
.renderTowardMotion(140, 1)
.soundPitch(1.5f)
.onBlockHit(plantCrop(Blocks.CARROTS))
.registerAndAssign(Items.CARROT),
GOLDEN_CARROT = create("golden_carrot").damage(12)
.reloadTicks(15)
.velocity(1.45f)
.knockback(0.5f)
.renderTowardMotion(140, 2)
.soundPitch(1.5f)
.registerAndAssign(Items.GOLDEN_CARROT),
SWEET_BERRIES = create("sweet_berry").damage(3)
.reloadTicks(10)
.knockback(0.1f)
.velocity(1.05f)
.renderTumbling()
.splitInto(3)
.soundPitch(1.25f)
.registerAndAssign(Items.SWEET_BERRIES),
GLOW_BERRIES = create("glow_berry").damage(2)
.reloadTicks(10)
.knockback(0.05f)
.velocity(1.05f)
.renderTumbling()
.splitInto(2)
.soundPitch(1.2f)
.onEntityHit(potion(MobEffects.GLOWING, 1, 200, false))
.registerAndAssign(Items.GLOW_BERRIES),
CHOCOLATE_BERRIES = create("chocolate_berry").damage(4)
.reloadTicks(10)
.knockback(0.2f)
.velocity(1.05f)
.renderTumbling()
.splitInto(3)
.soundPitch(1.25f)
.registerAndAssign(AllItems.CHOCOLATE_BERRIES.get()),
POISON_POTATO = create("poison_potato").damage(5)
.reloadTicks(15)
.knockback(0.05f)
.velocity(1.25f)
.renderTumbling()
.onEntityHit(potion(MobEffects.POISON, 1, 160, true))
.registerAndAssign(Items.POISONOUS_POTATO),
CHORUS_FRUIT = create("chorus_fruit").damage(3)
.reloadTicks(15)
.velocity(1.20f)
.knockback(0.05f)
.renderTumbling()
.onEntityHit(chorusTeleport(20))
.registerAndAssign(Items.CHORUS_FRUIT),
APPLE = create("apple").damage(5)
.reloadTicks(10)
.velocity(1.45f)
.knockback(0.5f)
.renderTumbling()
.soundPitch(1.1f)
.registerAndAssign(Items.APPLE),
HONEYED_APPLE = create("honeyed_apple").damage(6)
.reloadTicks(15)
.velocity(1.35f)
.knockback(0.1f)
.renderTumbling()
.soundPitch(1.1f)
.onEntityHit(potion(MobEffects.MOVEMENT_SLOWDOWN, 2, 160, true))
.registerAndAssign(AllItems.HONEYED_APPLE.get()),
GOLDEN_APPLE = create("golden_apple").damage(1)
.reloadTicks(100)
.velocity(1.45f)
.knockback(0.05f)
.renderTumbling()
.soundPitch(1.1f)
.onEntityHit(ray -> {
Entity entity = ray.getEntity();
Level world = entity.level();
if (!(entity instanceof ZombieVillager) || !((ZombieVillager) entity).hasEffect(MobEffects.WEAKNESS))
return foodEffects(Foods.GOLDEN_APPLE, false).test(ray);
if (world.isClientSide)
return false;
FakePlayer dummy = ZOMBIE_CONVERTERS.get(world);
dummy.setItemInHand(InteractionHand.MAIN_HAND, new ItemStack(Items.GOLDEN_APPLE, 1));
((ZombieVillager) entity).mobInteract(dummy, InteractionHand.MAIN_HAND);
return true;
})
.registerAndAssign(Items.GOLDEN_APPLE),
ENCHANTED_GOLDEN_APPLE = create("enchanted_golden_apple").damage(1)
.reloadTicks(100)
.velocity(1.45f)
.knockback(0.05f)
.renderTumbling()
.soundPitch(1.1f)
.onEntityHit(foodEffects(Foods.ENCHANTED_GOLDEN_APPLE, false))
.registerAndAssign(Items.ENCHANTED_GOLDEN_APPLE),
BEETROOT = create("beetroot").damage(2)
.reloadTicks(5)
.velocity(1.6f)
.knockback(0.1f)
.renderTowardMotion(140, 2)
.soundPitch(1.6f)
.registerAndAssign(Items.BEETROOT),
MELON_SLICE = create("melon_slice").damage(3)
.reloadTicks(8)
.knockback(0.1f)
.velocity(1.45f)
.renderTumbling()
.soundPitch(1.5f)
.registerAndAssign(Items.MELON_SLICE),
GLISTERING_MELON = create("glistering_melon").damage(5)
.reloadTicks(8)
.knockback(0.1f)
.velocity(1.45f)
.renderTumbling()
.soundPitch(1.5f)
.onEntityHit(potion(MobEffects.GLOWING, 1, 100, true))
.registerAndAssign(Items.GLISTERING_MELON_SLICE),
MELON_BLOCK = create("melon_block").damage(8)
.reloadTicks(20)
.knockback(2.0f)
.velocity(0.95f)
.renderTumbling()
.soundPitch(0.9f)
.onBlockHit(placeBlockOnGround(Blocks.MELON))
.registerAndAssign(Blocks.MELON),
PUMPKIN_BLOCK = create("pumpkin_block").damage(6)
.reloadTicks(15)
.knockback(2.0f)
.velocity(0.95f)
.renderTumbling()
.soundPitch(0.9f)
.onBlockHit(placeBlockOnGround(Blocks.PUMPKIN))
.registerAndAssign(Blocks.PUMPKIN),
PUMPKIN_PIE = create("pumpkin_pie").damage(7)
.reloadTicks(15)
.knockback(0.05f)
.velocity(1.1f)
.renderTumbling()
.sticky()
.soundPitch(1.1f)
.registerAndAssign(Items.PUMPKIN_PIE),
CAKE = create("cake").damage(8)
.reloadTicks(15)
.knockback(0.1f)
.velocity(1.1f)
.renderTumbling()
.sticky()
.soundPitch(1.0f)
.registerAndAssign(Items.CAKE),
BLAZE_CAKE = create("blaze_cake").damage(15)
.reloadTicks(20)
.knockback(0.3f)
.velocity(1.1f)
.renderTumbling()
.sticky()
.preEntityHit(setFire(12))
.soundPitch(1.0f)
.registerAndAssign(AllItems.BLAZE_CAKE.get());
private static PotatoCannonProjectileType.Builder create(String name) {
return new PotatoCannonProjectileType.Builder(Create.asResource(name));
}
private static Predicate<EntityHitResult> setFire(int seconds) {
return ray -> {
ray.getEntity()
.igniteForSeconds(seconds);
return false;
};
}
private static Predicate<EntityHitResult> potion(Holder<MobEffect> effect, int level, int ticks, boolean recoverable) {
return ray -> {
Entity entity = ray.getEntity();
if (entity.level().isClientSide)
return true;
if (entity instanceof LivingEntity)
applyEffect((LivingEntity) entity, new MobEffectInstance(effect, ticks, level - 1));
return !recoverable;
};
}
private static Predicate<EntityHitResult> foodEffects(FoodProperties food, boolean recoverable) {
return ray -> {
Entity entity = ray.getEntity();
if (entity.level().isClientSide)
return true;
if (entity instanceof LivingEntity) {
for (FoodProperties.PossibleEffect effect : food.effects()) {
if (Create.RANDOM.nextFloat() < effect.probability())
applyEffect((LivingEntity) entity, effect.effectSupplier().get());
}
}
return !recoverable;
};
}
private static void applyEffect(LivingEntity entity, MobEffectInstance effect) {
if (effect.getEffect().value()
.isInstantenous())
effect.getEffect().value()
.applyInstantenousEffect(null, null, entity, effect.getDuration(), 1.0);
else
entity.addEffect(effect);
}
private static BiPredicate<LevelAccessor, BlockHitResult> plantCrop(Supplier<? extends Block> cropBlock) {
return (world, ray) -> {
if (world.isClientSide())
return true;
BlockPos hitPos = ray.getBlockPos();
if (world instanceof Level l && !l.isLoaded(hitPos))
return true;
Direction face = ray.getDirection();
if (face != Direction.UP)
return false;
BlockPos placePos = hitPos.relative(face);
if (!world.getBlockState(placePos)
.canBeReplaced())
return false;
if (!(cropBlock.get() instanceof SpecialPlantable))
return false;
BlockState blockState = world.getBlockState(hitPos);
if (blockState.canSustainPlant(world, hitPos, face, cropBlock.get().defaultBlockState()) == TriState.FALSE)
return false;
world.setBlock(placePos, cropBlock.get()
.defaultBlockState(), 3);
return true;
};
}
private static BiPredicate<LevelAccessor, BlockHitResult> plantCrop(Block cropBlock) {
return plantCrop(() -> cropBlock);
}
private static BiPredicate<LevelAccessor, BlockHitResult> placeBlockOnGround(Supplier<? extends Block> block) {
return (world, ray) -> {
if (world.isClientSide())
return true;
BlockPos hitPos = ray.getBlockPos();
if (world instanceof Level l && !l.isLoaded(hitPos))
return true;
Direction face = ray.getDirection();
BlockPos placePos = hitPos.relative(face);
if (!world.getBlockState(placePos)
.canBeReplaced())
return false;
if (face == Direction.UP) {
world.setBlock(placePos, block.get()
.defaultBlockState(), 3);
} else if (world instanceof Level level) {
double y = ray.getLocation().y - 0.5;
if (!world.isEmptyBlock(placePos.above()))
y = Math.min(y, placePos.getY());
if (!world.isEmptyBlock(placePos.below()))
y = Math.max(y, placePos.getY());
FallingBlockEntity falling = FallingBlockEntityAccessor.create$callInit(level, placePos.getX() + 0.5, y,
placePos.getZ() + 0.5, block.get().defaultBlockState());
falling.time = 1;
world.addFreshEntity(falling);
}
return true;
};
}
private static BiPredicate<LevelAccessor, BlockHitResult> placeBlockOnGround(Block block) {
return placeBlockOnGround(() -> block);
}
private static Predicate<EntityHitResult> chorusTeleport(double teleportDiameter) {
return ray -> {
Entity entity = ray.getEntity();
Level world = entity.getCommandSenderWorld();
if (world.isClientSide)
return true;
if (!(entity instanceof LivingEntity livingEntity))
return false;
double entityX = livingEntity.getX();
double entityY = livingEntity.getY();
double entityZ = livingEntity.getZ();
for (int teleportTry = 0; teleportTry < 16; ++teleportTry) {
double teleportX = entityX + (livingEntity.getRandom()
.nextDouble() - 0.5D) * teleportDiameter;
double teleportY = Mth.clamp(entityY + (livingEntity.getRandom()
.nextInt((int) teleportDiameter) - (int) (teleportDiameter / 2)), 0.0D, world.getHeight() - 1);
double teleportZ = entityZ + (livingEntity.getRandom()
.nextDouble() - 0.5D) * teleportDiameter;
EntityTeleportEvent.ChorusFruit event =
EventHooks.onChorusFruitTeleport(livingEntity, teleportX, teleportY, teleportZ);
if (event.isCanceled())
return false;
if (livingEntity.randomTeleport(event.getTargetX(), event.getTargetY(), event.getTargetZ(), true)) {
if (livingEntity.isPassenger())
livingEntity.stopRiding();
SoundEvent soundevent =
livingEntity instanceof Fox ? SoundEvents.FOX_TELEPORT : SoundEvents.CHORUS_FRUIT_TELEPORT;
world.playSound(null, entityX, entityY, entityZ, soundevent, SoundSource.PLAYERS, 1.0F, 1.0F);
livingEntity.playSound(soundevent, 1.0F, 1.0F);
livingEntity.setDeltaMovement(Vec3.ZERO);
return true;
}
}
return false;
};
}
public static void register() {
}
}

View file

@ -9,8 +9,9 @@ import org.jetbrains.annotations.Nullable;
import com.simibubi.create.AllEnchantments;
import com.simibubi.create.AllEntityTypes;
import com.simibubi.create.Create;
import com.simibubi.create.CreateClient;
import com.simibubi.create.api.equipment.potatoCannon.PotatoCannonProjectileType;
import com.simibubi.create.api.registry.CreateRegistries;
import com.simibubi.create.content.equipment.armor.BacktankUtil;
import com.simibubi.create.content.equipment.zapper.ShootableGadgetItemMethods;
import com.simibubi.create.foundation.item.CustomArmPoseItem;
@ -55,6 +56,7 @@ import net.minecraft.world.phys.Vec3;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.api.distmarker.OnlyIn;
import net.neoforged.neoforge.client.extensions.common.IClientItemExtensions;
import net.neoforged.neoforge.server.ServerLifecycleHooks;
public class PotatoCannonItem extends ProjectileWeaponItem implements CustomArmPoseItem {
@ -120,14 +122,13 @@ public class PotatoCannonItem extends ProjectileWeaponItem implements CustomArmP
protected void shoot(ServerLevel level, LivingEntity shooter, InteractionHand hand, ItemStack weapon, List<ItemStack> projectileItems, float velocity, float inaccuracy, boolean isCrit, @Nullable LivingEntity target) {}
@Override
public InteractionResultHolder<ItemStack> use(Level world, Player player, InteractionHand hand) {
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
ItemStack stack = player.getItemInHand(hand);
return findAmmoInInventory(world, player, stack).map(ammoIn -> {
return findAmmoInInventory(level, player, stack).map(ammoIn -> {
if (ShootableGadgetItemMethods.shouldSwap(player, stack, hand, this::isCannon))
return InteractionResultHolder.fail(stack);
if (world.isClientSide) {
if (level.isClientSide) {
CreateClient.POTATO_CANNON_RENDER_HANDLER.dontAnimateItem(hand);
return InteractionResultHolder.success(stack);
}
@ -140,28 +141,33 @@ public class PotatoCannonItem extends ProjectileWeaponItem implements CustomArmP
.add(0, player.getEyeHeight(), 0));
ItemStack itemStack = ammoIn.copy();
PotatoCannonProjectileType projectileType = PotatoProjectileTypeManager.getTypeForStack(itemStack)
.orElse(BuiltinPotatoProjectileTypes.FALLBACK);
PotatoCannonProjectileType projectileType = PotatoCannonProjectileType.getTypeForStack(level, itemStack)
.orElseGet(() ->
level.registryAccess()
.lookupOrThrow(CreateRegistries.POTATO_PROJECTILE_TYPE)
.getOrThrow(AllPotatoProjectileTypes.FALLBACK)
.value()
);
Vec3 lookVec = player.getLookAngle();
Vec3 motion = lookVec.add(correction)
.normalize()
.scale(2)
.scale(projectileType.getVelocityMultiplier());
.scale(projectileType.velocityMultiplier());
float soundPitch = projectileType.getSoundPitch() + (Create.RANDOM.nextFloat() - .5f) / 4f;
float soundPitch = projectileType.soundPitch() + (level.getRandom().nextFloat() - .5f) / 4f;
boolean spray = projectileType.getSplit() > 1;
Vec3 sprayBase = VecHelper.rotate(new Vec3(0, 0.1, 0), 360 * Create.RANDOM.nextFloat(), Axis.Z);
float sprayChange = 360f / projectileType.getSplit();
boolean spray = projectileType.split() > 1;
Vec3 sprayBase = VecHelper.rotate(new Vec3(0, 0.1, 0), 360 * level.getRandom().nextFloat(), Axis.Z);
float sprayChange = 360f / projectileType.split();
for (int i = 0; i < projectileType.getSplit(); i++) {
PotatoProjectileEntity projectile = AllEntityTypes.POTATO_PROJECTILE.create(world);
for (int i = 0; i < projectileType.split(); i++) {
PotatoProjectileEntity projectile = AllEntityTypes.POTATO_PROJECTILE.create(level);
projectile.setItem(itemStack);
projectile.setEnchantmentEffectsFromCannon(stack);
Vec3 splitMotion = motion;
if (spray) {
float imperfection = 40 * (Create.RANDOM.nextFloat() - 0.5f);
float imperfection = 40 * (level.getRandom().nextFloat() - 0.5f);
Vec3 sprayOffset = VecHelper.rotate(sprayBase, i * sprayChange + imperfection, Axis.Z);
splitMotion = splitMotion.add(VecHelper.lookAt(sprayOffset, motion));
}
@ -172,7 +178,7 @@ public class PotatoCannonItem extends ProjectileWeaponItem implements CustomArmP
projectile.setPos(barrelPos.x, barrelPos.y, barrelPos.z);
projectile.setDeltaMovement(splitMotion);
projectile.setOwner(player);
world.addFreshEntity(projectile);
level.addFreshEntity(projectile);
}
if (!player.isCreative()) {
@ -185,8 +191,8 @@ public class PotatoCannonItem extends ProjectileWeaponItem implements CustomArmP
stack.hurtAndBreak(1, player, LivingEntity.getSlotForHand(hand));
Integer cooldown =
findAmmoInInventory(world, player, stack).flatMap(PotatoProjectileTypeManager::getTypeForStack)
.map(PotatoCannonProjectileType::getReloadTicks)
findAmmoInInventory(level, player, stack).flatMap(i -> PotatoCannonProjectileType.getTypeForStack(level, i))
.map(potatoCannonProjectileType -> potatoCannonProjectileType.reloadTicks())
.orElse(10);
ShootableGadgetItemMethods.applyCooldown(player, stack, hand, this::isCannon, cooldown);
@ -202,9 +208,9 @@ public class PotatoCannonItem extends ProjectileWeaponItem implements CustomArmP
return slotChanged || newStack.getItem() != oldStack.getItem();
}
private Optional<ItemStack> findAmmoInInventory(Level world, Player player, ItemStack held) {
private Optional<ItemStack> findAmmoInInventory(Level level, Player player, ItemStack held) {
ItemStack findAmmo = player.getProjectile(held);
return PotatoProjectileTypeManager.getTypeForStack(findAmmo)
return PotatoCannonProjectileType.getTypeForStack(level, findAmmo)
.map($ -> findAmmo);
}
@ -219,7 +225,7 @@ public class PotatoCannonItem extends ProjectileWeaponItem implements CustomArmP
if (player == null)
return Optional.empty();
ItemStack findAmmo = player.getProjectile(cannon);
Optional<ItemStack> found = PotatoProjectileTypeManager.getTypeForStack(findAmmo)
Optional<ItemStack> found = PotatoCannonProjectileType.getTypeForStack(Minecraft.getInstance().level, findAmmo)
.map($ -> findAmmo);
found.ifPresent(stack -> CLIENT_CURRENT_AMMO = stack);
return found;
@ -243,33 +249,33 @@ public class PotatoCannonItem extends ProjectileWeaponItem implements CustomArmP
tooltip.add(CommonComponents.EMPTY);
tooltip.add(Component.translatable(ammo.getDescriptionId()).append(Component.literal(":"))
.withStyle(ChatFormatting.GRAY));
PotatoCannonProjectileType type = PotatoProjectileTypeManager.getTypeForStack(ammo)
.get();
.withStyle(ChatFormatting.GRAY));
PotatoCannonProjectileType type = PotatoCannonProjectileType.getTypeForStack(Minecraft.getInstance().level, ammo)
.get();
MutableComponent spacing = CommonComponents.space();
ChatFormatting green = ChatFormatting.GREEN;
ChatFormatting darkGreen = ChatFormatting.DARK_GREEN;
float damageF = type.getDamage() * additionalDamageMult;
float damageF = type.damage() * additionalDamageMult;
MutableComponent damage = Component.literal(
damageF == Mth.floor(damageF) ? "" + Mth.floor(damageF) : "" + damageF);
MutableComponent reloadTicks = Component.literal("" + type.getReloadTicks());
damageF == Mth.floor(damageF) ? "" + Mth.floor(damageF) : "" + damageF);
MutableComponent reloadTicks = Component.literal("" + type.reloadTicks());
MutableComponent knockback =
Component.literal("" + (type.getKnockback() + additionalKnockback));
Component.literal("" + (type.knockback() + additionalKnockback));
damage = damage.withStyle(additionalDamageMult > 1 ? green : darkGreen);
knockback = knockback.withStyle(additionalKnockback > 0 ? green : darkGreen);
reloadTicks = reloadTicks.withStyle(darkGreen);
tooltip.add(spacing.plainCopy()
.append(CreateLang.translateDirect(_attack, damage)
.withStyle(darkGreen)));
.append(CreateLang.translateDirect(_attack, damage)
.withStyle(darkGreen)));
tooltip.add(spacing.plainCopy()
.append(CreateLang.translateDirect(_reload, reloadTicks)
.withStyle(darkGreen)));
.append(CreateLang.translateDirect(_reload, reloadTicks)
.withStyle(darkGreen)));
tooltip.add(spacing.plainCopy()
.append(CreateLang.translateDirect(_knockback, knockback)
.withStyle(darkGreen)));
.append(CreateLang.translateDirect(_knockback, knockback)
.withStyle(darkGreen)));
});
}
super.appendHoverText(stack, context, tooltip, flag);
@ -277,12 +283,13 @@ public class PotatoCannonItem extends ProjectileWeaponItem implements CustomArmP
@Override
public Predicate<ItemStack> getAllSupportedProjectiles() {
return stack -> PotatoProjectileTypeManager.getTypeForStack(stack)
Level level = ServerLifecycleHooks.getCurrentServer().getLevel(Level.OVERWORLD);
return stack -> PotatoCannonProjectileType.getTypeForStack(level, stack)
.isPresent();
}
@Override
public boolean onEntitySwing(ItemStack stack, LivingEntity entity) {
public boolean onEntitySwing(ItemStack stack, LivingEntity entity, InteractionHand hand) {
return true;
}

View file

@ -2,6 +2,7 @@ package com.simibubi.create.content.equipment.potatoCannon;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
import com.simibubi.create.AllItems;
import com.simibubi.create.Create;
import com.simibubi.create.CreateClient;
import com.simibubi.create.foundation.item.render.CustomRenderedItemModel;
@ -27,7 +28,7 @@ public class PotatoCannonItemRenderer extends CustomRenderedItemModelRenderer {
@Override
protected void render(ItemStack stack, CustomRenderedItemModel model, PartialItemModelRenderer renderer,
ItemDisplayContext transformType, PoseStack ms, MultiBufferSource buffer, int light, int overlay) {
ItemDisplayContext transformType, PoseStack ms, MultiBufferSource buffer, int light, int overlay) {
Minecraft mc = Minecraft.getInstance();
ItemRenderer itemRenderer = mc.getItemRenderer();
renderer.render(model.getOriginalModel(), light);
@ -54,18 +55,18 @@ public class PotatoCannonItemRenderer extends CustomRenderedItemModelRenderer {
ms.popPose();
if (transformType == ItemDisplayContext.GUI) {
PotatoCannonItem.getAmmoforPreview(stack)
.ifPresent(ammo -> {
PoseStack localMs = new PoseStack();
localMs.translate(-1 / 4f, -1 / 4f, 1);
localMs.scale(.5f, .5f, .5f);
TransformStack.of(localMs)
.rotateYDegrees(-34);
itemRenderer.renderStatic(ammo, ItemDisplayContext.GUI, light, OverlayTexture.NO_OVERLAY, localMs,
buffer, mc.level, 0);
});
PotatoCannonItem.getAmmoforPreview(stack).ifPresent(ammo -> {
if (AllItems.POTATO_CANNON.is(ammo)) return;
PoseStack localMs = new PoseStack();
localMs.translate(-1 / 4f, -1 / 4f, 1);
localMs.scale(.5f, .5f, .5f);
TransformStack.of(localMs)
.rotateYDegrees(-34);
itemRenderer.renderStatic(ammo, ItemDisplayContext.GUI, light, OverlayTexture.NO_OVERLAY, localMs,
buffer, mc.level, 0);
});
}
}
}

View file

@ -1,265 +0,0 @@
package com.simibubi.create.content.equipment.potatoCannon;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.createmod.catnip.codecs.stream.CatnipLargerStreamCodecs;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.EntityHitResult;
public class PotatoCannonProjectileType {
public static final Codec<PotatoCannonProjectileType> CODEC = RecordCodecBuilder.create(i -> i.group(
BuiltInRegistries.ITEM.byNameCodec().listOf().fieldOf("items").forGetter(p -> p.getItems()),
Codec.INT.optionalFieldOf("reload_ticks").forGetter(p -> Optional.of(p.getReloadTicks())),
Codec.INT.optionalFieldOf("damage").forGetter(p -> Optional.of(p.getDamage())),
Codec.INT.optionalFieldOf("split").forGetter(p -> Optional.of(p.getSplit())),
Codec.FLOAT.optionalFieldOf("knockback").forGetter(p -> Optional.of(p.getKnockback())),
Codec.FLOAT.optionalFieldOf("drag").forGetter(p -> Optional.of(p.getDrag())),
Codec.FLOAT.optionalFieldOf("velocity_multiplier").forGetter(p -> Optional.of(p.getVelocityMultiplier())),
Codec.FLOAT.optionalFieldOf("gravity_multiplier").forGetter(p -> Optional.of(p.getGravityMultiplier())),
Codec.FLOAT.optionalFieldOf("sound_pitch").forGetter(p -> Optional.of(p.getSoundPitch())),
Codec.BOOL.optionalFieldOf("sticky").forGetter(p -> Optional.of(p.isSticky()))
).apply(i, (items, reloadTicks, damage, split, knockback, drag, velocityMultiplier, gravityMultiplier, soundPitch, sticky) -> {
PotatoCannonProjectileType type = new PotatoCannonProjectileType();
type.items.addAll(items);
reloadTicks.ifPresent(r -> type.reloadTicks = r);
damage.ifPresent(r -> type.damage = r);
split.ifPresent(r -> type.split = r);
knockback.ifPresent(r -> type.knockback = r);
drag.ifPresent(r -> type.drag = r);
velocityMultiplier.ifPresent(r -> type.velocityMultiplier = r);
gravityMultiplier.ifPresent(r -> type.gravityMultiplier = r);
soundPitch.ifPresent(r -> type.soundPitch = r);
sticky.ifPresent(r -> type.sticky = r);
return type;
}));
public static final StreamCodec<RegistryFriendlyByteBuf, PotatoCannonProjectileType> STREAM_CODEC = CatnipLargerStreamCodecs.composite(
ByteBufCodecs.registry(Registries.ITEM).apply(ByteBufCodecs.list()), t -> t.items,
ByteBufCodecs.INT, PotatoCannonProjectileType::getReloadTicks,
ByteBufCodecs.INT, PotatoCannonProjectileType::getDamage,
ByteBufCodecs.INT, PotatoCannonProjectileType::getSplit,
ByteBufCodecs.FLOAT, PotatoCannonProjectileType::getKnockback,
ByteBufCodecs.FLOAT, PotatoCannonProjectileType::getDrag,
ByteBufCodecs.FLOAT, PotatoCannonProjectileType::getVelocityMultiplier,
ByteBufCodecs.FLOAT, PotatoCannonProjectileType::getGravityMultiplier,
ByteBufCodecs.FLOAT, PotatoCannonProjectileType::getSoundPitch,
ByteBufCodecs.BOOL, PotatoCannonProjectileType::isSticky,
PotatoCannonProjectileType::new
);
private List<Item> items = new ArrayList<>();
private int reloadTicks = 10;
private int damage = 1;
private int split = 1;
private float knockback = 1;
private float drag = 0.99f;
private float velocityMultiplier = 1;
private float gravityMultiplier = 1;
private float soundPitch = 1;
private boolean sticky = false;
private PotatoProjectileRenderMode renderMode = PotatoProjectileRenderMode.Billboard.INSTANCE;
private Predicate<EntityHitResult> preEntityHit = e -> false; // True if hit should be canceled
private Predicate<EntityHitResult> onEntityHit = e -> false; // True if shouldn't recover projectile
private BiPredicate<LevelAccessor, BlockHitResult> onBlockHit = (w, ray) -> false;
protected PotatoCannonProjectileType() {}
public PotatoCannonProjectileType(List<Item> items, int reloadTicks, int damage, int split, float knockback,
float drag, float velocityMultiplier, float gravityMultiplier, float soundPitch,
boolean sticky) {
this.items = items;
this.reloadTicks = reloadTicks;
this.damage = damage;
this.split = split;
this.knockback = knockback;
this.drag = drag;
this.velocityMultiplier = velocityMultiplier;
this.gravityMultiplier = gravityMultiplier;
this.soundPitch = soundPitch;
this.sticky = sticky;
}
public List<Item> getItems() {
return items;
}
public int getReloadTicks() {
return reloadTicks;
}
public int getDamage() {
return damage;
}
public int getSplit() {
return split;
}
public float getKnockback() {
return knockback;
}
public float getDrag() {
return drag;
}
public float getVelocityMultiplier() {
return velocityMultiplier;
}
public float getGravityMultiplier() {
return gravityMultiplier;
}
public float getSoundPitch() {
return soundPitch;
}
public boolean isSticky() {
return sticky;
}
public PotatoProjectileRenderMode getRenderMode() {
return renderMode;
}
public boolean preEntityHit(EntityHitResult ray) {
return preEntityHit.test(ray);
}
public boolean onEntityHit(EntityHitResult ray) {
return onEntityHit.test(ray);
}
public boolean onBlockHit(LevelAccessor world, BlockHitResult ray) {
return onBlockHit.test(world, ray);
}
public static class Builder {
protected ResourceLocation id;
protected PotatoCannonProjectileType result;
public Builder(ResourceLocation id) {
this.id = id;
this.result = new PotatoCannonProjectileType();
}
public Builder reloadTicks(int reload) {
result.reloadTicks = reload;
return this;
}
public Builder damage(int damage) {
result.damage = damage;
return this;
}
public Builder splitInto(int split) {
result.split = split;
return this;
}
public Builder knockback(float knockback) {
result.knockback = knockback;
return this;
}
public Builder drag(float drag) {
result.drag = drag;
return this;
}
public Builder velocity(float velocity) {
result.velocityMultiplier = velocity;
return this;
}
public Builder gravity(float modifier) {
result.gravityMultiplier = modifier;
return this;
}
public Builder soundPitch(float pitch) {
result.soundPitch = pitch;
return this;
}
public Builder sticky() {
result.sticky = true;
return this;
}
public Builder renderMode(PotatoProjectileRenderMode renderMode) {
result.renderMode = renderMode;
return this;
}
public Builder renderBillboard() {
renderMode(PotatoProjectileRenderMode.Billboard.INSTANCE);
return this;
}
public Builder renderTumbling() {
renderMode(PotatoProjectileRenderMode.Tumble.INSTANCE);
return this;
}
public Builder renderTowardMotion(int spriteAngle, float spin) {
renderMode(new PotatoProjectileRenderMode.TowardMotion(spriteAngle, spin));
return this;
}
public Builder preEntityHit(Predicate<EntityHitResult> callback) {
result.preEntityHit = callback;
return this;
}
public Builder onEntityHit(Predicate<EntityHitResult> callback) {
result.onEntityHit = callback;
return this;
}
public Builder onBlockHit(BiPredicate<LevelAccessor, BlockHitResult> callback) {
result.onBlockHit = callback;
return this;
}
public Builder addItems(ItemLike... items) {
for (ItemLike provider : items)
result.items.add(provider.asItem());
return this;
}
public PotatoCannonProjectileType register() {
PotatoProjectileTypeManager.registerBuiltinType(id, result);
return result;
}
public PotatoCannonProjectileType registerAndAssign(ItemLike... items) {
addItems(items);
register();
return result;
}
}
}

View file

@ -4,6 +4,9 @@ import org.jetbrains.annotations.NotNull;
import com.simibubi.create.AllEnchantments;
import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.api.equipment.potatoCannon.PotatoCannonProjectileType;
import com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileRenderMode;
import com.simibubi.create.api.registry.CreateRegistries;
import com.simibubi.create.foundation.advancement.AllAdvancements;
import com.simibubi.create.foundation.damageTypes.CreateDamageSources;
import com.simibubi.create.foundation.particle.AirParticleData;
@ -67,8 +70,13 @@ public class PotatoProjectileEntity extends AbstractHurtingProjectile implements
public PotatoCannonProjectileType getProjectileType() {
if (type == null)
type = PotatoProjectileTypeManager.getTypeForStack(stack)
.orElse(BuiltinPotatoProjectileTypes.FALLBACK);
type = PotatoCannonProjectileType.getTypeForStack(level(), stack)
.orElseGet(() ->
level().registryAccess()
.lookupOrThrow(CreateRegistries.POTATO_PROJECTILE_TYPE)
.getOrThrow(AllPotatoProjectileTypes.FALLBACK)
.value()
);
return type;
}
@ -119,7 +127,7 @@ public class PotatoProjectileEntity extends AbstractHurtingProjectile implements
if (getStuckEntity() != null)
return stuckRenderer;
return getProjectileType().getRenderMode();
return getProjectileType().renderMode();
}
public void tick() {
@ -131,15 +139,15 @@ public class PotatoProjectileEntity extends AbstractHurtingProjectile implements
pop(position());
kill();
} else {
stuckFallSpeed += 0.007 * projectileType.getGravityMultiplier();
stuckFallSpeed += 0.007 * projectileType.gravityMultiplier();
stuckOffset = stuckOffset.add(0, -stuckFallSpeed, 0);
Vec3 pos = stuckEntity.position()
.add(stuckOffset);
setPos(pos.x, pos.y, pos.z);
}
} else {
setDeltaMovement(getDeltaMovement().add(0, -0.05 * projectileType.getGravityMultiplier(), 0)
.scale(projectileType.getDrag()));
setDeltaMovement(getDeltaMovement().add(0, -0.05 * projectileType.gravityMultiplier(), 0)
.scale(projectileType.drag()));
}
super.tick();
@ -170,8 +178,8 @@ public class PotatoProjectileEntity extends AbstractHurtingProjectile implements
Vec3 hit = ray.getLocation();
Entity target = ray.getEntity();
PotatoCannonProjectileType projectileType = getProjectileType();
float damage = projectileType.getDamage() * additionalDamageMult;
float knockback = projectileType.getKnockback() + additionalKnockback;
float damage = projectileType.damage() * additionalDamageMult;
float knockback = projectileType.knockback() + additionalKnockback;
Entity owner = this.getOwner();
if (!target.isAlive())
@ -194,7 +202,7 @@ public class PotatoProjectileEntity extends AbstractHurtingProjectile implements
if (target instanceof WitherBoss && ((WitherBoss) target).isPowered())
return;
if (projectileType.preEntityHit(ray))
if (projectileType.preEntityHit(stack, ray))
return;
boolean targetIsEnderman = target.getType() == EntityType.ENDERMAN;
@ -213,9 +221,12 @@ public class PotatoProjectileEntity extends AbstractHurtingProjectile implements
if (targetIsEnderman)
return;
if (!projectileType.onEntityHit(ray) && onServer)
if (random.nextDouble() <= recoveryChance)
if (!projectileType.onEntityHit(stack, ray) && onServer)
if (random.nextDouble() <= recoveryChance) {
recoverItem();
} else {
spawnAtLocation(projectileType.dropStack());
}
if (!(target instanceof LivingEntity livingentity)) {
playHitSound(level(), position());
@ -223,8 +234,8 @@ public class PotatoProjectileEntity extends AbstractHurtingProjectile implements
return;
}
if (type.getReloadTicks() < 10)
livingentity.invulnerableTime = type.getReloadTicks() + 10;
if (type.reloadTicks() < 10)
livingentity.invulnerableTime = type.reloadTicks() + 10;
if (onServer && knockback > 0) {
Vec3 appliedMotion = this.getDeltaMovement()
@ -251,7 +262,7 @@ public class PotatoProjectileEntity extends AbstractHurtingProjectile implements
AllAdvancements.POTATO_CANNON.awardTo(serverplayerentity);
}
if (type.isSticky() && target.isAlive()) {
if (type.sticky() && target.isAlive()) {
setStuckEntity(target);
} else {
kill();
@ -276,7 +287,7 @@ public class PotatoProjectileEntity extends AbstractHurtingProjectile implements
protected void onHitBlock(BlockHitResult ray) {
Vec3 hit = ray.getLocation();
pop(hit);
if (!getProjectileType().onBlockHit(level(), ray) && !level().isClientSide)
if (!getProjectileType().onBlockHit(level(), stack, ray) && !level().isClientSide)
if (random.nextDouble() <= recoveryChance)
recoverItem();
super.onHitBlock(ray);

View file

@ -1,145 +0,0 @@
package com.simibubi.create.content.equipment.potatoCannon;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.mojang.serialization.JsonOps;
import com.simibubi.create.AllItems;
import com.simibubi.create.AllPackets;
import net.createmod.catnip.net.base.ClientboundPacketPayload;
import net.createmod.catnip.platform.CatnipServices;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.api.distmarker.OnlyIn;
public class PotatoProjectileTypeManager {
private static final Map<ResourceLocation, PotatoCannonProjectileType> BUILTIN_TYPE_MAP = new HashMap<>();
private static final Map<ResourceLocation, PotatoCannonProjectileType> CUSTOM_TYPE_MAP = new HashMap<>();
private static final Map<Item, PotatoCannonProjectileType> ITEM_TO_TYPE_MAP = new IdentityHashMap<>();
public static void registerBuiltinType(ResourceLocation id, PotatoCannonProjectileType type) {
synchronized (BUILTIN_TYPE_MAP) {
BUILTIN_TYPE_MAP.put(id, type);
}
}
public static PotatoCannonProjectileType getBuiltinType(ResourceLocation id) {
return BUILTIN_TYPE_MAP.get(id);
}
public static PotatoCannonProjectileType getCustomType(ResourceLocation id) {
return CUSTOM_TYPE_MAP.get(id);
}
public static PotatoCannonProjectileType getTypeForItem(Item item) {
return ITEM_TO_TYPE_MAP.get(item);
}
public static Set<Item> getItems() {
return ITEM_TO_TYPE_MAP.keySet();
}
public static Optional<PotatoCannonProjectileType> getTypeForStack(ItemStack item) {
if (item.isEmpty())
return Optional.empty();
return Optional.ofNullable(getTypeForItem(item.getItem()));
}
public static void clear() {
CUSTOM_TYPE_MAP.clear();
ITEM_TO_TYPE_MAP.clear();
}
public static void fillItemMap() {
for (Map.Entry<ResourceLocation, PotatoCannonProjectileType> entry : BUILTIN_TYPE_MAP.entrySet()) {
PotatoCannonProjectileType type = entry.getValue();
for (Item item : type.getItems()) {
ITEM_TO_TYPE_MAP.put(item, type);
}
}
for (Map.Entry<ResourceLocation, PotatoCannonProjectileType> entry : CUSTOM_TYPE_MAP.entrySet()) {
PotatoCannonProjectileType type = entry.getValue();
for (Item item : type.getItems()) {
ITEM_TO_TYPE_MAP.put(item, type);
}
}
ITEM_TO_TYPE_MAP.remove(AllItems.POTATO_CANNON.get());
}
public static void syncTo(ServerPlayer player) {
CatnipServices.NETWORK.sendToClient(player, new SyncPacket(CUSTOM_TYPE_MAP));
}
public static void syncToAll() {
CatnipServices.NETWORK.sendToAllClients(new SyncPacket(CUSTOM_TYPE_MAP));
}
public static class ReloadListener extends SimpleJsonResourceReloadListener {
private static final Gson GSON = new Gson();
public static final ReloadListener INSTANCE = new ReloadListener();
protected ReloadListener() {
super(GSON, "potato_cannon_projectile_types");
}
@Override
protected void apply(Map<ResourceLocation, JsonElement> map, ResourceManager resourceManager, ProfilerFiller profiler) {
clear();
for (Map.Entry<ResourceLocation, JsonElement> entry : map.entrySet()) {
PotatoCannonProjectileType.CODEC.decode(JsonOps.INSTANCE, entry.getValue()).result().ifPresent(p -> {
CUSTOM_TYPE_MAP.put(entry.getKey(), p.getFirst());
});
}
fillItemMap();
}
}
public record SyncPacket(Map<ResourceLocation, PotatoCannonProjectileType> customTypes) implements ClientboundPacketPayload {
public static final StreamCodec<RegistryFriendlyByteBuf, SyncPacket> STREAM_CODEC = ByteBufCodecs.map(
SyncPacket::newMap, ResourceLocation.STREAM_CODEC, PotatoCannonProjectileType.STREAM_CODEC
).map(SyncPacket::new, SyncPacket::customTypes);
@Override
@OnlyIn(Dist.CLIENT)
public void handle(LocalPlayer player) {
clear();
CUSTOM_TYPE_MAP.putAll(customTypes);
fillItemMap();
}
@Override
public PacketTypeProvider getTypeProvider() {
return AllPackets.SYNC_POTATO_PROJECTILE_TYPES;
}
// needed for generics
private static <K, V> Map<K, V> newMap(int size) {
return new HashMap<>(size);
}
}
}

View file

@ -126,7 +126,7 @@ public class ToolboxBlock extends HorizontalDirectionalBlock implements SimpleWa
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighbourState, LevelAccessor world,
BlockPos pos, BlockPos neighbourPos) {
BlockPos pos, BlockPos neighbourPos) {
if (state.getValue(WATERLOGGED))
world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world));
return state;
@ -167,7 +167,7 @@ public class ToolboxBlock extends HorizontalDirectionalBlock implements SimpleWa
FluidState ifluidstate = context.getLevel()
.getFluidState(context.getClickedPos());
return super.getStateForPlacement(context).setValue(FACING, context.getHorizontalDirection()
.getOpposite())
.getOpposite())
.setValue(WATERLOGGED, Boolean.valueOf(ifluidstate.getType() == Fluids.WATER));
}

View file

@ -1,13 +1,12 @@
package com.simibubi.create.content.fluids;
import com.simibubi.create.content.fluids.potion.PotionFluid;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.FluidState;
import net.neoforged.neoforge.fluids.BaseFlowingFluid;
public class VirtualFluid extends BaseFlowingFluid {

View file

@ -11,9 +11,9 @@ import org.jetbrains.annotations.NotNull;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.api.boiler.BoilerHeater;
import com.simibubi.create.api.stress.BlockStressValues;
import com.simibubi.create.content.decoration.steamWhistle.WhistleBlock;
import com.simibubi.create.content.decoration.steamWhistle.WhistleBlockEntity;
import com.simibubi.create.content.kinetics.BlockStressValues;
import com.simibubi.create.content.kinetics.steamEngine.SteamEngineBlock;
import com.simibubi.create.foundation.advancement.AdvancementBehaviour;
import com.simibubi.create.foundation.advancement.AllAdvancements;

View file

@ -1,68 +0,0 @@
package com.simibubi.create.content.kinetics;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import com.tterrag.registrate.builders.BlockBuilder;
import com.tterrag.registrate.util.nullness.NonNullUnaryOperator;
import net.createmod.catnip.data.Couple;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block;
public class BlockStressDefaults {
/**
* Increment this number if all stress entries should be forced to update in the
* next release. Worlds from the previous version will overwrite potentially
* changed values with the new defaults.
*/
public static final int FORCED_UPDATE_VERSION = 2;
public static final Map<ResourceLocation, Double> DEFAULT_IMPACTS = new ConcurrentHashMap<>();
public static final Map<ResourceLocation, Double> DEFAULT_CAPACITIES = new ConcurrentHashMap<>();
public static final Map<ResourceLocation, Supplier<Couple<Integer>>> GENERATOR_SPEEDS = new ConcurrentHashMap<>();
public static void setDefaultImpact(ResourceLocation blockId, double impact) {
DEFAULT_IMPACTS.put(blockId, impact);
}
public static void setDefaultCapacity(ResourceLocation blockId, double capacity) {
DEFAULT_CAPACITIES.put(blockId, capacity);
}
public static void setGeneratorSpeed(ResourceLocation blockId, Supplier<Couple<Integer>> provider) {
GENERATOR_SPEEDS.put(blockId, provider);
}
public static <B extends Block, P> NonNullUnaryOperator<BlockBuilder<B, P>> setNoImpact() {
return setImpact(0);
}
public static <B extends Block, P> NonNullUnaryOperator<BlockBuilder<B, P>> setImpact(double impact) {
return b -> {
setDefaultImpact(ResourceLocation.fromNamespaceAndPath(b.getOwner()
.getModid(), b.getName()), impact);
return b;
};
}
public static <B extends Block, P> NonNullUnaryOperator<BlockBuilder<B, P>> setCapacity(double capacity) {
return b -> {
setDefaultCapacity(ResourceLocation.fromNamespaceAndPath(b.getOwner()
.getModid(), b.getName()), capacity);
return b;
};
}
public static <B extends Block, P> NonNullUnaryOperator<BlockBuilder<B, P>> setGeneratorSpeed(
Supplier<Couple<Integer>> provider) {
return b -> {
setGeneratorSpeed(ResourceLocation.fromNamespaceAndPath(b.getOwner()
.getModid(), b.getName()), provider);
return b;
};
}
}

View file

@ -1,116 +0,0 @@
package com.simibubi.create.content.kinetics;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
import net.createmod.catnip.data.Couple;
import net.createmod.catnip.registry.RegisteredObjectsHelper;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block;
public class BlockStressValues {
private static final Map<String, IStressValueProvider> PROVIDERS = new HashMap<>();
public static void registerProvider(String namespace, IStressValueProvider provider) {
PROVIDERS.put(namespace, provider);
}
@Nullable
public static IStressValueProvider getProvider(String namespace) {
return PROVIDERS.get(namespace);
}
@Nullable
public static IStressValueProvider getProvider(Block block) {
return getProvider(RegisteredObjectsHelper.getKeyOrThrow(block)
.getNamespace());
}
public static double getImpact(Block block) {
ResourceLocation blockId = RegisteredObjectsHelper.getKeyOrThrow(block);
IStressValueProvider provider = getProvider(blockId.getNamespace());
if (provider != null) {
return provider.getImpact(block);
}
Double defaultImpact = BlockStressDefaults.DEFAULT_IMPACTS.get(blockId);
if (defaultImpact != null) {
return defaultImpact;
}
return 0;
}
public static double getCapacity(Block block) {
ResourceLocation blockId = RegisteredObjectsHelper.getKeyOrThrow(block);
IStressValueProvider provider = getProvider(blockId.getNamespace());
if (provider != null) {
return provider.getCapacity(block);
}
Double defaultCapacity = BlockStressDefaults.DEFAULT_CAPACITIES.get(blockId);
if (defaultCapacity != null) {
return defaultCapacity;
}
return 0;
}
public static boolean hasImpact(Block block) {
ResourceLocation blockId = RegisteredObjectsHelper.getKeyOrThrow(block);
IStressValueProvider provider = getProvider(blockId.getNamespace());
if (provider != null) {
return provider.hasImpact(block);
}
return BlockStressDefaults.DEFAULT_IMPACTS.containsKey(blockId);
}
public static boolean hasCapacity(Block block) {
ResourceLocation blockId = RegisteredObjectsHelper.getKeyOrThrow(block);
IStressValueProvider provider = getProvider(blockId.getNamespace());
if (provider != null) {
return provider.hasCapacity(block);
}
return BlockStressDefaults.DEFAULT_CAPACITIES.containsKey(blockId);
}
@Nullable
public static Couple<Integer> getGeneratedRPM(Block block) {
ResourceLocation blockId = RegisteredObjectsHelper.getKeyOrThrow(block);
IStressValueProvider provider = getProvider(blockId.getNamespace());
if (provider != null) {
return provider.getGeneratedRPM(block);
}
return null;
}
public interface IStressValueProvider {
/**
* Gets the stress impact of a block.
*
* @param block The block.
* @return the stress impact value of the block, or 0 if it does not have one.
*/
double getImpact(Block block);
/**
* Gets the stress capacity of a block.
*
* @param block The block.
* @return the stress capacity value of the block, or 0 if it does not have one.
*/
double getCapacity(Block block);
boolean hasImpact(Block block);
boolean hasCapacity(Block block);
/**
*
* @param block
* @return min, max generated RPM; null if block does not have a stress capacity
*/
@Nullable
Couple<Integer> getGeneratedRPM(Block block);
}
}

View file

@ -11,7 +11,7 @@ import javax.annotation.Nullable;
import com.simibubi.create.Create;
import com.simibubi.create.api.equipment.goggles.IHaveGoggleInformation;
import com.simibubi.create.api.equipment.goggles.IHaveHoveringInformation;
import com.simibubi.create.content.kinetics.BlockStressValues;
import com.simibubi.create.api.stress.BlockStressValues;
import com.simibubi.create.content.kinetics.KineticNetwork;
import com.simibubi.create.content.kinetics.RotationPropagator;
import com.simibubi.create.content.kinetics.base.IRotate.SpeedLevel;

View file

@ -19,14 +19,13 @@ import dev.engine_room.flywheel.lib.visualization.SimpleBlockEntityVisualizer;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.AxisDirection;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.Property;
public class OrientedRotatingVisual<T extends KineticBlockEntity> extends KineticBlockEntityVisual<T> {
protected final RotatingInstance rotatingModel;
/**
* @param from The source model orientation to rotate away from.
* @param to The orientation to rotate to.
* @param from The source model orientation to rotate away from.
* @param to The orientation to rotate to.
* @param model The model to spin.
*/
public OrientedRotatingVisual(VisualizationContext context, T blockEntity, float partialTick, Direction from, Direction to, Model model) {

View file

@ -9,7 +9,6 @@ import com.simibubi.create.foundation.block.IBE;
import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
import com.simibubi.create.infrastructure.config.AllConfigs;
import net.createmod.catnip.data.Couple;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
@ -149,9 +148,4 @@ public class HandCrankBlock extends DirectionalKineticBlock
protected boolean isPathfindable(BlockState state, PathComputationType pathComputationType) {
return false;
}
public static Couple<Integer> getSpeedRange() {
return Couple.create(32, 32);
}
}

View file

@ -8,7 +8,6 @@ import com.simibubi.create.AllItems;
import com.simibubi.create.AllShapes;
import com.simibubi.create.foundation.utility.BlockHelper;
import net.createmod.catnip.data.Couple;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
@ -23,6 +22,7 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.neoforged.bus.api.EventPriority;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
@ -33,7 +33,7 @@ import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent;
public class ValveHandleBlock extends HandCrankBlock {
public final DyeColor color;
public static ValveHandleBlock copper(Properties properties) {
return new ValveHandleBlock(properties, null);
}
@ -111,9 +111,4 @@ public class ValveHandleBlock extends HandCrankBlock {
public int getRotationSpeed() {
return 32;
}
public static Couple<Integer> getSpeedRange() {
return Couple.create(32, 32);
}
}

View file

@ -16,10 +16,9 @@ import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsFormatt
import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollValueBehaviour;
import com.simibubi.create.foundation.utility.CreateLang;
import net.createmod.catnip.math.VecHelper;
import net.createmod.catnip.render.CachedBuffers;
import net.createmod.catnip.render.SuperByteBuffer;
import net.createmod.catnip.math.VecHelper;
import net.createmod.ponder.render.VirtualRenderHelper;
import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
@ -102,7 +101,7 @@ public class ValveHandleBlockEntity extends HandCrankBlockEntity {
return (inUse > 0 && totalUseTicks > 0
? Mth.lerp(Math.min(totalUseTicks, totalUseTicks - inUse + partialTicks) / (float) totalUseTicks,
startAngle, targetAngle)
startAngle, targetAngle)
: targetAngle) * Mth.DEG_TO_RAD * (backwards ? -1 : 1) * step;
}
@ -139,7 +138,8 @@ public class ValveHandleBlockEntity extends HandCrankBlockEntity {
}
@Override
protected void copySequenceContextFrom(KineticBlockEntity sourceBE) {}
protected void copySequenceContextFrom(KineticBlockEntity sourceBE) {
}
@Override
@OnlyIn(Dist.CLIENT)
@ -163,8 +163,8 @@ public class ValveHandleBlockEntity extends HandCrankBlockEntity {
@Override
public ValueSettingsBoard createBoard(Player player, BlockHitResult hitResult) {
ImmutableList<Component> rows = ImmutableList.of(Component.literal("\u27f3")
.withStyle(ChatFormatting.BOLD),
ImmutableList<Component> rows = ImmutableList.of(Component.literal("\u27f3")
.withStyle(ChatFormatting.BOLD),
Component.literal("\u27f2")
.withStyle(ChatFormatting.BOLD));
return new ValueSettingsBoard(label, 180, 45, rows, new ValueSettingsFormatter(this::formatValue));

View file

@ -3,8 +3,6 @@ package com.simibubi.create.content.kinetics.drill;
import com.simibubi.create.AllPartialModels;
import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import com.simibubi.create.content.contraptions.render.ActorVisual;
import com.simibubi.create.content.kinetics.base.RotatingInstance;
import com.simibubi.create.foundation.render.AllInstanceTypes;
import com.simibubi.create.foundation.virtualWorld.VirtualRenderWorld;
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
@ -12,30 +10,29 @@ import dev.engine_room.flywheel.lib.instance.InstanceTypes;
import dev.engine_room.flywheel.lib.instance.TransformedInstance;
import dev.engine_room.flywheel.lib.model.Models;
import net.createmod.catnip.animation.AnimationTickHolder;
import net.createmod.catnip.math.VecHelper;
import net.createmod.catnip.math.AngleHelper;
import net.createmod.catnip.math.VecHelper;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;
import net.minecraft.world.level.block.state.BlockState;
public class DrillActorVisual extends ActorVisual {
TransformedInstance drillHead;
private final Direction facing;
TransformedInstance drillHead;
private final Direction facing;
private double rotation;
private double previousRotation;
public DrillActorVisual(VisualizationContext visualizationContext, VirtualRenderWorld contraption, MovementContext context) {
super(visualizationContext, contraption, context);
public DrillActorVisual(VisualizationContext visualizationContext, VirtualRenderWorld contraption, MovementContext context) {
super(visualizationContext, contraption, context);
BlockState state = context.state;
BlockState state = context.state;
facing = state.getValue(DrillBlock.FACING);
facing = state.getValue(DrillBlock.FACING);
drillHead = instancerProvider.instancer(InstanceTypes.TRANSFORMED, Models.partial(AllPartialModels.DRILL_HEAD))
.createInstance();
}
.createInstance();
}
@Override
public void tick() {
@ -53,7 +50,7 @@ public class DrillActorVisual extends ActorVisual {
}
@Override
public void beginFrame() {
public void beginFrame() {
drillHead.setIdentityTransform()
.translate(context.localPos)
.center()
@ -61,7 +58,7 @@ public class DrillActorVisual extends ActorVisual {
.rotateZDegrees((float) getRotation())
.uncenter()
.setChanged();
}
}
protected double getRotation() {
return AngleHelper.angleLerp(AnimationTickHolder.getPartialTicks(), previousRotation, rotation);

View file

@ -10,7 +10,6 @@ import com.simibubi.create.content.kinetics.base.RotatingInstance;
import com.simibubi.create.foundation.render.AllInstanceTypes;
import dev.engine_room.flywheel.api.instance.Instance;
import dev.engine_room.flywheel.api.instance.Instancer;
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
import dev.engine_room.flywheel.lib.instance.AbstractInstance;
import dev.engine_room.flywheel.lib.instance.FlatLit;
@ -18,20 +17,19 @@ import dev.engine_room.flywheel.lib.model.Models;
import net.createmod.catnip.data.Iterate;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
public class GearboxVisual extends KineticBlockEntityVisual<GearboxBlockEntity> {
protected final EnumMap<Direction, RotatingInstance> keys = new EnumMap<>(Direction.class);
protected Direction sourceFacing;
protected final EnumMap<Direction, RotatingInstance> keys = new EnumMap<>(Direction.class);
protected Direction sourceFacing;
public GearboxVisual(VisualizationContext context, GearboxBlockEntity blockEntity, float partialTick) {
super(context, blockEntity, partialTick);
public GearboxVisual(VisualizationContext context, GearboxBlockEntity blockEntity, float partialTick) {
super(context, blockEntity, partialTick);
final Direction.Axis boxAxis = blockState.getValue(BlockStateProperties.AXIS);
updateSourceFacing();
updateSourceFacing();
var instancer = instancerProvider().instancer(AllInstanceTypes.ROTATING, Models.partial(AllPartialModels.SHAFT_HALF));
@ -48,58 +46,58 @@ public class GearboxVisual extends KineticBlockEntityVisual<GearboxBlockEntity>
.rotateToFace(Direction.SOUTH, direction)
.setChanged();
keys.put(direction, instance);
}
}
keys.put(direction, instance);
}
}
private float getSpeed(Direction direction) {
float speed = blockEntity.getSpeed();
private float getSpeed(Direction direction) {
float speed = blockEntity.getSpeed();
if (speed != 0 && sourceFacing != null) {
if (sourceFacing.getAxis() == direction.getAxis())
speed *= sourceFacing == direction ? 1 : -1;
else if (sourceFacing.getAxisDirection() == direction.getAxisDirection())
speed *= -1;
}
return speed;
}
if (speed != 0 && sourceFacing != null) {
if (sourceFacing.getAxis() == direction.getAxis())
speed *= sourceFacing == direction ? 1 : -1;
else if (sourceFacing.getAxisDirection() == direction.getAxisDirection())
speed *= -1;
}
return speed;
}
protected void updateSourceFacing() {
if (blockEntity.hasSource()) {
BlockPos source = blockEntity.source.subtract(pos);
sourceFacing = Direction.getNearest(source.getX(), source.getY(), source.getZ());
} else {
sourceFacing = null;
}
}
protected void updateSourceFacing() {
if (blockEntity.hasSource()) {
BlockPos source = blockEntity.source.subtract(pos);
sourceFacing = Direction.getNearest(source.getX(), source.getY(), source.getZ());
} else {
sourceFacing = null;
}
}
@Override
public void update(float pt) {
updateSourceFacing();
for (Map.Entry<Direction, RotatingInstance> key : keys.entrySet()) {
Direction direction = key.getKey();
Direction.Axis axis = direction.getAxis();
@Override
public void update(float pt) {
updateSourceFacing();
for (Map.Entry<Direction, RotatingInstance> key : keys.entrySet()) {
Direction direction = key.getKey();
Direction.Axis axis = direction.getAxis();
key.getValue()
.setup(blockEntity, axis, getSpeed(direction))
.setChanged();
}
}
}
@Override
public void updateLight(float partialTick) {
relight(keys.values().toArray(FlatLit[]::new));
}
@Override
public void updateLight(float partialTick) {
relight(keys.values().toArray(FlatLit[]::new));
}
@Override
protected void _delete() {
keys.values().forEach(AbstractInstance::delete);
keys.clear();
}
@Override
protected void _delete() {
keys.values().forEach(AbstractInstance::delete);
keys.clear();
}
@Override
public void collectCrumblingInstances(Consumer<Instance> consumer) {
keys.values()
.forEach(consumer);
.forEach(consumer);
}
}

View file

@ -23,7 +23,6 @@ import net.createmod.catnip.data.Iterate;
import net.createmod.catnip.theme.Color;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack;
@ -121,10 +120,10 @@ public class ArmVisual extends SingleAxisRotatingVisual<ArmBlockEntity> implemen
int color = Color.rainbowColor(ticks * 100)
.getRGB();
updateAngles(baseAngle, lowerArmAngle, upperArmAngle, headAngle, color);
}
}
private void animateArm() {
updateAngles(this.baseAngle, this.lowerArmAngle - 135, this.upperArmAngle - 90, this.headAngle, 0xFFFFFF);
updateAngles(this.baseAngle, this.lowerArmAngle - 135, this.upperArmAngle - 90, this.headAngle, 0xFFFFFF);
}
private void updateAngles(float baseAngle, float lowerArmAngle, float upperArmAngle, float headAngle, int color) {
@ -163,7 +162,7 @@ public class ArmVisual extends SingleAxisRotatingVisual<ArmBlockEntity> implemen
boolean hasItem = !item.isEmpty();
boolean isBlockItem = hasItem && (item.getItem() instanceof BlockItem)
&& itemRenderer.getModel(item, Minecraft.getInstance().level, null, 0)
.isGui3d();
.isGui3d();
for (int index : Iterate.zeroAndOne) {
poseStack.pushPose();
@ -182,7 +181,7 @@ public class ArmVisual extends SingleAxisRotatingVisual<ArmBlockEntity> implemen
public void update(float pt) {
super.update(pt);
instancerProvider().instancer(InstanceTypes.TRANSFORMED, Models.partial(blockEntity.goggles ? AllPartialModels.ARM_CLAW_BASE_GOGGLES : AllPartialModels.ARM_CLAW_BASE))
.stealInstance(claw);
.stealInstance(claw);
}
@Override
@ -193,7 +192,7 @@ public class ArmVisual extends SingleAxisRotatingVisual<ArmBlockEntity> implemen
}
@Override
protected void _delete() {
protected void _delete() {
super._delete();
models.forEach(AbstractInstance::delete);
}

View file

@ -5,11 +5,9 @@ import java.util.function.Consumer;
import com.simibubi.create.AllPartialModels;
import com.simibubi.create.content.kinetics.base.RotatingInstance;
import com.simibubi.create.content.kinetics.base.SingleAxisRotatingVisual;
import com.simibubi.create.content.kinetics.simpleRelays.encased.EncasedCogVisual;
import com.simibubi.create.foundation.render.AllInstanceTypes;
import dev.engine_room.flywheel.api.instance.Instance;
import dev.engine_room.flywheel.api.model.Model;
import dev.engine_room.flywheel.api.visual.DynamicVisual;
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
import dev.engine_room.flywheel.lib.instance.InstanceTypes;
@ -34,7 +32,7 @@ public class MixerVisual extends SingleAxisRotatingVisual<MechanicalMixerBlockEn
mixerHead.setRotationAxis(Direction.Axis.Y);
mixerPole = instancerProvider().instancer(InstanceTypes.ORIENTED, Models.partial(AllPartialModels.MECHANICAL_MIXER_POLE))
.createInstance();
.createInstance();
animate(partialTick);
}
@ -55,15 +53,15 @@ public class MixerVisual extends SingleAxisRotatingVisual<MechanicalMixerBlockEn
float speed = mixer.getRenderedHeadRotationSpeed(pt);
mixerHead.setPosition(getVisualPosition())
.nudge(0, -renderedHeadOffset, 0)
.setRotationalSpeed(speed * 2 * RotatingInstance.SPEED_MULTIPLIER)
.setChanged();
.nudge(0, -renderedHeadOffset, 0)
.setRotationalSpeed(speed * 2 * RotatingInstance.SPEED_MULTIPLIER)
.setChanged();
}
private void transformPole(float renderedHeadOffset) {
mixerPole.position(getVisualPosition())
.translatePosition(0, -renderedHeadOffset, 0)
.setChanged();
.translatePosition(0, -renderedHeadOffset, 0)
.setChanged();
}
@Override

View file

@ -4,8 +4,6 @@ import java.util.function.Consumer;
import org.jetbrains.annotations.Nullable;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
import com.simibubi.create.AllPartialModels;
import com.simibubi.create.content.kinetics.base.IRotate;
import com.simibubi.create.content.kinetics.base.KineticBlockEntity;
@ -18,14 +16,10 @@ import dev.engine_room.flywheel.api.instance.Instance;
import dev.engine_room.flywheel.api.model.Model;
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
import dev.engine_room.flywheel.lib.model.Models;
import dev.engine_room.flywheel.lib.model.baked.PartialModel;
import dev.engine_room.flywheel.lib.transform.TransformStack;
import net.createmod.catnip.data.Iterate;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.AxisDirection;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
public class EncasedCogVisual extends KineticBlockEntityVisual<KineticBlockEntity> {

View file

@ -2,7 +2,7 @@ package com.simibubi.create.content.kinetics.steamEngine;
import java.util.List;
import com.simibubi.create.content.kinetics.BlockStressValues;
import com.simibubi.create.api.stress.BlockStressValues;
import com.simibubi.create.content.kinetics.base.GeneratingKineticBlockEntity;
import net.createmod.catnip.nbt.NBTHelper;

View file

@ -16,7 +16,6 @@ import net.createmod.catnip.gui.AbstractSimiScreen;
import net.createmod.catnip.gui.element.GuiGameElement;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.item.ItemStack;
public class SequencedGearshiftScreen extends AbstractSimiScreen {
@ -166,7 +165,7 @@ public class SequencedGearshiftScreen extends AbstractSimiScreen {
if (def.hasValueParameter) {
String text = def.formatValue(instruction.value);
int stringWidth = font.width(text);
label(graphics, 90 + (12 - stringWidth / 2), yOffset - 1, Component.literal(text));
label(graphics, 90 + (12 - stringWidth / 2), yOffset - 1, Component.literal(text));
}
if (def.hasSpeedParameter)
label(graphics, 127, yOffset - 1, instruction.speedModifier.label);
@ -177,9 +176,9 @@ public class SequencedGearshiftScreen extends AbstractSimiScreen {
}
private void renderAdditional(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks, int guiLeft, int guiTop,
AllGuiTextures background) {
AllGuiTextures background) {
GuiGameElement.of(renderedItem).<GuiGameElement
.GuiRenderBuilder>at(guiLeft + background.getWidth() + 6, guiTop + background.getHeight() - 56, 100)
.GuiRenderBuilder>at(guiLeft + background.getWidth() + 6, guiTop + background.getHeight() - 56, 100)
.scale(5)
.render(graphics);
}

View file

@ -5,7 +5,6 @@ import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock;
import com.simibubi.create.foundation.block.IBE;
import net.createmod.catnip.data.Couple;
import net.createmod.catnip.data.Iterate;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
@ -165,10 +164,6 @@ public class LargeWaterWheelBlock extends RotatedPillarKineticBlock implements I
return 2.25f;
}
public static Couple<Integer> getSpeedRange() {
return Couple.create(4, 4);
}
@Override
public boolean isFlammable(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
return false;

View file

@ -5,7 +5,6 @@ import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.kinetics.base.DirectionalKineticBlock;
import com.simibubi.create.foundation.block.IBE;
import net.createmod.catnip.data.Couple;
import net.createmod.catnip.data.Iterate;
import net.createmod.catnip.levelWrappers.WrappedLevel;
import net.minecraft.core.BlockPos;
@ -128,10 +127,6 @@ public class WaterWheelBlock extends DirectionalKineticBlock implements IBE<Wate
return AllBlockEntityTypes.WATER_WHEEL.get();
}
public static Couple<Integer> getSpeedRange() {
return Couple.create(8, 8);
}
@Override
public boolean isFlammable(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
return false;

View file

@ -4,16 +4,18 @@ import java.util.List;
import java.util.function.BiPredicate;
import java.util.function.Function;
import org.jetbrains.annotations.NotNull;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.NotNull;
public final class SingletonItemAttribute implements ItemAttribute {
private final Type type;
private final BiPredicate<ItemStack, Level> predicate;

View file

@ -7,6 +7,9 @@ import java.util.Optional;
import javax.annotation.Nullable;
import net.createmod.catnip.animation.AnimationTickHolder;
import net.createmod.catnip.platform.CatnipServices;
import org.lwjgl.glfw.GLFW;
import com.google.common.collect.ImmutableList;
@ -22,12 +25,10 @@ import com.simibubi.create.foundation.gui.widget.IconButton;
import com.simibubi.create.foundation.gui.widget.ScrollInput;
import com.simibubi.create.foundation.utility.CreateLang;
import net.createmod.catnip.animation.AnimationTickHolder;
import net.createmod.catnip.animation.LerpedFloat;
import net.createmod.catnip.animation.LerpedFloat.Chaser;
import net.createmod.catnip.gui.UIRenderHelper;
import net.createmod.catnip.gui.element.GuiGameElement;
import net.createmod.catnip.platform.CatnipServices;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiGraphics;
@ -93,7 +94,7 @@ public class StockKeeperCategoryScreen extends AbstractSimiContainerScreen<Stock
editorConfirm = new IconButton(leftPos + 36 + 131, topPos + 59, AllIcons.I_CONFIRM);
menu.slotsActive = true;
editorEditBox = new EditBox(font, leftPos + 47, topPos + 28, 124, 10, Component.empty());
editorEditBox = new EditBox(font, leftPos + 47, topPos + 28, 124, 10, Component.empty());
editorEditBox.setTextColor(0xffeeeeee);
editorEditBox.setBordered(false);
editorEditBox.setFocused(false);
@ -101,10 +102,10 @@ public class StockKeeperCategoryScreen extends AbstractSimiContainerScreen<Stock
editorEditBox.setMaxLength(28);
editorEditBox.setValue(index == -1 || schedule.get(index)
.isEmpty() ? CreateLang.translate("gui.stock_ticker.new_category")
.string()
: schedule.get(index)
.getHoverName()
.getString());
.string()
: schedule.get(index)
.getHoverName()
.getString());
editingIndex = index;
editingItem = index == -1 ? ItemStack.EMPTY : schedule.get(index);
@ -208,7 +209,7 @@ public class StockKeeperCategoryScreen extends AbstractSimiContainerScreen<Stock
}
public int renderScheduleEntry(GuiGraphics graphics, int i, ItemStack entry, int yOffset, int mouseX, int mouseY,
float partialTicks) {
float partialTicks) {
int cardWidth = CARD_WIDTH;
int cardHeader = CARD_HEADER;
int cardHeight = cardHeader;
@ -229,11 +230,11 @@ public class StockKeeperCategoryScreen extends AbstractSimiContainerScreen<Stock
entry.isEmpty() ? CreateLang.translate("gui.stock_ticker.empty_category_name_placeholder")
.string()
: entry.getHoverName()
.getString(20)
.stripTrailing()
+ (entry.getHoverName()
.getString()
.length() > 20 ? "..." : ""),
.getString(20)
.stripTrailing()
+ (entry.getHoverName()
.getString()
.length() > 20 ? "..." : ""),
35, 5, 0x656565, false);
matrixStack.popPose();
@ -413,7 +414,7 @@ public class StockKeeperCategoryScreen extends AbstractSimiContainerScreen<Stock
super.renderForeground(graphics, mouseX, mouseY, partialTicks);
GuiGameElement.of(AllBlocks.STOCK_TICKER.asStack()).<GuiGameElement
.GuiRenderBuilder>at(leftPos + AllGuiTextures.STOCK_KEEPER_CATEGORY.getWidth() + 12,
.GuiRenderBuilder>at(leftPos + AllGuiTextures.STOCK_KEEPER_CATEGORY.getWidth() + 12,
topPos + imageHeight - 39, -190)
.scale(3)
.render(graphics);
@ -426,14 +427,14 @@ public class StockKeeperCategoryScreen extends AbstractSimiContainerScreen<Stock
if (hoveredSlot instanceof SlotItemHandler && hoveredSlot.getItem()
.isEmpty()) {
graphics.renderComponentTooltip(font, List.of(CreateLang.translate("gui.stock_ticker.category_filter")
.color(ScrollInput.HEADER_RGB)
.component(),
CreateLang.translate("gui.stock_ticker.category_filter_tip")
.style(ChatFormatting.GRAY)
.component(),
CreateLang.translate("gui.stock_ticker.category_filter_tip_1")
.style(ChatFormatting.GRAY)
.component()),
.color(ScrollInput.HEADER_RGB)
.component(),
CreateLang.translate("gui.stock_ticker.category_filter_tip")
.style(ChatFormatting.GRAY)
.component(),
CreateLang.translate("gui.stock_ticker.category_filter_tip_1")
.style(ChatFormatting.GRAY)
.component()),
mouseX, mouseY);
}

View file

@ -1,13 +1,9 @@
package com.simibubi.create.content.processing.burner;
import org.joml.Quaternionf;
import org.joml.Quaternionfc;
import dev.engine_room.flywheel.api.instance.InstanceHandle;
import dev.engine_room.flywheel.api.instance.InstanceType;
import dev.engine_room.flywheel.lib.instance.TransformedInstance;
import net.createmod.catnip.render.SpriteShiftEntry;
import net.minecraft.core.Vec3i;
public class ScrollTransformedInstance extends TransformedInstance {
public float speedU;
@ -29,6 +25,7 @@ public class ScrollTransformedInstance extends TransformedInstance {
public ScrollTransformedInstance setSpriteShift(SpriteShiftEntry spriteShift) {
return setSpriteShift(spriteShift, 0.5f, 0.5f);
}
public ScrollTransformedInstance setSpriteShift(SpriteShiftEntry spriteShift, float factorU, float factorV) {
float spriteWidth = spriteShift.getTarget()
.getU1()

View file

@ -16,16 +16,15 @@ import com.simibubi.create.foundation.utility.CreateLang;
import com.simibubi.create.infrastructure.ponder.AllCreatePonderTags;
import dev.engine_room.flywheel.lib.transform.TransformStack;
import net.createmod.catnip.data.Iterate;
import net.createmod.catnip.gui.AbstractSimiScreen;
import net.createmod.catnip.gui.ScreenOpener;
import net.createmod.catnip.gui.element.GuiGameElement;
import net.createmod.catnip.gui.widget.AbstractSimiWidget;
import net.createmod.catnip.data.Iterate;
import net.createmod.ponder.foundation.ui.PonderTagScreen;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.util.Mth;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
@ -160,21 +159,21 @@ public class ThresholdSwitchScreen extends AbstractSimiScreen {
}
graphics.drawString(font,
Component.literal("\u2265 " + (typeOfCurrentTarget == ThresholdType.UNSUPPORTED ? ""
: forItems ? onAbove.getState() / valueStep
: blockEntity.format(onAbove.getState() / valueStep, stacks)
.getString())),
graphics.drawString(font,
Component.literal("\u2265 " + (typeOfCurrentTarget == ThresholdType.UNSUPPORTED ? ""
: forItems ? onAbove.getState() / valueStep
: blockEntity.format(onAbove.getState() / valueStep, stacks)
.getString())),
x + 53, y + 28, 0xFFFFFFFF, true);
graphics.drawString(font,
Component.literal("\u2264 " + (typeOfCurrentTarget == ThresholdType.UNSUPPORTED ? ""
: forItems ? offBelow.getState() / valueStep
: blockEntity.format(offBelow.getState() / valueStep, stacks)
.getString())),
graphics.drawString(font,
Component.literal("\u2264 " + (typeOfCurrentTarget == ThresholdType.UNSUPPORTED ? ""
: forItems ? offBelow.getState() / valueStep
: blockEntity.format(offBelow.getState() / valueStep, stacks)
.getString())),
x + 53, y + 28 + 24, 0xFFFFFFFF, true);
GuiGameElement.of(renderedItem).<GuiGameElement
.GuiRenderBuilder>at(x + background.getWidth() + 6, y + background.getHeight() - 56, -200)
.GuiRenderBuilder>at(x + background.getWidth() + 6, y + background.getHeight() - 56, -200)
.scale(5)
.render(graphics);
@ -183,7 +182,7 @@ public class ThresholdSwitchScreen extends AbstractSimiScreen {
ItemStack displayItem = blockEntity.getDisplayItemForScreen();
GuiGameElement.of(displayItem.isEmpty() ? new ItemStack(Items.BARRIER) : displayItem).<GuiGameElement
.GuiRenderBuilder>at(itemX, itemY, 0)
.GuiRenderBuilder>at(itemX, itemY, 0)
.render(graphics);
int torchX = x + 23;
@ -202,7 +201,7 @@ public class ThresholdSwitchScreen extends AbstractSimiScreen {
for (boolean power : Iterate.trueAndFalse) {
GuiGameElement.of(Blocks.REDSTONE_TORCH.defaultBlockState()
.setValue(RedstoneTorchBlock.LIT, blockEntity.isInverted() ^ power))
.setValue(RedstoneTorchBlock.LIT, blockEntity.isInverted() ^ power))
.scale(20)
.render(graphics);
ms.translate(0, 26, 0);

View file

@ -27,7 +27,6 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.level.Level;
@ -92,9 +91,9 @@ public class ServerSchematicLoader {
public void handleNewUpload(ServerPlayer player, String schematic, long size, BlockPos pos) {
String playerPath = getSchematicPath() + "/" + player.getGameProfile()
.getName();
.getName();
String playerSchematicId = player.getGameProfile()
.getName() + "/" + schematic;
.getName() + "/" + schematic;
FilesHelper.createFolderIfMissing(playerPath);
// Unsupported Format
@ -104,11 +103,11 @@ public class ServerSchematicLoader {
}
Path playerSchematicsPath = Paths.get(getSchematicPath(), player.getGameProfile()
.getName())
.toAbsolutePath();
.getName())
.toAbsolutePath();
Path uploadPath = playerSchematicsPath.resolve(schematic)
.normalize();
.normalize();
if (!uploadPath.startsWith(playerSchematicsPath)) {
Create.LOGGER.warn("Attempted Schematic Upload with directory escape: {}", playerSchematicId);
return;
@ -140,8 +139,8 @@ public class ServerSchematicLoader {
if (count >= getConfig().maxSchematics.get()) {
Stream<Path> list2 = Files.list(Paths.get(playerPath));
Optional<Path> lastFilePath = list2.filter(f -> !Files.isDirectory(f))
.min(Comparator.comparingLong(f -> f.toFile()
.lastModified()));
.min(Comparator.comparingLong(f -> f.toFile()
.lastModified()));
list2.close();
if (lastFilePath.isPresent()) {
Files.deleteIfExists(lastFilePath.get());
@ -164,9 +163,9 @@ public class ServerSchematicLoader {
protected boolean validateSchematicSizeOnServer(ServerPlayer player, long size) {
Integer maxFileSize = getConfig().maxTotalSchematicSize.get();
if (size > maxFileSize * 1000) {
player.sendSystemMessage(CreateLang.translateDirect("schematics.uploadTooLarge")
player.sendSystemMessage(CreateLang.translateDirect("schematics.uploadTooLarge")
.append(Component.literal(" (" + size / 1000 + " KB).")));
player.sendSystemMessage(CreateLang.translateDirect("schematics.maxAllowedSize")
player.sendSystemMessage(CreateLang.translateDirect("schematics.maxAllowedSize")
.append(Component.literal(" " + maxFileSize + " KB")));
return false;
}
@ -179,7 +178,7 @@ public class ServerSchematicLoader {
public void handleWriteRequest(ServerPlayer player, String schematic, byte[] data) {
String playerSchematicId = player.getGameProfile()
.getName() + "/" + schematic;
.getName() + "/" + schematic;
if (activeUploads.containsKey(playerSchematicId)) {
SchematicUploadEntry entry = activeUploads.get(playerSchematicId);
@ -249,7 +248,7 @@ public class ServerSchematicLoader {
public void handleFinishedUpload(ServerPlayer player, String schematic) {
String playerSchematicId = player.getGameProfile()
.getName() + "/" + schematic;
.getName() + "/" + schematic;
if (activeUploads.containsKey(playerSchematicId)) {
try {
@ -294,10 +293,10 @@ public class ServerSchematicLoader {
}
Path schematicPath = Paths.get(getSchematicPath())
.toAbsolutePath();
.toAbsolutePath();
Path path = schematicPath.resolve(playerSchematicId)
.normalize();
.normalize();
if (!path.startsWith(schematicPath)) {
Create.LOGGER.warn("Attempted Schematic Upload with directory escape: {}", playerSchematicId);
return;
@ -314,8 +313,8 @@ public class ServerSchematicLoader {
return;
SchematicExportResult result = SchematicExport.saveSchematic(
playerSchematics, schematic, true,
world, pos, pos.offset(bounds).offset(-1, -1, -1)
playerSchematics, schematic, true,
world, pos, pos.offset(bounds).offset(-1, -1, -1)
);
if (result != null)
player.setItemInHand(InteractionHand.MAIN_HAND,

View file

@ -26,7 +26,7 @@ import com.simibubi.create.infrastructure.config.AllConfigs;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.api.distmarker.OnlyIn;
@ -162,12 +162,12 @@ public class ClientSchematicLoader {
try {
Files.list(Paths.get("schematics/"))
.filter(f -> !Files.isDirectory(f) && f.getFileName().toString().endsWith(".nbt")).forEach(path -> {
if (Files.isDirectory(path))
return;
.filter(f -> !Files.isDirectory(f) && f.getFileName().toString().endsWith(".nbt")).forEach(path -> {
if (Files.isDirectory(path))
return;
availableSchematics.add(Component.literal(path.getFileName().toString()));
});
availableSchematics.add(Component.literal(path.getFileName().toString()));
});
} catch (NoSuchFileException e) {
// No Schematics created yet
} catch (IOException e) {

View file

@ -7,7 +7,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;
import net.minecraft.tags.ItemTags;
import net.createmod.catnip.registry.RegisteredObjectsHelper;
import org.apache.commons.lang3.ArrayUtils;
@ -25,7 +25,6 @@ import com.tterrag.registrate.util.nullness.NonNullFunction;
import net.createmod.catnip.data.Iterate;
import net.createmod.catnip.lang.Lang;
import net.createmod.catnip.registry.RegisteredObjectsHelper;
import net.minecraft.data.recipes.RecipeCategory;
import net.minecraft.data.recipes.ShapelessRecipeBuilder;
import net.minecraft.resources.ResourceLocation;
@ -40,6 +39,7 @@ import net.minecraft.world.level.block.WeatheringCopperFullBlock;
import net.minecraft.world.level.block.WeatheringCopperSlabBlock;
import net.minecraft.world.level.block.state.BlockBehaviour.Properties;
import net.neoforged.neoforge.client.model.generators.ModelProvider;
public class CopperBlockSet {
@ -47,6 +47,7 @@ public class CopperBlockSet {
protected static final int WEATHER_STATE_COUNT = WEATHER_STATES.length;
protected static final Map<WeatherState, Supplier<Block>> BASE_BLOCKS = new EnumMap<>(WeatherState.class);
static {
BASE_BLOCKS.put(WeatherState.UNAFFECTED, () -> Blocks.COPPER_BLOCK);
BASE_BLOCKS.put(WeatherState.EXPOSED, () -> Blocks.EXPOSED_COPPER);
@ -55,7 +56,7 @@ public class CopperBlockSet {
}
public static final Variant<?>[] DEFAULT_VARIANTS =
new Variant<?>[] { BlockVariant.INSTANCE, SlabVariant.INSTANCE, StairVariant.INSTANCE };
new Variant<?>[]{BlockVariant.INSTANCE, SlabVariant.INSTANCE, StairVariant.INSTANCE};
protected final String name;
protected final String generalDirectory; // Leave empty for root folder
@ -82,7 +83,7 @@ public class CopperBlockSet {
}
public CopperBlockSet(AbstractRegistrate<?> registrate, String name, String endTextureName, Variant<?>[] variants,
NonNullBiConsumer<DataGenContext<Block, ?>, RegistrateRecipeProvider> mainBlockRecipe, String generalDirectory, NonNullBiConsumer<WeatherState, Block> onRegister) {
NonNullBiConsumer<DataGenContext<Block, ?>, RegistrateRecipeProvider> mainBlockRecipe, String generalDirectory, NonNullBiConsumer<WeatherState, Block> onRegister) {
this.name = name;
this.generalDirectory = generalDirectory;
this.endTextureName = endTextureName;
@ -114,7 +115,7 @@ public class CopperBlockSet {
}
protected <T extends Block> BlockEntry<?> createEntry(AbstractRegistrate<?> registrate, Variant<T> variant,
WeatherState state, boolean waxed) {
WeatherState state, boolean waxed) {
String name = "";
if (waxed) {
name += "waxed_";
@ -209,20 +210,21 @@ public class CopperBlockSet {
NonNullFunction<Properties, T> getFactory(CopperBlockSet blocks, WeatherState state, boolean waxed);
default void generateLootTable(RegistrateBlockLootTables lootTable, T block, CopperBlockSet blocks,
WeatherState state, boolean waxed) {
WeatherState state, boolean waxed) {
lootTable.dropSelf(block);
}
void generateRecipes(BlockEntry<?> blockVariant, DataGenContext<Block, T> ctx, RegistrateRecipeProvider prov);
void generateBlockState(DataGenContext<Block, T> ctx, RegistrateBlockstateProvider prov, CopperBlockSet blocks,
WeatherState state, boolean waxed);
WeatherState state, boolean waxed);
}
public static class BlockVariant implements Variant<Block> {
public static final BlockVariant INSTANCE = new BlockVariant();
protected BlockVariant() {}
protected BlockVariant() {
}
@Override
public String getSuffix() {
@ -240,7 +242,7 @@ public class CopperBlockSet {
@Override
public void generateBlockState(DataGenContext<Block, Block> ctx, RegistrateBlockstateProvider prov,
CopperBlockSet blocks, WeatherState state, boolean waxed) {
CopperBlockSet blocks, WeatherState state, boolean waxed) {
Block block = ctx.get();
String path = RegisteredObjectsHelper.getKeyOrThrow(block)
.getPath();
@ -254,21 +256,23 @@ public class CopperBlockSet {
// End texture and base texture aren't equal, so we should use cube_column.
ResourceLocation endTexture = prov.modLoc(baseLoc + blocks.getEndTextureName());
prov.simpleBlock(block, prov.models()
.cubeColumn(path, texture, endTexture));
.cubeColumn(path, texture, endTexture));
}
}
@Override
public void generateRecipes(BlockEntry<?> blockVariant, DataGenContext<Block, Block> ctx,
RegistrateRecipeProvider prov) {}
RegistrateRecipeProvider prov) {
}
}
public static class SlabVariant implements Variant<SlabBlock> {
public static final SlabVariant INSTANCE = new SlabVariant();
protected SlabVariant() {}
protected SlabVariant() {
}
@Override
public String getSuffix() {
@ -277,7 +281,7 @@ public class CopperBlockSet {
@Override
public NonNullFunction<Properties, SlabBlock> getFactory(CopperBlockSet blocks, WeatherState state,
boolean waxed) {
boolean waxed) {
if (waxed) {
return SlabBlock::new;
} else {
@ -287,13 +291,13 @@ public class CopperBlockSet {
@Override
public void generateLootTable(RegistrateBlockLootTables lootTable, SlabBlock block, CopperBlockSet blocks,
WeatherState state, boolean waxed) {
WeatherState state, boolean waxed) {
lootTable.add(block, lootTable.createSlabItemTable(block));
}
@Override
public void generateBlockState(DataGenContext<Block, SlabBlock> ctx, RegistrateBlockstateProvider prov,
CopperBlockSet blocks, WeatherState state, boolean waxed) {
CopperBlockSet blocks, WeatherState state, boolean waxed) {
ResourceLocation fullModel =
prov.modLoc(ModelProvider.BLOCK_FOLDER + "/" + getWeatherStatePrefix(state) + blocks.getName());
@ -306,7 +310,7 @@ public class CopperBlockSet {
@Override
public void generateRecipes(BlockEntry<?> blockVariant, DataGenContext<Block, SlabBlock> ctx,
RegistrateRecipeProvider prov) {
RegistrateRecipeProvider prov) {
prov.slab(DataIngredient.items(blockVariant.get()), RecipeCategory.BUILDING_BLOCKS, ctx::get, null, true);
}
}
@ -341,7 +345,7 @@ public class CopperBlockSet {
@Override
public void generateBlockState(DataGenContext<Block, StairBlock> ctx, RegistrateBlockstateProvider prov,
CopperBlockSet blocks, WeatherState state, boolean waxed) {
CopperBlockSet blocks, WeatherState state, boolean waxed) {
String baseLoc = ModelProvider.BLOCK_FOLDER + "/" + blocks.generalDirectory + getWeatherStatePrefix(state);
ResourceLocation texture = prov.modLoc(baseLoc + blocks.getName());
ResourceLocation endTexture = prov.modLoc(baseLoc + blocks.getEndTextureName());
@ -350,7 +354,7 @@ public class CopperBlockSet {
@Override
public void generateRecipes(BlockEntry<?> blockVariant, DataGenContext<Block, StairBlock> ctx,
RegistrateRecipeProvider prov) {
RegistrateRecipeProvider prov) {
prov.stairs(DataIngredient.items(blockVariant.get()), RecipeCategory.BUILDING_BLOCKS, ctx::get, null, true);
}
}

View file

@ -16,13 +16,13 @@ import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.util.Mth;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.neoforged.neoforge.common.util.FakePlayer;
public class ScrollValueBehaviour extends BlockEntityBehaviour implements ValueSettingsBehaviour {
@ -156,7 +156,7 @@ public class ScrollValueBehaviour extends BlockEntityBehaviour implements ValueS
@Override
public ValueSettingsBoard createBoard(Player player, BlockHitResult hitResult) {
return new ValueSettingsBoard(label, max, 10, ImmutableList.of(Component.literal("Value")),
return new ValueSettingsBoard(label, max, 10, ImmutableList.of(Component.literal("Value")),
new ValueSettingsFormatter(ValueSettings::format));
}

View file

@ -1,5 +1,7 @@
package com.simibubi.create.foundation.codec;
import java.util.function.Function;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.simibubi.create.foundation.item.ItemSlots;
@ -25,4 +27,17 @@ public class CreateCodecs {
public static Codec<Integer> boundedIntStr(int min) {
return INT_STR.validate(i -> i >= min ? DataResult.success(i) : DataResult.error(() -> "Value under minimum of " + min));
}
public static final Codec<Double> NON_NEGATIVE_DOUBLE = doubleRangeWithMessage(0, Double.MAX_VALUE,
i -> "Value must be non-negative: " + i);
public static final Codec<Double> POSITIVE_DOUBLE = doubleRangeWithMessage(1, Double.MAX_VALUE,
i -> "Value must be positive: " + i);
private static Codec<Double> doubleRangeWithMessage(double min, double max, Function<Double, String> errorMessage) {
return Codec.DOUBLE.validate(i ->
i.compareTo(min) >= 0 && i.compareTo(max) <= 0 ? DataResult.success(i) : DataResult.error(() ->
errorMessage.apply(i)
)
);
}
}

View file

@ -21,6 +21,7 @@ import com.simibubi.create.AllDataComponents;
import com.simibubi.create.AllTags.AllBlockTags;
import com.simibubi.create.AllTags.AllItemTags;
import com.simibubi.create.Create;
import com.simibubi.create.api.stress.BlockStressValues;
import com.simibubi.create.content.contraptions.behaviour.DoorMovingInteraction;
import com.simibubi.create.content.contraptions.behaviour.TrapdoorMovingInteraction;
import com.simibubi.create.content.contraptions.piston.MechanicalPistonGenerator;
@ -32,7 +33,6 @@ import com.simibubi.create.content.decoration.encasing.CasingBlock;
import com.simibubi.create.content.decoration.encasing.EncasedCTBehaviour;
import com.simibubi.create.content.decoration.slidingDoor.SlidingDoorBlock;
import com.simibubi.create.content.decoration.slidingDoor.SlidingDoorMovementBehaviour;
import com.simibubi.create.content.kinetics.BlockStressDefaults;
import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock;
import com.simibubi.create.content.kinetics.crank.ValveHandleBlock;
import com.simibubi.create.content.kinetics.simpleRelays.encased.EncasedCogCTBehaviour;
@ -52,6 +52,7 @@ import com.simibubi.create.foundation.block.ItemUseOverrides;
import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry;
import com.simibubi.create.foundation.block.connected.HorizontalCTBehaviour;
import com.simibubi.create.foundation.item.ItemDescription;
import com.simibubi.create.infrastructure.config.CStress;
import com.tterrag.registrate.builders.BlockBuilder;
import com.tterrag.registrate.builders.ItemBuilder;
import com.tterrag.registrate.providers.RegistrateRecipeProvider;
@ -228,7 +229,7 @@ public class BuilderTransformers {
Supplier<ItemLike> drop) {
return b.initialProperties(SharedProperties::stone)
.properties(BlockBehaviour.Properties::noOcclusion)
.transform(BlockStressDefaults.setNoImpact())
.transform(CStress.setNoImpact())
.loot((p, lb) -> p.dropOther(lb, drop.get()));
}
@ -237,7 +238,7 @@ public class BuilderTransformers {
.blockstate((c, p) -> p.horizontalBlock(c.get(), p.models()
.getExistingFile(p.modLoc("block/cuckoo_clock/block"))))
.addLayer(() -> RenderType::cutoutMipped)
.transform(BlockStressDefaults.setImpact(1.0))
.transform(CStress.setImpact(1))
.item()
.transform(ModelGen.customItemModel("cuckoo_clock", "item"));
}
@ -301,7 +302,7 @@ public class BuilderTransformers {
.texture("3", p.modLoc("block/valve_handle/valve_handle_" + variant)));
})
.tag(AllBlockTags.BRITTLE.tag, AllBlockTags.VALVE_HANDLES.tag)
.transform(BlockStressDefaults.setGeneratorSpeed(ValveHandleBlock::getSpeedRange))
.onRegister(BlockStressValues.setGeneratorSpeed(32))
.onRegister(ItemUseOverrides::addBlock)
.item()
.tag(AllItemTags.VALVE_HANDLES.tag)
@ -382,7 +383,7 @@ public class BuilderTransformers {
.properties(p -> p.noOcclusion())
.blockstate(new MechanicalPistonGenerator(type)::generate)
.addLayer(() -> RenderType::cutoutMipped)
.transform(BlockStressDefaults.setImpact(4.0))
.transform(CStress.setImpact(4.0))
.item()
.transform(ModelGen.customItemModel("mechanical_piston", type.getSerializedName(), "item"));
}
@ -443,7 +444,7 @@ public class BuilderTransformers {
return b -> b.blockstate((c, p) -> p.horizontalBlock(c.getEntry(), AssetLookup.partialBaseModel(c, p)))
.transform(pickaxeOnly())
.addLayer(() -> RenderType::cutoutMipped)
.transform(BlockStressDefaults.setImpact(4.0))
.transform(CStress.setImpact(4.0))
.loot((lt, block) -> {
Builder builder = LootTable.lootTable();
LootItemCondition.Builder survivesExplosion = ExplosionCondition.survivesExplosion();

View file

@ -9,7 +9,6 @@ import static net.minecraft.world.level.block.state.properties.BlockStatePropert
import java.util.function.Supplier;
import com.simibubi.create.AllTags.AllBlockTags;
import com.simibubi.create.Create;
import com.tterrag.registrate.providers.DataGenContext;
import com.tterrag.registrate.providers.RegistrateBlockstateProvider;
import com.tterrag.registrate.util.DataIngredient;
@ -24,6 +23,7 @@ import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.IronBarsBlock;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.material.MapColor;
import net.neoforged.neoforge.client.model.generators.ModelFile;
public class MetalBarsGen {
@ -112,7 +112,7 @@ public class MetalBarsGen {
}
private static ModelFile barsSubModel(RegistrateBlockstateProvider p, String name, String suffix,
boolean specialEdge) {
boolean specialEdge) {
ResourceLocation barsTexture = p.modLoc("block/bars/" + name + "_bars");
ResourceLocation edgeTexture = specialEdge ? p.modLoc("block/bars/" + name + "_bars_edge") : barsTexture;
return p.models()
@ -123,7 +123,7 @@ public class MetalBarsGen {
}
public static BlockEntry<IronBarsBlock> createBars(String name, boolean specialEdge,
Supplier<DataIngredient> ingredient, MapColor color) {
Supplier<DataIngredient> ingredient, MapColor color) {
return REGISTRATE.block(name + "_bars", IronBarsBlock::new)
.addLayer(() -> RenderType::cutoutMipped)
.initialProperties(() -> Blocks.IRON_BARS)

View file

@ -9,7 +9,6 @@ import com.simibubi.create.content.contraptions.actors.psi.PortableItemInterface
import com.simibubi.create.content.contraptions.actors.trainControls.ControlsServerHandler;
import com.simibubi.create.content.contraptions.minecart.CouplingPhysics;
import com.simibubi.create.content.contraptions.minecart.capability.CapabilityMinecartController;
import com.simibubi.create.content.equipment.potatoCannon.PotatoProjectileTypeManager;
import com.simibubi.create.content.equipment.toolbox.ToolboxBlockEntity;
import com.simibubi.create.content.equipment.toolbox.ToolboxHandler;
import com.simibubi.create.content.equipment.wrench.WrenchItem;
@ -76,7 +75,6 @@ import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.client.gui.map.RegisterMapDecorationRenderersEvent;
import net.neoforged.neoforge.event.AddPackFindersEvent;
import net.neoforged.neoforge.event.AddReloadListenerEvent;
import net.neoforged.neoforge.event.OnDatapackSyncEvent;
import net.neoforged.neoforge.event.RegisterCommandsEvent;
import net.neoforged.neoforge.event.entity.EntityEvent;
import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent;
@ -173,20 +171,9 @@ public class CommonEvents {
@SubscribeEvent
public static void addReloadListeners(AddReloadListenerEvent event) {
event.addListener(RecipeFinder.LISTENER);
event.addListener(PotatoProjectileTypeManager.ReloadListener.INSTANCE);
event.addListener(BeltHelper.LISTENER);
}
@SubscribeEvent
public static void onDatapackSync(OnDatapackSyncEvent event) {
ServerPlayer player = event.getPlayer();
if (player != null) {
PotatoProjectileTypeManager.syncTo(player);
} else {
PotatoProjectileTypeManager.syncToAll();
}
}
@SubscribeEvent
public static void serverStopping(ServerStoppingEvent event) {
Create.SCHEMATIC_RECEIVER.shutdown();

View file

@ -31,6 +31,7 @@ import net.minecraft.tags.TagKey;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.level.material.FlowingFluid;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.Fluids;
import net.neoforged.neoforge.fluids.FluidStack;

View file

@ -9,8 +9,9 @@ import java.util.List;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.api.stress.BlockStressValues;
import com.simibubi.create.api.stress.BlockStressValues.GeneratedRpm;
import com.simibubi.create.content.equipment.goggles.GogglesItem;
import com.simibubi.create.content.kinetics.BlockStressValues;
import com.simibubi.create.content.kinetics.base.IRotate;
import com.simibubi.create.content.kinetics.base.IRotate.StressImpact;
import com.simibubi.create.content.kinetics.crank.ValveHandleBlock;
@ -19,7 +20,6 @@ import com.simibubi.create.foundation.utility.CreateLang;
import com.simibubi.create.infrastructure.config.AllConfigs;
import com.simibubi.create.infrastructure.config.CKinetics;
import net.createmod.catnip.data.Couple;
import net.createmod.catnip.lang.Lang;
import net.createmod.catnip.lang.LangBuilder;
import net.minecraft.network.chat.CommonComponents;
@ -80,7 +80,7 @@ public class KineticStats implements TooltipModifier {
boolean hasStressImpact =
StressImpact.isEnabled() && showStressImpact && BlockStressValues.getImpact(block) > 0;
boolean hasStressCapacity = StressImpact.isEnabled() && BlockStressValues.hasCapacity(block);
boolean hasStressCapacity = StressImpact.isEnabled() && BlockStressValues.getCapacity(block) > 0;
if (hasStressImpact) {
CreateLang.translate("tooltip.stressImpact")
@ -110,7 +110,7 @@ public class KineticStats implements TooltipModifier {
.addTo(list);
double capacity = BlockStressValues.getCapacity(block);
Couple<Integer> generatedRPM = BlockStressValues.getGeneratedRPM(block);
GeneratedRpm generatedRPM = BlockStressValues.RPM.get(block);
StressImpact impactId = capacity >= config.highCapacity.get() ? StressImpact.HIGH
: (capacity >= config.mediumCapacity.get() ? StressImpact.MEDIUM : StressImpact.LOW);
@ -126,11 +126,10 @@ public class KineticStats implements TooltipModifier {
.addTo(list);
if (generatedRPM != null) {
LangBuilder amount = CreateLang.number(capacity * generatedRPM.getSecond())
LangBuilder amount = CreateLang.number(capacity * generatedRPM.value())
.add(suUnit);
CreateLang.text(" -> ")
.add(!generatedRPM.getFirst()
.equals(generatedRPM.getSecond()) ? CreateLang.translate("tooltip.up_to", amount) : amount)
.add(generatedRPM.mayGenerateLess() ? CreateLang.translate("tooltip.up_to", amount) : amount)
.style(DARK_GRAY)
.addTo(list);
}

View file

@ -1,22 +1,23 @@
package com.simibubi.create.foundation.mixin;
import com.llamalad7.mixinextras.sugar.Local;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import com.simibubi.create.content.equipment.armor.CardboardArmorHandler;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Pose;
import com.simibubi.create.infrastructure.config.AllConfigs;
import net.minecraft.world.level.Level;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Pose;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
@Mixin(Player.class)
public abstract class PlayerMixin extends LivingEntity {
@ -38,7 +39,8 @@ public abstract class PlayerMixin extends LivingEntity {
)
private boolean pretendNotPassenger(boolean isPassenger) {
// avoid touching all items in the contraption's massive hitbox
if (isPassenger && this.getVehicle() instanceof AbstractContraptionEntity) {
boolean shouldSync = AllConfigs.server().kinetics.syncPlayerPickupHitboxWithContraptionHitbox.get();
if (isPassenger && !shouldSync && this.getVehicle() instanceof AbstractContraptionEntity) {
return false;
}

View file

@ -0,0 +1,12 @@
package com.simibubi.create.foundation.mixin.accessor;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import net.minecraft.world.effect.MobEffectInstance;
@Mixin(MobEffectInstance.class)
public interface MobEffectInstanceAccessor {
@Accessor("hiddenEffect")
MobEffectInstance create$getHiddenEffect();
}

View file

@ -22,7 +22,6 @@ import net.minecraft.network.chat.ClickEvent;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.ComponentUtils;
import net.minecraft.network.chat.HoverEvent;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.Mth;
@ -49,8 +48,8 @@ public class DumpRailwaysCommand {
CommandSourceStack source = ctx.getSource();
fillReport(source.getLevel(), source.getPosition(),
(s, f) -> source.sendSuccess(() -> {
return Component.literal(s).withStyle(st -> st.withColor(f));
}, false),
return Component.literal(s).withStyle(st -> st.withColor(f));
}, false),
(c) -> source.sendSuccess(() -> c, false));
return 1;
});
@ -58,7 +57,7 @@ public class DumpRailwaysCommand {
// https://www.compart.com/en/unicode/search?q=box+drawings+light#characters
static void fillReport(ServerLevel level, Vec3 location, BiConsumer<String, Integer> chat,
Consumer<Component> chatRaw) {
Consumer<Component> chatRaw) {
GlobalRailwayManager railways = Create.RAILWAYS;
@ -85,7 +84,7 @@ public class DumpRailwaysCommand {
chat.accept(graph.id.toString()
.substring(0, 5) + " with "
+ graph.getNodes()
.size()
.size()
+ " Nodes", white);
Collection<SignalBoundary> signals = graph.getPoints(EdgePointType.SIGNAL);
if (!signals.isEmpty())
@ -113,9 +112,9 @@ public class DumpRailwaysCommand {
chat.accept("", white);
for (Train train : nearestTrains) {
chat.accept(String.format("┬%1$s: %2$s, %3$d Wagons",
train.id.toString().substring(0, 5),
train.name.getString(),
train.carriages.size()
train.id.toString().substring(0, 5),
train.name.getString(),
train.carriages.size()
), bright);
if (train.derailed)
chat.accept("├─Derailed", orange);
@ -135,9 +134,9 @@ public class DumpRailwaysCommand {
ScheduleRuntime runtime = train.runtime;
if (runtime.getSchedule() != null) {
chat.accept("├─Schedule, Entry " + runtime.currentEntry + ", "
+ (runtime.paused ? "Paused"
+ (runtime.paused ? "Paused"
: runtime.state.name()
.replaceAll("_", " ")),
.replaceAll("_", " ")),
runtime.paused ? darkBlue : blue);
} else
chat.accept("├─Idle, No Schedule", darkBlue);
@ -163,29 +162,29 @@ public class DumpRailwaysCommand {
}
private static Component createDeleteButton(Train train) {
return Component.literal("└─").withStyle(style -> style.withColor(blue)).append(
return Component.literal("└─").withStyle(style -> style.withColor(blue)).append(
ComponentUtils.wrapInSquareBrackets(
Component.literal("Remove").withStyle(style -> style.withColor(orange))
Component.literal("Remove").withStyle(style -> style.withColor(orange))
).withStyle(style -> {
return style
.withColor(blue)
.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/c train remove " + train.id.toString()))
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal("Click to remove ").append(train.name)));
}
return style
.withColor(blue)
.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/c train remove " + train.id.toString()))
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal("Click to remove ").append(train.name)));
}
)
);
}
private static Component createTeleportButton(Train train) {
return Component.literal("├─").withStyle(style -> style.withColor(darkBlue)).append(
return Component.literal("├─").withStyle(style -> style.withColor(darkBlue)).append(
ComponentUtils.wrapInSquareBrackets(
Component.literal("Teleport").withStyle(style -> style.withColor(orange))
).withStyle(style -> {
return style
.withColor(darkBlue)
.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/c train tp " + train.id.toString()))
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal("Click to teleport to ").append(train.name)));
}
return style
.withColor(darkBlue)
.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/c train tp " + train.id.toString()))
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal("Click to teleport to ").append(train.name)));
}
)
);
}

View file

@ -15,7 +15,7 @@ import net.neoforged.fml.event.config.ModConfigEvent;
import net.neoforged.neoforge.common.ModConfigSpec;
import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.content.kinetics.BlockStressValues;
import com.simibubi.create.api.stress.BlockStressValues;
@EventBusSubscriber(bus = EventBusSubscriber.Bus.MOD)
public class AllConfigs {
@ -63,7 +63,9 @@ public class AllConfigs {
for (Entry<ModConfig.Type, ConfigBase> pair : CONFIGS.entrySet())
container.registerConfig(pair.getKey(), pair.getValue().specification);
BlockStressValues.registerProvider(context.getActiveNamespace(), server().kinetics.stressValues);
CStress stress = server().kinetics.stressValues;
BlockStressValues.IMPACTS.registerProvider(stress::getImpact);
BlockStressValues.CAPACITIES.registerProvider(stress::getCapacity);
}
@SubscribeEvent

View file

@ -51,6 +51,7 @@ public class CKinetics extends ConfigBase {
public final ConfigBool minecartContraptionInContainers =
b(false, "minecartContraptionInContainers", Comments.minecartContraptionInContainers);
public final ConfigBool stabiliseStableContraptions = b(false, "stabiliseStableContraptions", Comments.stabiliseStableContraptions, "[Technical]");
public final ConfigBool syncPlayerPickupHitboxWithContraptionHitbox = b(false, "syncPlayerPickupHitboxWithContraptionHitbox", Comments.syncPlayerPickupHitboxWithContraptionHitbox, "[Technical]");
public final ConfigGroup stats = group(1, "stats", Comments.stats);
public final ConfigFloat mediumSpeed = f(30, 0, 4096, "mediumSpeed", Comments.rpm, Comments.mediumSpeed);
@ -120,6 +121,7 @@ public class CKinetics extends ConfigBase {
static String reinforcedDeepslateMovement = "Configure how Reinforced Deepslate blocks can be moved by contraptions.";
static String minecartContraptionInContainers = "Whether minecart contraptions can be placed into container items.";
static String stabiliseStableContraptions = "Whether stabilised bearings create a separated entity even on non-rotating contraptions.";
static String syncPlayerPickupHitboxWithContraptionHitbox = "Whether the players hitbox should be expanded to the size of the contraption hitbox.";
}
public enum DeployerAggroSetting {

View file

@ -2,14 +2,17 @@ package com.simibubi.create.infrastructure.config;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
import java.util.function.DoubleSupplier;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.Create;
import com.simibubi.create.content.kinetics.BlockStressDefaults;
import com.simibubi.create.content.kinetics.BlockStressValues.IStressValueProvider;
import com.tterrag.registrate.builders.BlockBuilder;
import com.tterrag.registrate.util.nullness.NonNullUnaryOperator;
import it.unimi.dsi.fastutil.objects.Object2DoubleMap;
import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap;
import net.createmod.catnip.config.ConfigBase;
import net.createmod.catnip.data.Couple;
import net.createmod.catnip.registry.RegisteredObjectsHelper;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block;
@ -17,91 +20,76 @@ import net.minecraft.world.level.block.Block;
import net.neoforged.neoforge.common.ModConfigSpec.Builder;
import net.neoforged.neoforge.common.ModConfigSpec.ConfigValue;
public class CStress extends ConfigBase implements IStressValueProvider {
public class CStress extends ConfigBase {
// bump this version to reset configured values.
private static final int VERSION = 2;
private final Map<ResourceLocation, ConfigValue<Double>> capacities = new HashMap<>();
private final Map<ResourceLocation, ConfigValue<Double>> impacts = new HashMap<>();
// IDs need to be used since configs load before registration
private static final Object2DoubleMap<ResourceLocation> DEFAULT_IMPACTS = new Object2DoubleOpenHashMap<>();
private static final Object2DoubleMap<ResourceLocation> DEFAULT_CAPACITIES = new Object2DoubleOpenHashMap<>();
protected final Map<ResourceLocation, ConfigValue<Double>> capacities = new HashMap<>();
protected final Map<ResourceLocation, ConfigValue<Double>> impacts = new HashMap<>();
@Override
public void registerAll(Builder builder) {
builder.comment(".", Comments.su, Comments.impact)
.push("impact");
BlockStressDefaults.DEFAULT_IMPACTS.forEach((r, i) -> {
if (r.getNamespace()
.equals(Create.ID))
getImpacts().put(r, builder.define(r.getPath(), i));
});
DEFAULT_IMPACTS.forEach((id, value) -> this.impacts.put(id, builder.define(id.getPath(), value)));
builder.pop();
builder.comment(".", Comments.su, Comments.capacity)
.push("capacity");
BlockStressDefaults.DEFAULT_CAPACITIES.forEach((r, i) -> {
if (r.getNamespace()
.equals(Create.ID))
getCapacities().put(r, builder.define(r.getPath(), i));
});
DEFAULT_CAPACITIES.forEach((id, value) -> this.capacities.put(id, builder.define(id.getPath(), value)));
builder.pop();
}
@Override
public double getImpact(Block block) {
block = redirectValues(block);
ResourceLocation key = RegisteredObjectsHelper.getKeyOrThrow(block);
ConfigValue<Double> value = getImpacts().get(key);
if (value != null)
return value.get();
return 0;
}
@Override
public double getCapacity(Block block) {
block = redirectValues(block);
ResourceLocation key = RegisteredObjectsHelper.getKeyOrThrow(block);
ConfigValue<Double> value = getCapacities().get(key);
if (value != null)
return value.get();
return 0;
}
@Override
public Couple<Integer> getGeneratedRPM(Block block) {
block = redirectValues(block);
ResourceLocation key = RegisteredObjectsHelper.getKeyOrThrow(block);
Supplier<Couple<Integer>> supplier = BlockStressDefaults.GENERATOR_SPEEDS.get(key);
if (supplier == null)
return null;
return supplier.get();
}
@Override
public boolean hasImpact(Block block) {
block = redirectValues(block);
ResourceLocation key = RegisteredObjectsHelper.getKeyOrThrow(block);
return getImpacts().containsKey(key);
}
@Override
public boolean hasCapacity(Block block) {
block = redirectValues(block);
ResourceLocation key = RegisteredObjectsHelper.getKeyOrThrow(block);
return getCapacities().containsKey(key);
}
protected Block redirectValues(Block block) {
return block;
}
@Override
public String getName() {
return "stressValues.v" + BlockStressDefaults.FORCED_UPDATE_VERSION;
return "stressValues.v" + VERSION;
}
public Map<ResourceLocation, ConfigValue<Double>> getImpacts() {
return impacts;
@Nullable
public DoubleSupplier getImpact(Block block) {
ResourceLocation id = RegisteredObjectsHelper.getKeyOrThrow(block);
ConfigValue<Double> value = this.impacts.get(id);
return value == null ? null : value::get;
}
public Map<ResourceLocation, ConfigValue<Double>> getCapacities() {
return capacities;
@Nullable
public DoubleSupplier getCapacity(Block block) {
ResourceLocation id = RegisteredObjectsHelper.getKeyOrThrow(block);
ConfigValue<Double> value = this.capacities.get(id);
return value == null ? null : value::get;
}
public static <B extends Block, P> NonNullUnaryOperator<BlockBuilder<B, P>> setNoImpact() {
return setImpact(0);
}
public static <B extends Block, P> NonNullUnaryOperator<BlockBuilder<B, P>> setImpact(double value) {
return builder -> {
assertFromCreate(builder);
ResourceLocation id = Create.asResource(builder.getName());
DEFAULT_IMPACTS.put(id, value);
return builder;
};
}
public static <B extends Block, P> NonNullUnaryOperator<BlockBuilder<B, P>> setCapacity(double value) {
return builder -> {
assertFromCreate(builder);
ResourceLocation id = Create.asResource(builder.getName());
DEFAULT_CAPACITIES.put(id, value);
return builder;
};
}
private static void assertFromCreate(BlockBuilder<?, ?> builder) {
if (!builder.getOwner().getModid().equals(Create.ID)) {
throw new IllegalStateException("Non-Create blocks cannot be added to Create's config.");
}
}
private static class Comments {

View file

@ -6,13 +6,14 @@ import java.util.concurrent.CompletableFuture;
import com.simibubi.create.AllDamageTypes;
import com.simibubi.create.AllEnchantments;
import com.simibubi.create.Create;
import com.simibubi.create.api.registry.CreateRegistries;
import com.simibubi.create.content.equipment.potatoCannon.AllPotatoProjectileTypes;
import com.simibubi.create.infrastructure.worldgen.AllBiomeModifiers;
import com.simibubi.create.infrastructure.worldgen.AllConfiguredFeatures;
import com.simibubi.create.infrastructure.worldgen.AllPlacedFeatures;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.RegistrySetBuilder;
import net.minecraft.core.RegistrySetBuilder.RegistryBootstrap;
import net.minecraft.core.registries.Registries;
import net.minecraft.data.PackOutput;
@ -20,13 +21,13 @@ import net.neoforged.neoforge.common.data.DatapackBuiltinEntriesProvider;
import net.neoforged.neoforge.registries.NeoForgeRegistries;
public class GeneratedEntriesProvider extends DatapackBuiltinEntriesProvider {
@SuppressWarnings({ "rawtypes", "unchecked" })
private static final RegistrySetBuilder BUILDER = new RegistrySetBuilder()
.add(Registries.ENCHANTMENT, AllEnchantments::bootstrap)
.add(Registries.ENCHANTMENT, AllEnchantments::bootstrap)
.add(Registries.DAMAGE_TYPE, AllDamageTypes::bootstrap)
.add(Registries.CONFIGURED_FEATURE, (RegistryBootstrap) AllConfiguredFeatures::bootstrap)
.add(Registries.PLACED_FEATURE, AllPlacedFeatures::bootstrap)
.add(NeoForgeRegistries.Keys.BIOME_MODIFIERS, AllBiomeModifiers::bootstrap);
.add(Registries.CONFIGURED_FEATURE, AllConfiguredFeatures::bootstrap)
.add(Registries.PLACED_FEATURE, AllPlacedFeatures::bootstrap)
.add(NeoForgeRegistries.Keys.BIOME_MODIFIERS, AllBiomeModifiers::bootstrap)
.add(CreateRegistries.POTATO_PROJECTILE_TYPE, AllPotatoProjectileTypes::bootstrap);
public GeneratedEntriesProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries) {
super(output, registries, BUILDER, Set.of(Create.ID));

View file

@ -13,7 +13,6 @@ import com.simibubi.create.infrastructure.gametest.CreateGameTestHelper;
import com.simibubi.create.infrastructure.gametest.GameTestGroup;
import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.Registries;
import net.minecraft.gametest.framework.GameTest;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.server.level.ServerLevel;
@ -37,8 +36,8 @@ public class TestMisc {
BlockPos redEndTop = helper.absolutePos(new BlockPos(5, 4, 7));
ServerLevel level = helper.getLevel();
SchematicExport.saveSchematic(
SchematicExport.SCHEMATICS.resolve("uploaded/Deployer"), "schematicannon_gametest", true,
level, whiteEndBottom, redEndTop
SchematicExport.SCHEMATICS.resolve("uploaded/Deployer"), "schematicannon_gametest", true,
level, whiteEndBottom, redEndTop
);
ItemStack schematic =
SchematicItem.create(level, "schematicannon_gametest.nbt", "Deployer");

View file

@ -19,7 +19,6 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.RegistryAccess;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.phys.AABB;
@ -151,7 +150,7 @@ public class ElevatorScenes {
scene.idle(75);
scene.overlay().showControls(util.vector().blockSurface(util.grid().at(3, 6, 2), Direction.NORTH), Pointing.RIGHT, 60)
.rightClick();
.rightClick();
scene.idle(7);
scene.effects().indicateSuccess(util.grid().at(3, 6, 2));
scene.world().toggleRedstonePower(util.select().position(1, 13, 2));
@ -174,7 +173,7 @@ public class ElevatorScenes {
scene.idle(80);
scene.overlay().showControls(util.vector().blockSurface(util.grid().at(1, 1, 2), Direction.UP), Pointing.DOWN, 60)
.rightClick();
.rightClick();
scene.idle(7);
scene.overlay().showOutlineWithText(util.select().position(1, 1, 2), 60)
.placeNearTarget()
@ -242,7 +241,7 @@ public class ElevatorScenes {
scene.idle(10);
scene.overlay().showControls(util.vector().blockSurface(util.grid().at(4, 2, 2), Direction.UP), Pointing.DOWN, 60)
.scroll();
.scroll();
scene.idle(15);
scene.overlay().showText(90)
.placeNearTarget()
@ -251,7 +250,7 @@ public class ElevatorScenes {
scene.idle(85);
scene.overlay().showControls(util.vector().blockSurface(util.grid().at(4, 2, 2), Direction.UP), Pointing.DOWN, 10)
.rightClick();
.rightClick();
scene.idle(7);
scene.world().cycleBlockProperty(midContact, ElevatorContactBlock.POWERING);
scene.world().cycleBlockProperty(topContact, ElevatorContactBlock.CALLING);
@ -267,7 +266,7 @@ public class ElevatorScenes {
scene.idle(15);
scene.overlay().showControls(util.vector().blockSurface(util.grid().at(3, 6, 2), Direction.NORTH), Pointing.RIGHT, 60)
.rightClick();
.rightClick();
scene.idle(7);
scene.effects().indicateSuccess(util.grid().at(3, 6, 2));
scene.world().movePulley(pulleyPos, -1, 0);
@ -283,7 +282,7 @@ public class ElevatorScenes {
scene.idle(20);
scene.overlay().showControls(util.vector().blockSurface(util.grid().at(3, 6, 2), Direction.NORTH), Pointing.RIGHT, 60)
.rightClick();
.rightClick();
scene.idle(7);
scene.effects().indicateSuccess(util.grid().at(3, 6, 2));
scene.world().movePulley(pulleyPos, 1, 0);
@ -362,14 +361,14 @@ public class ElevatorScenes {
scene.world().showSectionAndMerge(util.select().position(nixiePos), Direction.DOWN, camLink);
scene.idle(15);
scene.overlay().showControls(util.vector().blockSurface(util.grid().at(4, 1, 0), Direction.UP), Pointing.DOWN, 15)
.rightClick()
.withItem(AllBlocks.DISPLAY_LINK.asStack());
.rightClick()
.withItem(AllBlocks.DISPLAY_LINK.asStack());
scene.world().toggleRedstonePower(util.select().position(1, 14, 2));
scene.idle(15);
scene.world().showSectionAndMerge(util.select().position(linkPos), Direction.DOWN, camLink);
scene.world().flashDisplayLink(linkPos);
scene.world().modifyBlockEntityNBT(util.select().position(nixiePos), NixieTubeBlockEntity.class, nbt -> {
Component component = Component.literal("0F");
Component component = Component.literal("0F");
nbt.putString("RawCustomText", component.getString());
nbt.putString("CustomText", Component.Serializer.toJson(component, scene.world().getHolderLookupProvider()));
});
@ -400,7 +399,7 @@ public class ElevatorScenes {
scene.world().flashDisplayLink(linkPos);
scene.world().modifyBlockEntityNBT(util.select().position(nixiePos), NixieTubeBlockEntity.class, nbt -> {
Component component = Component.literal("1F");
Component component = Component.literal("1F");
nbt.putString("RawCustomText", component.getString());
nbt.putString("CustomText", Component.Serializer.toJson(component, scene.world().getHolderLookupProvider()));
});
@ -416,7 +415,7 @@ public class ElevatorScenes {
scene.world().flashDisplayLink(linkPos);
scene.world().modifyBlockEntityNBT(util.select().position(nixiePos), NixieTubeBlockEntity.class, nbt -> {
Component component = Component.literal("2F");
Component component = Component.literal("2F");
nbt.putString("RawCustomText", component.getString());
nbt.putString("CustomText", Component.Serializer.toJson(component, scene.world().getHolderLookupProvider()));
});

View file

@ -30,7 +30,6 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
@ -507,10 +506,10 @@ public class RedstoneScenes {
scene.title("analog_lever", "Controlling signals using the Analog Lever");
scene.configureBasePlate(0, 0, 5);
BlockPos[] wireLocations = new BlockPos[] { util.grid().at(2, 1, 1), util.grid().at(2, 1, 0), util.grid().at(1, 1, 0),
BlockPos[] wireLocations = new BlockPos[]{util.grid().at(2, 1, 1), util.grid().at(2, 1, 0), util.grid().at(1, 1, 0),
util.grid().at(0, 1, 0), util.grid().at(0, 1, 1), util.grid().at(0, 1, 2), util.grid().at(0, 1, 3),
util.grid().at(0, 1, 4), util.grid().at(1, 1, 4), util.grid().at(2, 1, 4), util.grid().at(3, 1, 4),
util.grid().at(4, 1, 4), util.grid().at(4, 1, 3), util.grid().at(4, 1, 2), util.grid().at(4, 1, 1) };
util.grid().at(4, 1, 4), util.grid().at(4, 1, 3), util.grid().at(4, 1, 2), util.grid().at(4, 1, 1)};
Selection leverSelection = util.select().fromTo(2, 1, 2, 2, 2, 2);
Selection lamp = util.select().position(4, 1, 0);
@ -638,7 +637,7 @@ public class RedstoneScenes {
.withItem(clipboard);
scene.idle(7);
Component component = Component.literal("CREATE");
Component component = Component.literal("CREATE");
for (int i = 0; i < 3; i++) {
final int index = i;
scene.world().modifyBlockEntityNBT(util.select().position(3 - i, 1, 3), NixieTubeBlockEntity.class, nbt -> {

View file

@ -36,6 +36,7 @@
"accessor.LivingEntityAccessor",
"accessor.MappedRegistryAccessor",
"accessor.MinecartFurnaceAccessor",
"accessor.MobEffectInstanceAccessor",
"accessor.NbtAccounterAccessor",
"accessor.PotionBrewingAccessor",
"accessor.ProjectileDispenseBehaviorAccessor",