mirror of
https://github.com/Creators-of-Create/Create.git
synced 2025-03-04 06:44:40 +01:00
Convert Potato Cannon projectile types into a dynamic registry (#19)
This commit is contained in:
parent
2bd0034f01
commit
a50fb9dac0
54 changed files with 1736 additions and 988 deletions
|
@ -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
|
||||
|
|
|
@ -1,4 +1,29 @@
|
|||
// 1.20.1 2025-02-02T11:59:39.5970888 Create's Generated Registry Entries
|
||||
// 1.20.1 2025-02-23T18:42:20.032170723 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
|
||||
9dd1298993a4657d69a9d2ac4de3ad7879d9aa8d 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
|
||||
d15070ca23129e7d4025d86cb4be5701a466e593 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
|
||||
2dc21c61b4fd4c60b9ade2974b395df42611ee26 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
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
{
|
||||
"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,
|
||||
"effect": "minecraft:regeneration"
|
||||
},
|
||||
"probability": 1.0
|
||||
},
|
||||
{
|
||||
"effect": {
|
||||
"duration": 6000,
|
||||
"effect": "minecraft:resistance"
|
||||
},
|
||||
"probability": 1.0
|
||||
},
|
||||
{
|
||||
"effect": {
|
||||
"duration": 6000,
|
||||
"effect": "minecraft:fire_resistance"
|
||||
},
|
||||
"probability": 1.0
|
||||
},
|
||||
{
|
||||
"effect": {
|
||||
"amplifier": 3,
|
||||
"duration": 2400,
|
||||
"effect": "minecraft:absorption"
|
||||
},
|
||||
"probability": 1.0
|
||||
}
|
||||
],
|
||||
"nutrition": 4,
|
||||
"saturation_modifier": 1.2
|
||||
},
|
||||
"recoverable": false
|
||||
},
|
||||
"reload_ticks": 100,
|
||||
"render_mode": {
|
||||
"type": "create:tumble"
|
||||
},
|
||||
"sound_pitch": 1.1,
|
||||
"velocity_multiplier": 1.45
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"damage": 0,
|
||||
"items": []
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"damage": 4,
|
||||
"items": "minecraft:pufferfish",
|
||||
"knockback": 0.4,
|
||||
"on_entity_hit": {
|
||||
"type": "create:food_effects",
|
||||
"food_property": {
|
||||
"effects": [
|
||||
{
|
||||
"effect": {
|
||||
"amplifier": 1,
|
||||
"duration": 1200,
|
||||
"effect": "minecraft:poison"
|
||||
},
|
||||
"probability": 1.0
|
||||
},
|
||||
{
|
||||
"effect": {
|
||||
"amplifier": 2,
|
||||
"duration": 300,
|
||||
"effect": "minecraft:hunger"
|
||||
},
|
||||
"probability": 1.0
|
||||
},
|
||||
{
|
||||
"effect": {
|
||||
"duration": 300,
|
||||
"effect": "minecraft:nausea"
|
||||
},
|
||||
"probability": 1.0
|
||||
}
|
||||
],
|
||||
"nutrition": 1,
|
||||
"saturation_modifier": 0.1
|
||||
},
|
||||
"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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -40,7 +40,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;
|
||||
|
@ -190,7 +189,7 @@ public enum AllPackets {
|
|||
CONTRAPTION_COLLIDER_LOCK_REQUEST(ContraptionColliderLockPacketRequest.class,
|
||||
ContraptionColliderLockPacketRequest::new, PLAY_TO_SERVER),
|
||||
RADIAL_WRENCH_MENU_SUBMIT(RadialWrenchMenuSubmitPacket.class, RadialWrenchMenuSubmitPacket::new,
|
||||
PLAY_TO_SERVER),
|
||||
PLAY_TO_SERVER),
|
||||
LOGISTICS_STOCK_REQUEST(LogisticalStockRequestPacket.class, LogisticalStockRequestPacket::new, PLAY_TO_SERVER),
|
||||
LOGISTICS_PACKAGE_REQUEST(PackageOrderRequestPacket.class, PackageOrderRequestPacket::new, PLAY_TO_SERVER),
|
||||
CHAIN_CONVEYOR_CONNECT(ChainConveyorConnectionPacket.class, ChainConveyorConnectionPacket::new, PLAY_TO_SERVER),
|
||||
|
@ -227,8 +226,6 @@ public enum AllPackets {
|
|||
SOUL_PULSE(SoulPulseEffectPacket.class, SoulPulseEffectPacket::new, PLAY_TO_CLIENT),
|
||||
PERSISTENT_DATA(ISyncPersistentData.PersistentDataPacket.class, ISyncPersistentData.PersistentDataPacket::new,
|
||||
PLAY_TO_CLIENT),
|
||||
SYNC_POTATO_PROJECTILE_TYPES(PotatoProjectileTypeManager.SyncPacket.class,
|
||||
PotatoProjectileTypeManager.SyncPacket::new, PLAY_TO_CLIENT),
|
||||
SYNC_RAIL_GRAPH(TrackGraphSyncPacket.class, TrackGraphSyncPacket::new, PLAY_TO_CLIENT),
|
||||
SYNC_EDGE_GROUP(SignalEdgeGroupPacket.class, SignalEdgeGroupPacket::new, PLAY_TO_CLIENT),
|
||||
SYNC_TRAIN(TrainPacket.class, TrainPacket::new, PLAY_TO_CLIENT),
|
||||
|
@ -280,7 +277,7 @@ public enum AllPackets {
|
|||
private PacketType<?> packetType;
|
||||
|
||||
<T extends SimplePacketBase> AllPackets(Class<T> type, Function<FriendlyByteBuf, T> factory,
|
||||
NetworkDirection direction) {
|
||||
NetworkDirection direction) {
|
||||
packetType = new PacketType<>(type, factory, direction);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,9 @@ 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.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;
|
||||
|
@ -56,6 +58,7 @@ import net.minecraftforge.fml.ModLoadingContext;
|
|||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||
import net.minecraftforge.registries.RegisterEvent;
|
||||
|
||||
@Mod(Create.ID)
|
||||
public class Create {
|
||||
|
@ -68,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();
|
||||
|
||||
|
@ -82,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)))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -132,6 +137,7 @@ public class Create {
|
|||
|
||||
AllConfigs.register(modLoadingContext);
|
||||
|
||||
// TODO - Make these use Registry.register and move them into the RegisterEvent
|
||||
AllArmInteractionPointTypes.register(modEventBus);
|
||||
AllFanProcessingTypes.register(modEventBus);
|
||||
AllItemAttributeTypes.register(modEventBus);
|
||||
|
@ -148,6 +154,7 @@ public class Create {
|
|||
CopperRegistries.inject();
|
||||
|
||||
modEventBus.addListener(Create::init);
|
||||
modEventBus.addListener(Create::onRegister);
|
||||
modEventBus.addListener(AllEntityTypes::registerEntityAttributes);
|
||||
modEventBus.addListener(EventPriority.LOWEST, CreateDatagen::gatherData);
|
||||
modEventBus.addListener(AllSoundEvents::register);
|
||||
|
@ -166,7 +173,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,6 +188,12 @@ public class Create {
|
|||
});
|
||||
}
|
||||
|
||||
public static void onRegister(final RegisterEvent event) {
|
||||
AllPotatoProjectileRenderModes.init();
|
||||
AllPotatoProjectileEntityHitActions.init();
|
||||
AllPotatoProjectileBlockHitActions.init();
|
||||
}
|
||||
|
||||
public static LangBuilder lang() {
|
||||
return new LangBuilder(ID);
|
||||
}
|
||||
|
|
|
@ -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.BootstapContext;
|
||||
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(BootstapContext<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(BootstapContext<PotatoCannonProjectileType> ctx, ItemLike... items) {
|
||||
addItems(items);
|
||||
register(ctx);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
package com.simibubi.create.api.equipment.potatoCannon;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
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.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
|
||||
import net.minecraftforge.common.IPlantable;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
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);
|
||||
|
||||
Codec<? extends PotatoProjectileBlockHitAction> codec();
|
||||
|
||||
record PlantCrop(Holder<Block> cropBlock) implements PotatoProjectileBlockHitAction {
|
||||
public static final Codec<PlantCrop> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
BuiltInRegistries.BLOCK.holderByNameCodec().fieldOf("block").forGetter(PlantCrop::cropBlock)
|
||||
).apply(instance, PlantCrop::new));
|
||||
|
||||
public PlantCrop(Block cropBlock) {
|
||||
this(ForgeRegistries.BLOCKS.getDelegateOrThrow(cropBlock));
|
||||
}
|
||||
|
||||
@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.get() instanceof IPlantable))
|
||||
return false;
|
||||
BlockState blockState = level.getBlockState(hitPos);
|
||||
if (!blockState.canSustainPlant(level, hitPos, face, (IPlantable) cropBlock.get()))
|
||||
return false;
|
||||
level.setBlock(placePos, cropBlock.get()
|
||||
.defaultBlockState(), 3);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Codec<? extends PotatoProjectileBlockHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
record PlaceBlockOnGround(Holder<Block> block) implements PotatoProjectileBlockHitAction {
|
||||
public static final Codec<PlaceBlockOnGround> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
BuiltInRegistries.BLOCK.holderByNameCodec().fieldOf("block").forGetter(PlaceBlockOnGround::block)
|
||||
).apply(instance, PlaceBlockOnGround::new));
|
||||
|
||||
public PlaceBlockOnGround(Block block) {
|
||||
this(ForgeRegistries.BLOCKS.getDelegateOrThrow(block));
|
||||
}
|
||||
|
||||
@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.get().defaultBlockState());
|
||||
falling.time = 1;
|
||||
level.addFreshEntity(falling);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Codec<? extends PotatoProjectileBlockHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,245 @@
|
|||
package com.simibubi.create.api.equipment.potatoCannon;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import com.simibubi.create.api.registry.CreateBuiltInRegistries;
|
||||
import com.simibubi.create.foundation.mixin.accessor.SuspiciousStewItemAccessor;
|
||||
import com.simibubi.create.foundation.utility.CreateCodecs;
|
||||
|
||||
import net.createmod.catnip.data.WorldAttached;
|
||||
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.Foods;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.EntityHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import net.minecraftforge.common.util.FakePlayer;
|
||||
import net.minecraftforge.event.ForgeEventFactory;
|
||||
import net.minecraftforge.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);
|
||||
|
||||
Codec<? extends PotatoProjectileEntityHitAction> codec();
|
||||
|
||||
record SetOnFire(int ticks) implements PotatoProjectileEntityHitAction {
|
||||
public static final Codec<SetOnFire> CODEC = RecordCodecBuilder.create(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 Codec<? extends PotatoProjectileEntityHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
record PotionEffect(MobEffect effect, int level, int ticks,
|
||||
boolean recoverable) implements PotatoProjectileEntityHitAction {
|
||||
public static final Codec<PotionEffect> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
BuiltInRegistries.MOB_EFFECT.byNameCodec().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 Codec<? extends PotatoProjectileEntityHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
record FoodEffects(FoodProperties foodProperty, boolean recoverable) implements PotatoProjectileEntityHitAction {
|
||||
public static final Codec<FoodEffects> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
CreateCodecs.FOOD_PROPERTIES.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 (Pair<MobEffectInstance, Float> effect : foodProperty.getEffects()) {
|
||||
if (livingEntity.getRandom().nextFloat() < effect.getSecond())
|
||||
applyEffect(livingEntity, new MobEffectInstance(effect.getFirst()));
|
||||
}
|
||||
}
|
||||
return !recoverable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Codec<? extends PotatoProjectileEntityHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
record ChorusTeleport(double teleportDiameter) implements PotatoProjectileEntityHitAction {
|
||||
public static final Codec<ChorusTeleport> CODEC = RecordCodecBuilder.create(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 =
|
||||
ForgeEventFactory.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 Codec<? 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 Codec<CureZombieVillager> CODEC = Codec.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 Codec<? extends PotatoProjectileEntityHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
enum SuspiciousStew implements PotatoProjectileEntityHitAction {
|
||||
INSTANCE;
|
||||
|
||||
public static final Codec<SuspiciousStew> CODEC = Codec.unit(INSTANCE);
|
||||
|
||||
@Override
|
||||
public boolean execute(ItemStack projectile, EntityHitResult ray, Type type) {
|
||||
if (ray.getEntity() instanceof LivingEntity livingEntity)
|
||||
SuspiciousStewItemAccessor.create$listPotionEffects(projectile, livingEntity::addEffect);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Codec<? extends PotatoProjectileEntityHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyEffect(LivingEntity entity, MobEffectInstance effect) {
|
||||
if (effect.getEffect().isInstantenous()) {
|
||||
effect.getEffect()
|
||||
.applyInstantenousEffect(null, null, entity, effect.getDuration(), 1.0);
|
||||
} else {
|
||||
entity.addEffect(effect);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,14 @@
|
|||
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.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 +16,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.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.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 {
|
||||
Codec<? extends PotatoProjectileRenderMode> codec();
|
||||
|
||||
public static final Billboard INSTANCE = new Billboard();
|
||||
enum Billboard implements PotatoProjectileRenderMode {
|
||||
INSTANCE;
|
||||
|
||||
public static final Codec<Billboard> CODEC = Codec.unit(INSTANCE);
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
|
@ -37,32 +49,37 @@ public interface PotatoProjectileRenderMode {
|
|||
.rotateXDegrees(AngleHelper.deg(Mth.atan2(diff.y, Mth.sqrt((float) (diff.x * diff.x + diff.z * diff.z)))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Codec<? 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 Codec<Tumble> CODEC = Codec.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 Codec<? 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 Codec<TowardMotion> CODEC = RecordCodecBuilder.create(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 +94,16 @@ public interface PotatoProjectileRenderMode {
|
|||
.rotateZDegrees(-spriteAngleOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Codec<? 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 Codec<StuckToEntity> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
Vec3.CODEC.fieldOf("offset").forGetter(i -> i.offset)
|
||||
).apply(instance, StuckToEntity::new));
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
|
@ -93,10 +111,13 @@ public interface PotatoProjectileRenderMode {
|
|||
TransformStack.of(ms).rotateYDegrees(AngleHelper.deg(Mth.atan2(offset.x, offset.z)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Codec<? 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -2,12 +2,16 @@ package com.simibubi.create.api.registry;
|
|||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
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;
|
||||
|
@ -32,6 +36,9 @@ public class CreateBuiltInRegistries {
|
|||
public static final Registry<MountedItemStorageType<?>> MOUNTED_ITEM_STORAGE_TYPE = withIntrusiveHolders(CreateRegistries.MOUNTED_ITEM_STORAGE_TYPE);
|
||||
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<Codec<? extends PotatoProjectileRenderMode>> POTATO_PROJECTILE_RENDER_MODE = simple(CreateRegistries.POTATO_PROJECTILE_RENDER_MODE);
|
||||
public static final Registry<Codec<? extends PotatoProjectileEntityHitAction>> POTATO_PROJECTILE_ENTITY_HIT_ACTION = simple(CreateRegistries.POTATO_PROJECTILE_ENTITY_HIT_ACTION);
|
||||
public static final Registry<Codec<? extends PotatoProjectileBlockHitAction>> POTATO_PROJECTILE_BLOCK_HIT_ACTION = simple(CreateRegistries.POTATO_PROJECTILE_BLOCK_HIT_ACTION);
|
||||
|
||||
private static <T> Registry<T> simple(ResourceKey<Registry<T>> key) {
|
||||
return register(key, new MappedRegistry<>(key, Lifecycle.stable(), false));
|
||||
|
|
|
@ -1,11 +1,18 @@
|
|||
package com.simibubi.create.api.registry;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus.Internal;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
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;
|
||||
|
@ -13,10 +20,17 @@ import com.simibubi.create.content.logistics.item.filter.attribute.ItemAttribute
|
|||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus;
|
||||
import net.minecraftforge.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");
|
||||
|
@ -26,8 +40,22 @@ public class CreateRegistries {
|
|||
public static final ResourceKey<Registry<MountedItemStorageType<?>>> MOUNTED_ITEM_STORAGE_TYPE = key("mounted_item_storage_type");
|
||||
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<PotatoCannonProjectileType>> POTATO_PROJECTILE_TYPE = key("potato_projectile/type");
|
||||
public static final ResourceKey<Registry<Codec<? extends PotatoProjectileRenderMode>>> POTATO_PROJECTILE_RENDER_MODE = key("potato_projectile/render_mode");
|
||||
public static final ResourceKey<Registry<Codec<? extends PotatoProjectileEntityHitAction>>> POTATO_PROJECTILE_ENTITY_HIT_ACTION = key("potato_projectile/entity_hit_action");
|
||||
public static final ResourceKey<Registry<Codec<? 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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -245,6 +245,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))
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package com.simibubi.create.content.equipment.potatoCannon;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
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, Codec<? extends PotatoProjectileBlockHitAction> codec) {
|
||||
Registry.register(CreateBuiltInRegistries.POTATO_PROJECTILE_BLOCK_HIT_ACTION, Create.asResource(name), codec);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.simibubi.create.content.equipment.potatoCannon;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
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, Codec<? extends PotatoProjectileEntityHitAction> codec) {
|
||||
Registry.register(CreateBuiltInRegistries.POTATO_PROJECTILE_ENTITY_HIT_ACTION, Create.asResource(name), codec);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.simibubi.create.content.equipment.potatoCannon;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
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, Codec<? extends PotatoProjectileRenderMode> codec) {
|
||||
Registry.register(CreateBuiltInRegistries.POTATO_PROJECTILE_RENDER_MODE, Create.asResource(name), codec);
|
||||
}
|
||||
}
|
|
@ -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.BootstapContext;
|
||||
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(BootstapContext<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));
|
||||
}
|
||||
}
|
|
@ -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.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.minecraftforge.common.IPlantable;
|
||||
import net.minecraftforge.common.util.FakePlayer;
|
||||
import net.minecraftforge.event.ForgeEventFactory;
|
||||
import net.minecraftforge.event.entity.EntityTeleportEvent;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
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()
|
||||
.setSecondsOnFire(seconds);
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
private static Predicate<EntityHitResult> potion(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 (Pair<MobEffectInstance, Float> effect : food.getEffects()) {
|
||||
if (Create.RANDOM.nextFloat() < effect.getSecond())
|
||||
applyEffect((LivingEntity) entity, new MobEffectInstance(effect.getFirst()));
|
||||
}
|
||||
}
|
||||
return !recoverable;
|
||||
};
|
||||
}
|
||||
|
||||
private static void applyEffect(LivingEntity entity, MobEffectInstance effect) {
|
||||
if (effect.getEffect()
|
||||
.isInstantenous())
|
||||
effect.getEffect()
|
||||
.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 IPlantable))
|
||||
return false;
|
||||
BlockState blockState = world.getBlockState(hitPos);
|
||||
if (!blockState.canSustainPlant(world, hitPos, face, (IPlantable) cropBlock.get()))
|
||||
return false;
|
||||
world.setBlock(placePos, cropBlock.get()
|
||||
.defaultBlockState(), 3);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
private static BiPredicate<LevelAccessor, BlockHitResult> plantCrop(Block cropBlock) {
|
||||
return plantCrop(ForgeRegistries.BLOCKS.getDelegateOrThrow(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(ForgeRegistries.BLOCKS.getDelegateOrThrow(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 =
|
||||
ForgeEventFactory.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() {
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
@ -50,6 +51,7 @@ import net.minecraft.world.phys.Vec3;
|
|||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.client.extensions.common.IClientItemExtensions;
|
||||
import net.minecraftforge.server.ServerLifecycleHooks;
|
||||
|
||||
public class PotatoCannonItem extends ProjectileWeaponItem implements CustomArmPoseItem {
|
||||
|
||||
|
@ -109,14 +111,13 @@ public class PotatoCannonItem extends ProjectileWeaponItem implements CustomArmP
|
|||
}
|
||||
|
||||
@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(itemStack -> {
|
||||
|
||||
return findAmmoInInventory(level, player, stack).map(itemStack -> {
|
||||
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);
|
||||
}
|
||||
|
@ -128,28 +129,33 @@ public class PotatoCannonItem extends ProjectileWeaponItem implements CustomArmP
|
|||
.subtract(player.position()
|
||||
.add(0, player.getEyeHeight(), 0));
|
||||
|
||||
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));
|
||||
}
|
||||
|
@ -160,7 +166,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()) {
|
||||
|
@ -173,8 +179,8 @@ public class PotatoCannonItem extends ProjectileWeaponItem implements CustomArmP
|
|||
stack.hurtAndBreak(1, player, p -> p.broadcastBreakEvent(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);
|
||||
|
@ -190,9 +196,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);
|
||||
}
|
||||
|
||||
|
@ -207,7 +213,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;
|
||||
|
@ -215,7 +221,7 @@ public class PotatoCannonItem extends ProjectileWeaponItem implements CustomArmP
|
|||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void appendHoverText(ItemStack stack, Level world, List<Component> tooltip, TooltipFlag flag) {
|
||||
public void appendHoverText(ItemStack stack, @Nullable Level level, List<Component> tooltip, TooltipFlag flag) {
|
||||
int power = stack.getEnchantmentLevel(Enchantments.POWER_ARROWS);
|
||||
int punch = stack.getEnchantmentLevel(Enchantments.PUNCH_ARROWS);
|
||||
final float additionalDamageMult = 1 + power * .2f;
|
||||
|
@ -229,17 +235,17 @@ 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)
|
||||
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());
|
||||
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);
|
||||
|
@ -255,12 +261,13 @@ public class PotatoCannonItem extends ProjectileWeaponItem implements CustomArmP
|
|||
.append(CreateLang.translateDirect(_knockback, knockback)
|
||||
.withStyle(darkGreen)));
|
||||
});
|
||||
super.appendHoverText(stack, world, tooltip, flag);
|
||||
super.appendHoverText(stack, level, tooltip, flag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<ItemStack> getAllSupportedProjectiles() {
|
||||
return stack -> PotatoProjectileTypeManager.getTypeForStack(stack)
|
||||
Level level = ServerLifecycleHooks.getCurrentServer().getLevel(Level.OVERWORLD);
|
||||
return stack -> PotatoCannonProjectileType.getTypeForStack(level, stack)
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,298 +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.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
import net.createmod.catnip.platform.CatnipServices;
|
||||
import net.minecraft.ResourceLocationException;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
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;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
public class PotatoCannonProjectileType {
|
||||
|
||||
private List<Supplier<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 List<Supplier<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 PotatoCannonProjectileType fromJson(JsonObject object) {
|
||||
PotatoCannonProjectileType type = new PotatoCannonProjectileType();
|
||||
try {
|
||||
JsonElement itemsElement = object.get("items");
|
||||
if (itemsElement != null && itemsElement.isJsonArray()) {
|
||||
for (JsonElement element : itemsElement.getAsJsonArray()) {
|
||||
if (element.isJsonPrimitive()) {
|
||||
JsonPrimitive primitive = element.getAsJsonPrimitive();
|
||||
if (primitive.isString()) {
|
||||
try {
|
||||
Optional<Holder.Reference<Item>> reference = ForgeRegistries.ITEMS.getDelegate(new ResourceLocation(primitive.getAsString()));
|
||||
if (reference.isPresent()) {
|
||||
type.items.add(reference.get());
|
||||
}
|
||||
} catch (ResourceLocationException e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parseJsonPrimitive(object, "reload_ticks", JsonPrimitive::isNumber, primitive -> type.reloadTicks = primitive.getAsInt());
|
||||
parseJsonPrimitive(object, "damage", JsonPrimitive::isNumber, primitive -> type.damage = primitive.getAsInt());
|
||||
parseJsonPrimitive(object, "split", JsonPrimitive::isNumber, primitive -> type.split = primitive.getAsInt());
|
||||
parseJsonPrimitive(object, "knockback", JsonPrimitive::isNumber, primitive -> type.knockback = primitive.getAsFloat());
|
||||
parseJsonPrimitive(object, "drag", JsonPrimitive::isNumber, primitive -> type.drag = primitive.getAsFloat());
|
||||
parseJsonPrimitive(object, "velocity_multiplier", JsonPrimitive::isNumber, primitive -> type.velocityMultiplier = primitive.getAsFloat());
|
||||
parseJsonPrimitive(object, "gravity_multiplier", JsonPrimitive::isNumber, primitive -> type.gravityMultiplier = primitive.getAsFloat());
|
||||
parseJsonPrimitive(object, "sound_pitch", JsonPrimitive::isNumber, primitive -> type.soundPitch = primitive.getAsFloat());
|
||||
parseJsonPrimitive(object, "sticky", JsonPrimitive::isBoolean, primitive -> type.sticky = primitive.getAsBoolean());
|
||||
} catch (Exception e) {
|
||||
//
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
private static void parseJsonPrimitive(JsonObject object, String key, Predicate<JsonPrimitive> predicate, Consumer<JsonPrimitive> consumer) {
|
||||
JsonElement element = object.get(key);
|
||||
if (element != null && element.isJsonPrimitive()) {
|
||||
JsonPrimitive primitive = element.getAsJsonPrimitive();
|
||||
if (predicate.test(primitive)) {
|
||||
consumer.accept(primitive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void toBuffer(PotatoCannonProjectileType type, FriendlyByteBuf buffer) {
|
||||
buffer.writeVarInt(type.items.size());
|
||||
for (Supplier<Item> delegate : type.items) {
|
||||
buffer.writeResourceLocation(CatnipServices.REGISTRIES.getKeyOrThrow(delegate.get()));
|
||||
}
|
||||
buffer.writeInt(type.reloadTicks);
|
||||
buffer.writeInt(type.damage);
|
||||
buffer.writeInt(type.split);
|
||||
buffer.writeFloat(type.knockback);
|
||||
buffer.writeFloat(type.drag);
|
||||
buffer.writeFloat(type.velocityMultiplier);
|
||||
buffer.writeFloat(type.gravityMultiplier);
|
||||
buffer.writeFloat(type.soundPitch);
|
||||
buffer.writeBoolean(type.sticky);
|
||||
}
|
||||
|
||||
public static PotatoCannonProjectileType fromBuffer(FriendlyByteBuf buffer) {
|
||||
PotatoCannonProjectileType type = new PotatoCannonProjectileType();
|
||||
int size = buffer.readVarInt();
|
||||
for (int i = 0; i < size; i++) {
|
||||
Optional<Holder.Reference<Item>> reference = ForgeRegistries.ITEMS.getDelegate(buffer.readResourceLocation());
|
||||
if (reference.isPresent()) {
|
||||
type.items.add(reference.get());
|
||||
}
|
||||
}
|
||||
type.reloadTicks = buffer.readInt();
|
||||
type.damage = buffer.readInt();
|
||||
type.split = buffer.readInt();
|
||||
type.knockback = buffer.readFloat();
|
||||
type.drag = buffer.readFloat();
|
||||
type.velocityMultiplier = buffer.readFloat();
|
||||
type.gravityMultiplier = buffer.readFloat();
|
||||
type.soundPitch = buffer.readFloat();
|
||||
type.sticky = buffer.readBoolean();
|
||||
return type;
|
||||
}
|
||||
|
||||
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(ForgeRegistries.ITEMS.getDelegateOrThrow(provider.asItem()));
|
||||
return this;
|
||||
}
|
||||
|
||||
public PotatoCannonProjectileType register() {
|
||||
PotatoProjectileTypeManager.registerBuiltinType(id, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public PotatoCannonProjectileType registerAndAssign(ItemLike... items) {
|
||||
addItems(items);
|
||||
register();
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
@ -68,8 +71,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;
|
||||
}
|
||||
|
||||
|
@ -127,7 +135,7 @@ public class PotatoProjectileEntity extends AbstractHurtingProjectile implements
|
|||
if (getStuckEntity() != null)
|
||||
return stuckRenderer;
|
||||
|
||||
return getProjectileType().getRenderMode();
|
||||
return getProjectileType().renderMode();
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
|
@ -139,15 +147,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();
|
||||
|
@ -178,8 +186,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())
|
||||
|
@ -202,7 +210,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;
|
||||
|
@ -220,9 +228,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());
|
||||
|
@ -230,8 +241,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()
|
||||
|
@ -259,7 +270,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();
|
||||
|
@ -284,7 +295,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);
|
||||
|
|
|
@ -1,160 +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.function.Supplier;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.AllPackets;
|
||||
import com.simibubi.create.foundation.networking.SimplePacketBase;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
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.minecraftforge.network.NetworkEvent.Context;
|
||||
import net.minecraftforge.network.PacketDistributor;
|
||||
|
||||
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 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 (Supplier<Item> delegate : type.getItems()) {
|
||||
ITEM_TO_TYPE_MAP.put(delegate.get(), type);
|
||||
}
|
||||
}
|
||||
for (Map.Entry<ResourceLocation, PotatoCannonProjectileType> entry : CUSTOM_TYPE_MAP.entrySet()) {
|
||||
PotatoCannonProjectileType type = entry.getValue();
|
||||
for (Supplier<Item> delegate : type.getItems()) {
|
||||
ITEM_TO_TYPE_MAP.put(delegate.get(), type);
|
||||
}
|
||||
}
|
||||
ITEM_TO_TYPE_MAP.remove(AllItems.POTATO_CANNON.get());
|
||||
}
|
||||
|
||||
public static void toBuffer(FriendlyByteBuf buffer) {
|
||||
buffer.writeVarInt(CUSTOM_TYPE_MAP.size());
|
||||
for (Map.Entry<ResourceLocation, PotatoCannonProjectileType> entry : CUSTOM_TYPE_MAP.entrySet()) {
|
||||
buffer.writeResourceLocation(entry.getKey());
|
||||
PotatoCannonProjectileType.toBuffer(entry.getValue(), buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public static void fromBuffer(FriendlyByteBuf buffer) {
|
||||
clear();
|
||||
|
||||
int size = buffer.readVarInt();
|
||||
for (int i = 0; i < size; i++) {
|
||||
CUSTOM_TYPE_MAP.put(buffer.readResourceLocation(), PotatoCannonProjectileType.fromBuffer(buffer));
|
||||
}
|
||||
|
||||
fillItemMap();
|
||||
}
|
||||
|
||||
public static void syncTo(ServerPlayer player) {
|
||||
AllPackets.getChannel().send(PacketDistributor.PLAYER.with(() -> player), new SyncPacket());
|
||||
}
|
||||
|
||||
public static void syncToAll() {
|
||||
AllPackets.getChannel().send(PacketDistributor.ALL.noArg(), new SyncPacket());
|
||||
}
|
||||
|
||||
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()) {
|
||||
JsonElement element = entry.getValue();
|
||||
if (element.isJsonObject()) {
|
||||
ResourceLocation id = entry.getKey();
|
||||
JsonObject object = element.getAsJsonObject();
|
||||
PotatoCannonProjectileType type = PotatoCannonProjectileType.fromJson(object);
|
||||
CUSTOM_TYPE_MAP.put(id, type);
|
||||
}
|
||||
}
|
||||
|
||||
fillItemMap();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class SyncPacket extends SimplePacketBase {
|
||||
|
||||
private FriendlyByteBuf buffer;
|
||||
|
||||
public SyncPacket() {
|
||||
}
|
||||
|
||||
public SyncPacket(FriendlyByteBuf buffer) {
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
toBuffer(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(Context context) {
|
||||
context.enqueueWork(() -> {
|
||||
fromBuffer(buffer);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -6,7 +6,6 @@ import com.simibubi.create.content.contraptions.ContraptionHandler;
|
|||
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.ToolboxHandler;
|
||||
import com.simibubi.create.content.equipment.wrench.WrenchItem;
|
||||
import com.simibubi.create.content.equipment.zapper.ZapperInteractionHandler;
|
||||
|
@ -39,7 +38,6 @@ import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
|
|||
import net.minecraftforge.event.AddPackFindersEvent;
|
||||
import net.minecraftforge.event.AddReloadListenerEvent;
|
||||
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||
import net.minecraftforge.event.OnDatapackSyncEvent;
|
||||
import net.minecraftforge.event.RegisterCommandsEvent;
|
||||
import net.minecraftforge.event.TickEvent.LevelTickEvent;
|
||||
import net.minecraftforge.event.TickEvent.Phase;
|
||||
|
@ -143,20 +141,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();
|
||||
|
|
|
@ -5,6 +5,7 @@ import org.spongepowered.asm.mixin.injection.At;
|
|||
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
|
||||
import com.simibubi.create.infrastructure.config.AllConfigs;
|
||||
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
|
@ -26,7 +27,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.simibubi.create.foundation.mixin.accessor;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.SuspiciousStewItem;
|
||||
|
||||
@Mixin(SuspiciousStewItem.class)
|
||||
public interface SuspiciousStewItemAccessor {
|
||||
@Invoker("listPotionEffects")
|
||||
static void create$listPotionEffects(ItemStack stack, Consumer<MobEffectInstance> output) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
|
@ -1,10 +1,30 @@
|
|||
package com.simibubi.create.foundation.utility;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.primitives.UnsignedBytes;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.DataResult;
|
||||
import com.mojang.serialization.DynamicOps;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.MapLike;
|
||||
import com.mojang.serialization.RecordBuilder;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import com.simibubi.create.foundation.item.ItemSlots;
|
||||
import com.simibubi.create.foundation.mixin.accessor.MobEffectInstanceAccessor;
|
||||
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.util.ExtraCodecs;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.effect.MobEffectInstance.FactorData;
|
||||
import net.minecraft.world.food.FoodProperties;
|
||||
|
||||
import net.minecraftforge.items.ItemStackHandler;
|
||||
|
||||
|
@ -30,4 +50,117 @@ public class CreateCodecs {
|
|||
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 ExtraCodecs.validate(Codec.DOUBLE, i ->
|
||||
i.compareTo(min) >= 0 && i.compareTo(max) <= 0 ? DataResult.success(i) : DataResult.error(() ->
|
||||
errorMessage.apply(i)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static final Codec<Integer> UNSIGNED_BYTE = Codec.BYTE
|
||||
.flatComapMap(
|
||||
UnsignedBytes::toInt,
|
||||
p_324632_ -> p_324632_ > 255
|
||||
? DataResult.error(() -> "Unsigned byte was too large: " + p_324632_ + " > 255")
|
||||
: DataResult.success(p_324632_.byteValue())
|
||||
);
|
||||
|
||||
public static final MapCodec<MobEffectInstance> MOB_EFFECT_INSTANCE = recursive(
|
||||
"MobEffectInstance",
|
||||
codec -> RecordCodecBuilder.mapCodec(
|
||||
instance -> instance.group(
|
||||
BuiltInRegistries.MOB_EFFECT.byNameCodec().fieldOf("effect").forGetter(MobEffectInstance::getEffect),
|
||||
Codec.INT.optionalFieldOf("duration", 0).forGetter(MobEffectInstance::getDuration),
|
||||
UNSIGNED_BYTE.optionalFieldOf("amplifier", 0).forGetter(MobEffectInstance::getAmplifier),
|
||||
Codec.BOOL.optionalFieldOf("ambient", false).forGetter(MobEffectInstance::isAmbient),
|
||||
Codec.BOOL.optionalFieldOf("show_particles", true).forGetter(MobEffectInstance::isVisible),
|
||||
Codec.BOOL.optionalFieldOf("show_icon", true).forGetter(MobEffectInstance::showIcon),
|
||||
codec.optionalFieldOf("hidden_effect").forGetter(i -> Optional.ofNullable(((MobEffectInstanceAccessor) i).create$getHiddenEffect())),
|
||||
FactorData.CODEC.optionalFieldOf("factor_data").forGetter(MobEffectInstance::getFactorData)
|
||||
)
|
||||
.apply(instance, (effect, duration, amplifier, isAmbient, showParticles, showIcon, hiddenEffect, factorData) ->
|
||||
new MobEffectInstance(effect, duration, amplifier, isAmbient, showParticles, showIcon, hiddenEffect.orElse(null), factorData))
|
||||
)
|
||||
);
|
||||
|
||||
public static final Codec<FoodProperties> FOOD_PROPERTIES = RecordCodecBuilder.create(instance -> instance.group(
|
||||
ExtraCodecs.NON_NEGATIVE_INT.fieldOf("nutrition").forGetter(FoodProperties::getNutrition),
|
||||
Codec.FLOAT.fieldOf("saturation_modifier").forGetter(FoodProperties::getSaturationModifier),
|
||||
Codec.BOOL.optionalFieldOf("is_meat", false).forGetter(FoodProperties::isMeat),
|
||||
Codec.BOOL.optionalFieldOf("can_always_eat", false).forGetter(FoodProperties::canAlwaysEat),
|
||||
Codec.BOOL.optionalFieldOf("is_fast_food", false).forGetter(FoodProperties::isFastFood),
|
||||
FoodEffect.CODEC.listOf().optionalFieldOf("effects", List.of()).forGetter(i -> {
|
||||
List<FoodEffect> effects = new ArrayList<>();
|
||||
for (Pair<MobEffectInstance, Float> pair : i.getEffects())
|
||||
effects.add(new FoodEffect(pair.getFirst(), pair.getSecond()));
|
||||
return effects;
|
||||
})
|
||||
).apply(instance, (nutrition, saturationModifier, isMeat, canAlwaysEat, isFastFood, effects) -> {
|
||||
FoodProperties.Builder builder = new FoodProperties.Builder()
|
||||
.nutrition(nutrition)
|
||||
.saturationMod(saturationModifier);
|
||||
|
||||
if (isMeat) builder.meat();
|
||||
if (canAlwaysEat) builder.alwaysEat();
|
||||
if (isFastFood) builder.fast();
|
||||
for (FoodEffect effect : effects) builder.effect(effect.effectSupplier(), effect.probability());
|
||||
|
||||
return builder.build();
|
||||
}));
|
||||
|
||||
public record FoodEffect(Supplier<MobEffectInstance> effectSupplier, float probability) {
|
||||
public static final Codec<FoodEffect> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
MOB_EFFECT_INSTANCE.fieldOf("effect").forGetter(FoodEffect::effect),
|
||||
Codec.FLOAT.fieldOf("probability").forGetter(FoodEffect::probability)
|
||||
).apply(instance, FoodEffect::new));
|
||||
|
||||
private FoodEffect(MobEffectInstance effect, float probability) {
|
||||
this(() -> effect, probability);
|
||||
}
|
||||
|
||||
public MobEffectInstance effect() {
|
||||
return new MobEffectInstance(this.effectSupplier.get());
|
||||
}
|
||||
}
|
||||
|
||||
public static <A> MapCodec<A> recursive(final String name, final Function<Codec<A>, MapCodec<A>> wrapped) {
|
||||
return new RecursiveMapCodec<>(name, wrapped);
|
||||
}
|
||||
|
||||
private static class RecursiveMapCodec<A> extends MapCodec<A> {
|
||||
private final String name;
|
||||
private final Supplier<MapCodec<A>> wrapped;
|
||||
|
||||
private RecursiveMapCodec(final String name, final Function<Codec<A>, MapCodec<A>> wrapped) {
|
||||
this.name = name;
|
||||
this.wrapped = Suppliers.memoize(() -> wrapped.apply(codec()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> RecordBuilder<T> encode(final A input, final DynamicOps<T> ops, final RecordBuilder<T> prefix) {
|
||||
return wrapped.get().encode(input, ops, prefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> DataResult<A> decode(final DynamicOps<T> ops, final MapLike<T> input) {
|
||||
return wrapped.get().decode(ops, input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Stream<T> keys(final DynamicOps<T> ops) {
|
||||
return wrapped.get().keys(ops);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RecursiveMapCodec[" + name + ']';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -5,25 +5,27 @@ import java.util.concurrent.CompletableFuture;
|
|||
|
||||
import com.simibubi.create.AllDamageTypes;
|
||||
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;
|
||||
|
||||
import net.minecraftforge.common.data.DatapackBuiltinEntriesProvider;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
public class GeneratedEntriesProvider extends DatapackBuiltinEntriesProvider {
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private static final RegistrySetBuilder BUILDER = new RegistrySetBuilder()
|
||||
.add(Registries.DAMAGE_TYPE, AllDamageTypes::bootstrap)
|
||||
.add(Registries.CONFIGURED_FEATURE, (RegistryBootstrap) AllConfiguredFeatures::bootstrap)
|
||||
.add(Registries.PLACED_FEATURE, AllPlacedFeatures::bootstrap)
|
||||
.add(ForgeRegistries.Keys.BIOME_MODIFIERS, AllBiomeModifiers::bootstrap);
|
||||
.add(Registries.DAMAGE_TYPE, AllDamageTypes::bootstrap)
|
||||
.add(Registries.CONFIGURED_FEATURE, AllConfiguredFeatures::bootstrap)
|
||||
.add(Registries.PLACED_FEATURE, AllPlacedFeatures::bootstrap)
|
||||
.add(ForgeRegistries.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));
|
||||
|
|
|
@ -31,9 +31,11 @@
|
|||
"accessor.GameTestHelperAccessor",
|
||||
"accessor.ItemModelGeneratorsAccessor",
|
||||
"accessor.LivingEntityAccessor",
|
||||
"accessor.MobEffectInstanceAccessor",
|
||||
"accessor.NbtAccounterAccessor",
|
||||
"accessor.ServerLevelAccessor",
|
||||
"accessor.StateHolderAccessor",
|
||||
"accessor.SuspiciousStewItemAccessor",
|
||||
"accessor.SystemReportAccessor",
|
||||
"accessor.UseOnContextAccessor"
|
||||
],
|
||||
|
|
Loading…
Add table
Reference in a new issue