Merge branch 'mc1.20.1/feature-dev' into mc1.21.1/dev
20
changelog.md
|
@ -130,6 +130,7 @@ _Now using Flywheel 1.0_
|
|||
- Fixed vaults and tanks rotated in place not updating their multiblock correctly
|
||||
- Hose pulley now deletes lilypads and other surface foliage
|
||||
- Fixed crushing wheels not applying looting to killed entities
|
||||
- Updated contraption chunkban protections, corrected limits and made them much harder to hit
|
||||
|
||||
#### API Changes
|
||||
|
||||
|
@ -138,6 +139,7 @@ _Now using Flywheel 1.0_
|
|||
- Added `#create:chain_rideable` to mark items as valid for riding a chain with
|
||||
- Added `#create:invalid_for_track_paving` for items
|
||||
- Added `#create:sugar_cane_variants` to allow the mechanical saw to work with custom sugarcane variants (#7263)
|
||||
- Added `#create:not_harvestable` to disallow blocks that the mechanical harvester would otherwise try to harvest
|
||||
- New API for custom storage block behaviour on contraptions.
|
||||
For simple cases, create provides the `#create:simple_mounted_storage` and `#create:chest_mounted_storage` block tags.
|
||||
- Added `#create:non_breakable` to mark blocks that cannot be broken by block-breaking kinetics
|
||||
|
@ -149,6 +151,22 @@ _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
|
||||
- Convert Potato Cannon projectile 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
|
||||
- Reworked the AttachedRegistry class into SimpleRegistry and added Provider functionality
|
||||
- Exposed all custom registries as API
|
||||
- Exposed a handful of previously internal classes to the API, and gave them some cleanup
|
||||
- BlockSpoutingBehaviour
|
||||
- MovementBehaviour
|
||||
- MovingInteractionBehaviour
|
||||
- DisplaySource
|
||||
- DisplayTarget
|
||||
- ContraptionMovementSetting
|
||||
- BoilerHeater
|
||||
- PortalTrackProvider
|
||||
- BlockMovementChecks
|
||||
- ContraptionType
|
||||
- MountedDispenseBehavior
|
||||
- BlockStressValues
|
||||
- OpenPipeEffectHandler
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// 1.21.1 2025-02-23T21:05:27.700364514 Create's Generated Registry Entries
|
||||
// 1.20.1 2025-02-24T12:59:18.4372587 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
|
||||
|
@ -7,7 +7,7 @@ abb9dd2c98388abb430343d4ac02d460e5edc086 data/create/create/potato_projectile/ty
|
|||
22e0f5befe5835c7a9a6448e17e73e6fb7d0fb9c data/create/create/potato_projectile/type/carrot.json
|
||||
af17d72549ee9421d2643a215ffc2291874fff93 data/create/create/potato_projectile/type/chocolate_berry.json
|
||||
8cb4811601d46db5fdc0291edce3ec2f3a64e902 data/create/create/potato_projectile/type/chorus_fruit.json
|
||||
69138506c1b02aa4e2456cc1912ddb70f8a1e42a data/create/create/potato_projectile/type/enchanted_golden_apple.json
|
||||
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
|
||||
|
@ -19,10 +19,10 @@ c6234751ccad5111857b0ae9e297e42f529ad32a data/create/create/potato_projectile/ty
|
|||
352402ba2fff3f23af178d15d61b0ba0a151097a data/create/create/potato_projectile/type/melon_slice.json
|
||||
cbfd3028ad878bddbdaeb0eec0cd5a1c50d4c901 data/create/create/potato_projectile/type/poison_potato.json
|
||||
b58e779803d29d4b36ecf79fde4e918577c71748 data/create/create/potato_projectile/type/potato.json
|
||||
3ba8dbd239452eb2531d8f13332a37bc1ffa3616 data/create/create/potato_projectile/type/pufferfish.json
|
||||
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
|
||||
30bf0b35aeff136251d3bfe2af04fd89ccf953de data/create/create/potato_projectile/type/suspicious_stew.json
|
||||
0e73e50b02e9afe5f170729935ae5921d22d7091 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
|
||||
|
@ -33,11 +33,9 @@ afdc8574e8e915dac5693f368e9c1260714ad111 data/create/damage_type/mechanical_roll
|
|||
43cfce97a9326a1a7ce95f91a052586610b9686c data/create/damage_type/mechanical_saw.json
|
||||
58ab7a8eed0841f05b4b1373ba159e3e6503b7c3 data/create/damage_type/potato_cannon.json
|
||||
4dae2c0fc9fe6749649ef06dd3b7baaa9bd5e807 data/create/damage_type/run_over.json
|
||||
eefc270acd718dc889a9a15e350cee5b9c673dfa data/create/enchantment/capacity.json
|
||||
d7ba49f29711546a65861c8140004d97fa09f16b data/create/enchantment/potato_recovery.json
|
||||
95c3416ba53bcedc4e8aae5d2e9fffb10e4f7d10 data/create/neoforge/biome_modifier/striated_ores_nether.json
|
||||
422b87075cee548e3d215822f546a06c89aaf7f4 data/create/neoforge/biome_modifier/striated_ores_overworld.json
|
||||
3bc0da630715b1fc7d796e1592dd15e0f36951a5 data/create/neoforge/biome_modifier/zinc_ore.json
|
||||
f650826db97d0562230ae0bd965ccbad4c696eff data/create/forge/biome_modifier/striated_ores_nether.json
|
||||
d401f270f1ba0e5d6940aeb8f72ebb3a02dd055e data/create/forge/biome_modifier/striated_ores_overworld.json
|
||||
ed82e4fd3dba36cf2fd81a196cc6670ae0c6da9f data/create/forge/biome_modifier/zinc_ore.json
|
||||
ed83634a4af759ef80cfd1101f5715d38268620f data/create/worldgen/configured_feature/striated_ores_nether.json
|
||||
39576de9dc1368287a96a8627bbdef34954242e0 data/create/worldgen/configured_feature/striated_ores_overworld.json
|
||||
fbf6999fb922a0770cfbea3a8bddc11ba8b1552b data/create/worldgen/configured_feature/zinc_ore.json
|
||||
|
|
|
@ -1072,6 +1072,7 @@
|
|||
"create.display_source.nixie_tube": "sǝqn⟘ ǝıxıN ʎdoƆ",
|
||||
"create.display_source.observed_train_name": "ǝɯɐN uıɐɹ⟘ pǝʇɔǝʇǝᗡ",
|
||||
"create.display_source.player_deaths": "sɥʇɐǝᗡ ɹǝʎɐןԀ",
|
||||
"create.display_source.read_package_address": "ssǝɹppⱯ ǝbɐʞɔɐԀ pɐǝᴚ",
|
||||
"create.display_source.redstone_power": "ɹǝʍoԀ ǝuoʇspǝᴚ",
|
||||
"create.display_source.redstone_power.display": "ʇɐɯɹoℲ ʎɐןdsıᗡ",
|
||||
"create.display_source.redstone_power.number": "ɹǝqɯnN",
|
||||
|
|
|
@ -1072,6 +1072,7 @@
|
|||
"create.display_source.nixie_tube": "Copy Nixie Tubes",
|
||||
"create.display_source.observed_train_name": "Detected Train Name",
|
||||
"create.display_source.player_deaths": "Player Deaths",
|
||||
"create.display_source.read_package_address": "Read Package Address",
|
||||
"create.display_source.redstone_power": "Redstone Power",
|
||||
"create.display_source.redstone_power.display": "Display Format",
|
||||
"create.display_source.redstone_power.number": "Number",
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"values": [
|
||||
"minecraft:fire"
|
||||
]
|
||||
}
|
|
@ -270,7 +270,6 @@ import com.simibubi.create.foundation.data.SharedProperties;
|
|||
import com.simibubi.create.foundation.item.ItemDescription;
|
||||
import com.simibubi.create.foundation.item.UncontainableBlockItem;
|
||||
import com.simibubi.create.foundation.mixin.accessor.BlockLootSubProviderAccessor;
|
||||
import com.simibubi.create.foundation.utility.ColorHandlers;
|
||||
import com.simibubi.create.foundation.utility.DyeHelper;
|
||||
import com.simibubi.create.infrastructure.config.CStress;
|
||||
import com.tterrag.registrate.providers.RegistrateRecipeProvider;
|
||||
|
@ -299,6 +298,7 @@ import net.minecraft.world.item.enchantment.Enchantments;
|
|||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.IronBarsBlock;
|
||||
import net.minecraft.world.level.block.RedStoneWireBlock;
|
||||
import net.minecraft.world.level.block.RotatedPillarBlock;
|
||||
import net.minecraft.world.level.block.SoundType;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
|
@ -1265,7 +1265,8 @@ public class AllBlocks {
|
|||
.transform(pickaxeOnly())
|
||||
.blockstate(new ControllerRailGenerator()::generate)
|
||||
.addLayer(() -> RenderType::cutoutMipped)
|
||||
.color(() -> ColorHandlers::getRedstonePower)
|
||||
.color(() -> () -> (state, world, pos, layer) -> RedStoneWireBlock
|
||||
.getColorForPower(pos != null && world != null ? state.getValue(BlockStateProperties.POWER) : 0))
|
||||
.tag(BlockTags.RAILS)
|
||||
.item()
|
||||
.model((c, p) -> p.generated(c, Create.asResource("block/" + c.getName())))
|
||||
|
@ -1801,6 +1802,7 @@ public class AllBlocks {
|
|||
.transform(displaySource(AllDisplaySources.LIST_ITEMS))
|
||||
.transform(displaySource(AllDisplaySources.COUNT_FLUIDS))
|
||||
.transform(displaySource(AllDisplaySources.LIST_FLUIDS))
|
||||
.transform(displaySource(AllDisplaySources.READ_PACKAGE_ADDRESS))
|
||||
.lang("Smart Observer")
|
||||
.item()
|
||||
.transform(customItemModel("_", "block"))
|
||||
|
|
|
@ -5,7 +5,7 @@ import java.util.Map;
|
|||
import java.util.function.Supplier;
|
||||
|
||||
import com.simibubi.create.api.contraption.ContraptionType;
|
||||
import com.simibubi.create.api.registry.CreateRegistries;
|
||||
import com.simibubi.create.api.registry.CreateBuiltInRegistries;
|
||||
import com.simibubi.create.content.contraptions.Contraption;
|
||||
import com.simibubi.create.content.contraptions.bearing.BearingContraption;
|
||||
import com.simibubi.create.content.contraptions.bearing.ClockworkContraption;
|
||||
|
@ -17,35 +17,29 @@ import com.simibubi.create.content.contraptions.piston.PistonContraption;
|
|||
import com.simibubi.create.content.contraptions.pulley.PulleyContraption;
|
||||
import com.simibubi.create.content.trains.entity.CarriageContraption;
|
||||
|
||||
import net.minecraft.core.Holder;
|
||||
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.neoforge.registries.DeferredRegister;
|
||||
import net.minecraft.core.Holder.Reference;
|
||||
import net.minecraft.core.Registry;
|
||||
|
||||
public class AllContraptionTypes {
|
||||
private static final DeferredRegister<ContraptionType> REGISTER = DeferredRegister.create(CreateRegistries.CONTRAPTION_TYPE, Create.ID);
|
||||
|
||||
public static final Map<String, ContraptionType> BY_LEGACY_NAME = new HashMap<>();
|
||||
|
||||
public static final Holder<ContraptionType> PISTON = register("piston", PistonContraption::new);
|
||||
public static final Holder<ContraptionType> BEARING = register("bearing", BearingContraption::new);
|
||||
public static final Holder<ContraptionType> PULLEY = register("pulley", PulleyContraption::new);
|
||||
public static final Holder<ContraptionType> CLOCKWORK = register("clockwork", ClockworkContraption::new);
|
||||
public static final Holder<ContraptionType> MOUNTED = register("mounted", MountedContraption::new);
|
||||
public static final Holder<ContraptionType> STABILIZED = register("stabilized", StabilizedContraption::new);
|
||||
public static final Holder<ContraptionType> GANTRY = register("gantry", GantryContraption::new);
|
||||
public static final Holder<ContraptionType> CARRIAGE = register("carriage", CarriageContraption::new);
|
||||
public static final Holder<ContraptionType> ELEVATOR = register("elevator", ElevatorContraption::new);
|
||||
public static final Reference<ContraptionType> PISTON = register("piston", PistonContraption::new);
|
||||
public static final Reference<ContraptionType> BEARING = register("bearing", BearingContraption::new);
|
||||
public static final Reference<ContraptionType> PULLEY = register("pulley", PulleyContraption::new);
|
||||
public static final Reference<ContraptionType> CLOCKWORK = register("clockwork", ClockworkContraption::new);
|
||||
public static final Reference<ContraptionType> MOUNTED = register("mounted", MountedContraption::new);
|
||||
public static final Reference<ContraptionType> STABILIZED = register("stabilized", StabilizedContraption::new);
|
||||
public static final Reference<ContraptionType> GANTRY = register("gantry", GantryContraption::new);
|
||||
public static final Reference<ContraptionType> CARRIAGE = register("carriage", CarriageContraption::new);
|
||||
public static final Reference<ContraptionType> ELEVATOR = register("elevator", ElevatorContraption::new);
|
||||
|
||||
private static Holder<ContraptionType> register(String name, Supplier<? extends Contraption> factory) {
|
||||
return REGISTER.register(name, () -> {
|
||||
ContraptionType type = new ContraptionType(factory);
|
||||
BY_LEGACY_NAME.put(name, type);
|
||||
return type;
|
||||
});
|
||||
private static Reference<ContraptionType> register(String name, Supplier<? extends Contraption> factory) {
|
||||
ContraptionType type = new ContraptionType(factory);
|
||||
BY_LEGACY_NAME.put(name, type);
|
||||
|
||||
return Registry.registerForHolder(CreateBuiltInRegistries.CONTRAPTION_TYPE, Create.asResource(name), type);
|
||||
}
|
||||
|
||||
public static void register(IEventBus modEventBus) {
|
||||
REGISTER.register(modEventBus);
|
||||
public static void init() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import com.simibubi.create.content.redstone.displayLink.source.KineticSpeedDispl
|
|||
import com.simibubi.create.content.redstone.displayLink.source.KineticStressDisplaySource;
|
||||
import com.simibubi.create.content.redstone.displayLink.source.NixieTubeDisplaySource;
|
||||
import com.simibubi.create.content.redstone.displayLink.source.ObservedTrainNameSource;
|
||||
import com.simibubi.create.content.redstone.displayLink.source.PackageAddressDisplaySource;
|
||||
import com.simibubi.create.content.redstone.displayLink.source.RedstonePowerDisplaySource;
|
||||
import com.simibubi.create.content.redstone.displayLink.source.ScoreboardDisplaySource;
|
||||
import com.simibubi.create.content.redstone.displayLink.source.StationSummaryDisplaySource;
|
||||
|
@ -83,6 +84,7 @@ public class AllDisplaySources {
|
|||
public static final RegistryEntry<DisplaySource, ItemListDisplaySource> LIST_ITEMS = simple("list_items", ItemListDisplaySource::new);
|
||||
public static final RegistryEntry<DisplaySource, FluidAmountDisplaySource> COUNT_FLUIDS = simple("count_fluids", FluidAmountDisplaySource::new);
|
||||
public static final RegistryEntry<DisplaySource, FluidListDisplaySource> LIST_FLUIDS = simple("list_fluids", FluidListDisplaySource::new);
|
||||
public static final RegistryEntry<DisplaySource, PackageAddressDisplaySource> READ_PACKAGE_ADDRESS = simple("read_package_address", PackageAddressDisplaySource::new);
|
||||
|
||||
public static final RegistryEntry<DisplaySource, ComputerDisplaySource> COMPUTER = REGISTRATE.displaySource("computer", ComputerDisplaySource::new)
|
||||
.onRegisterAfter(Registries.BLOCK_ENTITY_TYPE, source -> {
|
||||
|
|
|
@ -408,6 +408,7 @@ public class AllItems {
|
|||
|
||||
public static final ItemEntry<PotatoCannonItem> POTATO_CANNON =
|
||||
REGISTRATE.item("potato_cannon", PotatoCannonItem::new)
|
||||
.properties(p -> p.durability(100))
|
||||
.model(AssetLookup.itemModelWithPartials())
|
||||
.tag(Tags.Items.ENCHANTABLES)
|
||||
.register();
|
||||
|
|
|
@ -130,6 +130,7 @@ public class AllPartialModels {
|
|||
CHAIN_CONVEYOR_SHAFT = block("chain_conveyor/shaft"),
|
||||
|
||||
FROGPORT_BODY = block("package_frogport/body"), FROGPORT_HEAD = block("package_frogport/head"),
|
||||
FROGPORT_HEAD_GOGGLES = block("package_frogport/head_goggles"),
|
||||
FROGPORT_TONGUE = block("package_frogport/tongue"),
|
||||
POSTBOX_FLAG = block("package_postbox/flag"),
|
||||
|
||||
|
|
|
@ -110,6 +110,7 @@ public class AllTags {
|
|||
FALLBACK_MOUNTED_STORAGE_BLACKLIST,
|
||||
ROOTS,
|
||||
SUGAR_CANE_VARIANTS,
|
||||
NON_HARVESTABLE,
|
||||
|
||||
CORALS,
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@ package com.simibubi.create;
|
|||
|
||||
import java.util.Random;
|
||||
|
||||
import com.simibubi.create.foundation.recipe.AllIngredients;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
@ -28,14 +30,13 @@ import com.simibubi.create.content.schematics.ServerSchematicLoader;
|
|||
import com.simibubi.create.content.trains.GlobalRailwayManager;
|
||||
import com.simibubi.create.content.trains.bogey.BogeySizes;
|
||||
import com.simibubi.create.content.trains.track.AllPortalTracks;
|
||||
import com.simibubi.create.foundation.CreateNBTProcessors;
|
||||
import com.simibubi.create.foundation.advancement.AllAdvancements;
|
||||
import com.simibubi.create.foundation.advancement.AllTriggers;
|
||||
import com.simibubi.create.foundation.data.CreateRegistrate;
|
||||
import com.simibubi.create.foundation.item.ItemDescription;
|
||||
import com.simibubi.create.foundation.item.KineticStats;
|
||||
import com.simibubi.create.foundation.item.TooltipModifier;
|
||||
import com.simibubi.create.foundation.recipe.AllIngredients;
|
||||
import com.simibubi.create.foundation.utility.CreateNBTProcessors;
|
||||
import com.simibubi.create.infrastructure.command.ServerLagger;
|
||||
import com.simibubi.create.infrastructure.config.AllConfigs;
|
||||
import com.simibubi.create.infrastructure.data.CreateDatagen;
|
||||
|
@ -137,10 +138,6 @@ public class Create {
|
|||
AllConfigs.register(modLoadingContext, modContainer);
|
||||
|
||||
// TODO - Make these use Registry.register and move them into the RegisterEvent
|
||||
AllArmInteractionPointTypes.register(modEventBus);
|
||||
AllFanProcessingTypes.register(modEventBus);
|
||||
AllItemAttributeTypes.register(modEventBus);
|
||||
AllContraptionTypes.register(modEventBus);
|
||||
AllPackagePortTargetTypes.register(modEventBus);
|
||||
|
||||
// FIXME: some of these registrations are not thread-safe
|
||||
|
@ -183,6 +180,10 @@ public class Create {
|
|||
}
|
||||
|
||||
public static void onRegister(final RegisterEvent event) {
|
||||
AllArmInteractionPointTypes.init();
|
||||
AllFanProcessingTypes.init();
|
||||
AllItemAttributeTypes.init();
|
||||
AllContraptionTypes.init();
|
||||
AllPotatoProjectileRenderModes.init();
|
||||
AllPotatoProjectileEntityHitActions.init();
|
||||
AllPotatoProjectileBlockHitActions.init();
|
||||
|
|
|
@ -21,9 +21,9 @@ import com.simibubi.create.content.schematics.client.SchematicHandler;
|
|||
import com.simibubi.create.content.trains.GlobalRailwayManager;
|
||||
import com.simibubi.create.foundation.ClientResourceReloadListener;
|
||||
import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsClient;
|
||||
import com.simibubi.create.foundation.model.ModelSwapper;
|
||||
import com.simibubi.create.foundation.ponder.CreatePonderPlugin;
|
||||
import com.simibubi.create.foundation.render.AllInstanceTypes;
|
||||
import com.simibubi.create.foundation.utility.ModelSwapper;
|
||||
import com.simibubi.create.infrastructure.config.AllConfigs;
|
||||
import com.simibubi.create.infrastructure.gui.CreateMainMenuScreen;
|
||||
|
||||
|
@ -43,7 +43,6 @@ import net.minecraft.network.chat.HoverEvent;
|
|||
import net.minecraft.network.chat.MutableComponent;
|
||||
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.fml.common.Mod;
|
||||
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
|
||||
import net.neoforged.neoforge.common.NeoForge;
|
||||
|
@ -67,12 +66,12 @@ public class CreateClient {
|
|||
|
||||
public static final ClientResourceReloadListener RESOURCE_RELOAD_LISTENER = new ClientResourceReloadListener();
|
||||
|
||||
public CreateClient(IEventBus modEventBus) {
|
||||
public CreateClient(net.neoforged.bus.api.IEventBus modEventBus) {
|
||||
onCtorClient(modEventBus);
|
||||
}
|
||||
|
||||
public static void onCtorClient(IEventBus modEventBus) {
|
||||
IEventBus neoEventBus = NeoForge.EVENT_BUS;
|
||||
public static void onCtorClient(net.neoforged.bus.api.IEventBus modEventBus) {
|
||||
net.neoforged.bus.api.IEventBus neoEventBus = NeoForge.EVENT_BUS;
|
||||
|
||||
modEventBus.addListener(CreateClient::clientInit);
|
||||
modEventBus.addListener(AllParticleTypes::registerFactories);
|
||||
|
|
|
@ -4,26 +4,23 @@ 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 com.simibubi.create.content.equipment.potatoCannon.AllPotatoProjectileRenderModes.Billboard;
|
||||
import com.simibubi.create.content.equipment.potatoCannon.AllPotatoProjectileRenderModes.TowardMotion;
|
||||
import com.simibubi.create.content.equipment.potatoCannon.AllPotatoProjectileRenderModes.Tumble;
|
||||
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.Holder.Reference;
|
||||
import net.minecraft.core.HolderSet;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.core.RegistryCodecs;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.data.worldgen.BootstrapContext;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.EntityHitResult;
|
||||
|
@ -53,26 +50,12 @@ public record PotatoCannonProjectileType(HolderSet<Item> items, int reloadTicks,
|
|||
PotatoProjectileBlockHitAction.CODEC.optionalFieldOf("on_entity_hit").forGetter(p -> p.onBlockHit)
|
||||
).apply(i, PotatoCannonProjectileType::new));
|
||||
|
||||
@Nullable
|
||||
public static PotatoCannonProjectileType getTypeForItem(Level level, Item item) {
|
||||
public static Optional<Reference<PotatoCannonProjectileType>> getTypeForItem(RegistryAccess registryAccess, Item item) {
|
||||
// Cache this if it causes performance issues, but it probably won't
|
||||
List<PotatoCannonProjectileType> types = level.registryAccess()
|
||||
.lookupOrThrow(CreateRegistries.POTATO_PROJECTILE_TYPE)
|
||||
return 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()));
|
||||
.filter(ref -> ref.value().items.contains(item.builtInRegistryHolder()))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public boolean preEntityHit(ItemStack stack, EntityHitResult ray) {
|
||||
|
@ -94,8 +77,6 @@ public record PotatoCannonProjectileType(HolderSet<Item> items, int reloadTicks,
|
|||
}
|
||||
|
||||
public static class Builder {
|
||||
private ResourceLocation id;
|
||||
|
||||
private final List<Holder<Item>> items = new ArrayList<>();
|
||||
private int reloadTicks = 10;
|
||||
private int damage = 1;
|
||||
|
@ -112,10 +93,6 @@ public record PotatoCannonProjectileType(HolderSet<Item> items, int reloadTicks,
|
|||
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;
|
||||
|
@ -172,17 +149,17 @@ public record PotatoCannonProjectileType(HolderSet<Item> items, int reloadTicks,
|
|||
}
|
||||
|
||||
public Builder renderBillboard() {
|
||||
renderMode(PotatoProjectileRenderMode.Billboard.INSTANCE);
|
||||
renderMode(Billboard.INSTANCE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder renderTumbling() {
|
||||
renderMode(PotatoProjectileRenderMode.Tumble.INSTANCE);
|
||||
renderMode(Tumble.INSTANCE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder renderTowardMotion(int spriteAngle, float spin) {
|
||||
renderMode(new PotatoProjectileRenderMode.TowardMotion(spriteAngle, spin));
|
||||
renderMode(new TowardMotion(spriteAngle, spin));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -207,8 +184,8 @@ public record PotatoCannonProjectileType(HolderSet<Item> items, int reloadTicks,
|
|||
return this;
|
||||
}
|
||||
|
||||
public void register(BootstrapContext<PotatoCannonProjectileType> ctx) {
|
||||
PotatoCannonProjectileType type = new PotatoCannonProjectileType(
|
||||
public PotatoCannonProjectileType build() {
|
||||
return new PotatoCannonProjectileType(
|
||||
HolderSet.direct(items),
|
||||
reloadTicks,
|
||||
damage,
|
||||
|
@ -225,12 +202,6 @@ public record PotatoCannonProjectileType(HolderSet<Item> items, int reloadTicks,
|
|||
Optional.ofNullable(onEntityHit),
|
||||
Optional.ofNullable(onBlockHit)
|
||||
);
|
||||
ctx.register(ResourceKey.create(CreateRegistries.POTATO_PROJECTILE_TYPE, id), type);
|
||||
}
|
||||
|
||||
public void registerAndAssign(BootstrapContext<PotatoCannonProjectileType> ctx, ItemLike... items) {
|
||||
addItems(items);
|
||||
register(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,23 +4,12 @@ import java.util.function.Function;
|
|||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import com.simibubi.create.api.registry.CreateBuiltInRegistries;
|
||||
import com.simibubi.create.foundation.mixin.accessor.FallingBlockEntityAccessor;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.world.entity.item.FallingBlockEntity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
|
||||
import net.neoforged.neoforge.common.SpecialPlantable;
|
||||
|
||||
public interface PotatoProjectileBlockHitAction {
|
||||
Codec<PotatoProjectileBlockHitAction> CODEC = CreateBuiltInRegistries.POTATO_PROJECTILE_BLOCK_HIT_ACTION.byNameCodec()
|
||||
.dispatch(PotatoProjectileBlockHitAction::codec, Function.identity());
|
||||
|
@ -28,89 +17,4 @@ public interface PotatoProjectileBlockHitAction {
|
|||
boolean execute(LevelAccessor level, ItemStack projectile, BlockHitResult ray);
|
||||
|
||||
MapCodec<? extends PotatoProjectileBlockHitAction> codec();
|
||||
|
||||
record PlantCrop(Holder<Block> cropBlock) implements PotatoProjectileBlockHitAction {
|
||||
public static final MapCodec<PlantCrop> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
BuiltInRegistries.BLOCK.holderByNameCodec().fieldOf("block").forGetter(PlantCrop::cropBlock)
|
||||
).apply(instance, PlantCrop::new));
|
||||
|
||||
public PlantCrop(Block cropBlock) {
|
||||
this(cropBlock.builtInRegistryHolder());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(LevelAccessor level, ItemStack projectile, BlockHitResult ray) {
|
||||
if (level.isClientSide())
|
||||
return true;
|
||||
|
||||
BlockPos hitPos = ray.getBlockPos();
|
||||
if (level instanceof Level l && !l.isLoaded(hitPos))
|
||||
return true;
|
||||
Direction face = ray.getDirection();
|
||||
if (face != Direction.UP)
|
||||
return false;
|
||||
BlockPos placePos = hitPos.relative(face);
|
||||
if (!level.getBlockState(placePos)
|
||||
.canBeReplaced())
|
||||
return false;
|
||||
if (!(cropBlock.value() instanceof SpecialPlantable specialPlantable))
|
||||
return false;
|
||||
if (specialPlantable.canPlacePlantAtPosition(projectile, level, placePos, null))
|
||||
specialPlantable.spawnPlantAtPosition(projectile, level, placePos, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileBlockHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
record PlaceBlockOnGround(Holder<Block> block) implements PotatoProjectileBlockHitAction {
|
||||
public static final MapCodec<PlaceBlockOnGround> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
BuiltInRegistries.BLOCK.holderByNameCodec().fieldOf("block").forGetter(PlaceBlockOnGround::block)
|
||||
).apply(instance, PlaceBlockOnGround::new));
|
||||
|
||||
public PlaceBlockOnGround(Block block) {
|
||||
this(block.builtInRegistryHolder());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(LevelAccessor levelAccessor, ItemStack projectile, BlockHitResult ray) {
|
||||
if (levelAccessor.isClientSide())
|
||||
return true;
|
||||
|
||||
BlockPos hitPos = ray.getBlockPos();
|
||||
if (levelAccessor instanceof Level l && !l.isLoaded(hitPos))
|
||||
return true;
|
||||
Direction face = ray.getDirection();
|
||||
BlockPos placePos = hitPos.relative(face);
|
||||
if (!levelAccessor.getBlockState(placePos)
|
||||
.canBeReplaced())
|
||||
return false;
|
||||
|
||||
if (face == Direction.UP) {
|
||||
levelAccessor.setBlock(placePos, block.value()
|
||||
.defaultBlockState(), 3);
|
||||
} else if (levelAccessor instanceof Level level) {
|
||||
double y = ray.getLocation().y - 0.5;
|
||||
if (!level.isEmptyBlock(placePos.above()))
|
||||
y = Math.min(y, placePos.getY());
|
||||
if (!level.isEmptyBlock(placePos.below()))
|
||||
y = Math.max(y, placePos.getY());
|
||||
|
||||
FallingBlockEntity falling = FallingBlockEntityAccessor.create$callInit(level, placePos.getX() + 0.5, y,
|
||||
placePos.getZ() + 0.5, block.value().defaultBlockState());
|
||||
falling.time = 1;
|
||||
level.addFreshEntity(falling);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileBlockHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,47 +1,13 @@
|
|||
package com.simibubi.create.api.equipment.potatoCannon;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import com.simibubi.create.api.registry.CreateBuiltInRegistries;
|
||||
import com.simibubi.create.foundation.codec.CreateCodecs;
|
||||
|
||||
import net.createmod.catnip.data.WorldAttached;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.util.ExtraCodecs;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.animal.Fox;
|
||||
import net.minecraft.world.entity.monster.ZombieVillager;
|
||||
import net.minecraft.world.food.FoodProperties;
|
||||
import net.minecraft.world.food.FoodProperties.PossibleEffect;
|
||||
import net.minecraft.world.food.Foods;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.component.SuspiciousStewEffects;
|
||||
import net.minecraft.world.item.component.SuspiciousStewEffects.Entry;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.EntityHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import net.neoforged.neoforge.common.util.FakePlayer;
|
||||
import net.neoforged.neoforge.event.EventHooks;
|
||||
import net.neoforged.neoforge.event.entity.EntityTeleportEvent;
|
||||
|
||||
public interface PotatoProjectileEntityHitAction {
|
||||
Codec<PotatoProjectileEntityHitAction> CODEC = CreateBuiltInRegistries.POTATO_PROJECTILE_ENTITY_HIT_ACTION.byNameCodec()
|
||||
|
@ -59,194 +25,4 @@ public interface PotatoProjectileEntityHitAction {
|
|||
boolean execute(ItemStack projectile, EntityHitResult ray, Type type);
|
||||
|
||||
MapCodec<? extends PotatoProjectileEntityHitAction> codec();
|
||||
|
||||
record SetOnFire(int ticks) implements PotatoProjectileEntityHitAction {
|
||||
public static final MapCodec<SetOnFire> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
ExtraCodecs.POSITIVE_INT.fieldOf("ticks").forGetter(SetOnFire::ticks)
|
||||
).apply(instance, SetOnFire::new));
|
||||
|
||||
public static SetOnFire seconds(int seconds) {
|
||||
return new SetOnFire(seconds * 20);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(ItemStack projectile, EntityHitResult ray, Type type) {
|
||||
ray.getEntity()
|
||||
.setRemainingFireTicks(ticks);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileEntityHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
record PotionEffect(Holder<MobEffect> effect, int level, int ticks,
|
||||
boolean recoverable) implements PotatoProjectileEntityHitAction {
|
||||
public static final MapCodec<PotionEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
BuiltInRegistries.MOB_EFFECT.holderByNameCodec().fieldOf("effect").forGetter(PotionEffect::effect),
|
||||
ExtraCodecs.POSITIVE_INT.fieldOf("level").forGetter(PotionEffect::level),
|
||||
ExtraCodecs.POSITIVE_INT.fieldOf("ticks").forGetter(PotionEffect::ticks),
|
||||
Codec.BOOL.fieldOf("recoverable").forGetter(PotionEffect::recoverable)
|
||||
).apply(instance, PotionEffect::new));
|
||||
|
||||
@Override
|
||||
public boolean execute(ItemStack projectile, EntityHitResult ray, Type type) {
|
||||
Entity entity = ray.getEntity();
|
||||
if (entity.level().isClientSide)
|
||||
return true;
|
||||
if (entity instanceof LivingEntity)
|
||||
applyEffect((LivingEntity) entity, new MobEffectInstance(effect, ticks, level - 1));
|
||||
return !recoverable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileEntityHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
record FoodEffects(FoodProperties foodProperty, boolean recoverable) implements PotatoProjectileEntityHitAction {
|
||||
public static final MapCodec<FoodEffects> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
FoodProperties.DIRECT_CODEC.fieldOf("food_property").forGetter(FoodEffects::foodProperty),
|
||||
Codec.BOOL.fieldOf("recoverable").forGetter(FoodEffects::recoverable)
|
||||
).apply(instance, FoodEffects::new));
|
||||
|
||||
@Override
|
||||
public boolean execute(ItemStack projectile, EntityHitResult ray, Type type) {
|
||||
Entity entity = ray.getEntity();
|
||||
if (entity.level().isClientSide)
|
||||
return true;
|
||||
|
||||
if (entity instanceof LivingEntity livingEntity) {
|
||||
for (PossibleEffect possibleEffect : foodProperty.effects()) {
|
||||
if (livingEntity.getRandom().nextFloat() < possibleEffect.probability())
|
||||
applyEffect(livingEntity, new MobEffectInstance(possibleEffect.effect()));
|
||||
}
|
||||
}
|
||||
return !recoverable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileEntityHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
record ChorusTeleport(double teleportDiameter) implements PotatoProjectileEntityHitAction {
|
||||
public static final MapCodec<ChorusTeleport> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
CreateCodecs.POSITIVE_DOUBLE.fieldOf("teleport_diameter").forGetter(ChorusTeleport::teleportDiameter)
|
||||
).apply(instance, ChorusTeleport::new));
|
||||
|
||||
@Override
|
||||
public boolean execute(ItemStack projectile, EntityHitResult ray, Type type) {
|
||||
Entity entity = ray.getEntity();
|
||||
Level level = entity.getCommandSenderWorld();
|
||||
if (level.isClientSide)
|
||||
return true;
|
||||
if (!(entity instanceof LivingEntity livingEntity))
|
||||
return false;
|
||||
|
||||
double entityX = livingEntity.getX();
|
||||
double entityY = livingEntity.getY();
|
||||
double entityZ = livingEntity.getZ();
|
||||
|
||||
for (int teleportTry = 0; teleportTry < 16; ++teleportTry) {
|
||||
double teleportX = entityX + (livingEntity.getRandom()
|
||||
.nextDouble() - 0.5D) * teleportDiameter;
|
||||
double teleportY = Mth.clamp(entityY + (livingEntity.getRandom()
|
||||
.nextInt((int) teleportDiameter) - (int) (teleportDiameter / 2)), 0.0D, level.getHeight() - 1);
|
||||
double teleportZ = entityZ + (livingEntity.getRandom()
|
||||
.nextDouble() - 0.5D) * teleportDiameter;
|
||||
|
||||
EntityTeleportEvent.ChorusFruit event =
|
||||
EventHooks.onChorusFruitTeleport(livingEntity, teleportX, teleportY, teleportZ);
|
||||
if (event.isCanceled())
|
||||
return false;
|
||||
if (livingEntity.randomTeleport(event.getTargetX(), event.getTargetY(), event.getTargetZ(), true)) {
|
||||
if (livingEntity.isPassenger())
|
||||
livingEntity.stopRiding();
|
||||
|
||||
SoundEvent soundevent =
|
||||
livingEntity instanceof Fox ? SoundEvents.FOX_TELEPORT : SoundEvents.CHORUS_FRUIT_TELEPORT;
|
||||
level.playSound(null, entityX, entityY, entityZ, soundevent, SoundSource.PLAYERS, 1.0F, 1.0F);
|
||||
livingEntity.playSound(soundevent, 1.0F, 1.0F);
|
||||
livingEntity.setDeltaMovement(Vec3.ZERO);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileEntityHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
enum CureZombieVillager implements PotatoProjectileEntityHitAction {
|
||||
INSTANCE;
|
||||
|
||||
private static final FoodEffects EFFECT = new FoodEffects(Foods.GOLDEN_APPLE, false);
|
||||
private static final GameProfile ZOMBIE_CONVERTER_NAME =
|
||||
new GameProfile(UUID.fromString("be12d3dc-27d3-4992-8c97-66be53fd49c5"), "Converter");
|
||||
private static final WorldAttached<FakePlayer> ZOMBIE_CONVERTERS =
|
||||
new WorldAttached<>(w -> new FakePlayer((ServerLevel) w, ZOMBIE_CONVERTER_NAME));
|
||||
|
||||
public static final MapCodec<CureZombieVillager> CODEC = MapCodec.unit(INSTANCE);
|
||||
|
||||
@Override
|
||||
public boolean execute(ItemStack projectile, EntityHitResult ray, Type type) {
|
||||
Entity entity = ray.getEntity();
|
||||
Level world = entity.level();
|
||||
|
||||
if (!(entity instanceof ZombieVillager zombieVillager) || !zombieVillager.hasEffect(MobEffects.WEAKNESS))
|
||||
return EFFECT.execute(projectile, ray, type);
|
||||
if (world.isClientSide)
|
||||
return false;
|
||||
|
||||
FakePlayer dummy = ZOMBIE_CONVERTERS.get(world);
|
||||
dummy.setItemInHand(InteractionHand.MAIN_HAND, new ItemStack(Items.GOLDEN_APPLE, 1));
|
||||
zombieVillager.mobInteract(dummy, InteractionHand.MAIN_HAND);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileEntityHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
enum SuspiciousStew implements PotatoProjectileEntityHitAction {
|
||||
INSTANCE;
|
||||
|
||||
public static final MapCodec<SuspiciousStew> CODEC = MapCodec.unit(INSTANCE);
|
||||
|
||||
@Override
|
||||
public boolean execute(ItemStack projectile, EntityHitResult ray, Type type) {
|
||||
if (ray.getEntity() instanceof LivingEntity livingEntity) {
|
||||
SuspiciousStewEffects effects = projectile.getOrDefault(DataComponents.SUSPICIOUS_STEW_EFFECTS, SuspiciousStewEffects.EMPTY);
|
||||
for (Entry effect : effects.effects())
|
||||
livingEntity.addEffect(effect.createEffectInstance());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileEntityHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyEffect(LivingEntity entity, MobEffectInstance effect) {
|
||||
if (effect.getEffect().value().isInstantenous()) {
|
||||
effect.getEffect().value()
|
||||
.applyInstantenousEffect(null, null, entity, effect.getDuration(), 1.0);
|
||||
} else {
|
||||
entity.addEffect(effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,13 @@
|
|||
package com.simibubi.create.api.equipment.potatoCannon;
|
||||
|
||||
import static com.simibubi.create.api.equipment.potatoCannon.PotatoProjectileRenderMode.entityRandom;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import com.simibubi.create.api.registry.CreateBuiltInRegistries;
|
||||
import com.simibubi.create.content.equipment.potatoCannon.PotatoProjectileEntity;
|
||||
|
||||
import dev.engine_room.flywheel.lib.transform.TransformStack;
|
||||
import net.createmod.catnip.math.AngleHelper;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
|
||||
|
@ -29,96 +19,4 @@ public interface PotatoProjectileRenderMode {
|
|||
void transform(PoseStack ms, PotatoProjectileEntity entity, float pt);
|
||||
|
||||
MapCodec<? extends PotatoProjectileRenderMode> codec();
|
||||
|
||||
enum Billboard implements PotatoProjectileRenderMode {
|
||||
INSTANCE;
|
||||
|
||||
public static final MapCodec<Billboard> CODEC = MapCodec.unit(INSTANCE);
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void transform(PoseStack ms, PotatoProjectileEntity entity, float pt) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
Vec3 p1 = mc.getCameraEntity()
|
||||
.getEyePosition(pt);
|
||||
Vec3 diff = entity.getBoundingBox()
|
||||
.getCenter()
|
||||
.subtract(p1);
|
||||
|
||||
TransformStack.of(ms)
|
||||
.rotateYDegrees(AngleHelper.deg(Mth.atan2(diff.x, diff.z)) + 180)
|
||||
.rotateXDegrees(AngleHelper.deg(Mth.atan2(diff.y, Mth.sqrt((float) (diff.x * diff.x + diff.z * diff.z)))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileRenderMode> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
enum Tumble implements PotatoProjectileRenderMode {
|
||||
INSTANCE;
|
||||
|
||||
public static final MapCodec<Tumble> CODEC = MapCodec.unit(INSTANCE);
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void transform(PoseStack ms, PotatoProjectileEntity entity, float pt) {
|
||||
Billboard.INSTANCE.transform(ms, entity, pt);
|
||||
TransformStack.of(ms)
|
||||
.rotateZDegrees((entity.tickCount + pt) * 2 * entityRandom(entity, 16))
|
||||
.rotateXDegrees((entity.tickCount + pt) * entityRandom(entity, 32));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileRenderMode> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
record TowardMotion(int spriteAngleOffset, float spin) implements PotatoProjectileRenderMode {
|
||||
public static final MapCodec<TowardMotion> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
Codec.INT.fieldOf("sprite_angle_offset").forGetter(i -> i.spriteAngleOffset),
|
||||
Codec.FLOAT.fieldOf("spin").forGetter(i -> i.spin)
|
||||
).apply(instance, TowardMotion::new));
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void transform(PoseStack ms, PotatoProjectileEntity entity, float pt) {
|
||||
Vec3 diff = entity.getDeltaMovement();
|
||||
TransformStack.of(ms)
|
||||
.rotateYDegrees(AngleHelper.deg(Mth.atan2(diff.x, diff.z)))
|
||||
.rotateXDegrees(270
|
||||
+ AngleHelper.deg(Mth.atan2(diff.y, -Mth.sqrt((float) (diff.x * diff.x + diff.z * diff.z)))));
|
||||
TransformStack.of(ms)
|
||||
.rotateYDegrees((entity.tickCount + pt) * 20 * spin + entityRandom(entity, 360))
|
||||
.rotateZDegrees(-spriteAngleOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileRenderMode> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
record StuckToEntity(Vec3 offset) implements PotatoProjectileRenderMode {
|
||||
public static final MapCodec<StuckToEntity> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
Vec3.CODEC.fieldOf("offset").forGetter(i -> i.offset)
|
||||
).apply(instance, StuckToEntity::new));
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void transform(PoseStack ms, PotatoProjectileEntity entity, float pt) {
|
||||
TransformStack.of(ms).rotateYDegrees(AngleHelper.deg(Mth.atan2(offset.x, offset.z)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileRenderMode> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
static int entityRandom(Entity entity, int maxValue) {
|
||||
return (System.identityHashCode(entity) * 31) % maxValue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package com.simibubi.create.api.registry;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus.Internal;
|
||||
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.simibubi.create.content.logistics.packagePort.PackagePortTargetType;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.api.behaviour.display.DisplaySource;
|
||||
import com.simibubi.create.api.behaviour.display.DisplayTarget;
|
||||
|
@ -16,22 +16,15 @@ 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;
|
||||
import com.simibubi.create.content.logistics.packagePort.PackagePortTargetType;
|
||||
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.EventBusSubscriber;
|
||||
import net.neoforged.fml.common.EventBusSubscriber.Bus;
|
||||
import net.neoforged.neoforge.registries.DataPackRegistryEvent;
|
||||
|
||||
/**
|
||||
* Keys for registries added by Create.
|
||||
*
|
||||
* @see CreateBuiltInRegistries
|
||||
*/
|
||||
@EventBusSubscriber(bus = Bus.MOD)
|
||||
public class CreateRegistries {
|
||||
public static final ResourceKey<Registry<ArmInteractionPointType>> ARM_INTERACTION_POINT_TYPE = key("arm_interaction_point_type");
|
||||
public static final ResourceKey<Registry<FanProcessingType>> FAN_PROCESSING_TYPE = key("fan_processing_type");
|
||||
|
@ -50,14 +43,4 @@ public class CreateRegistries {
|
|||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,10 @@ import java.util.function.Function;
|
|||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.core.HolderLookup;
|
||||
|
||||
import net.minecraft.core.Vec3i;
|
||||
|
||||
import org.apache.commons.lang3.tuple.MutablePair;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
|
@ -73,7 +77,6 @@ import com.simibubi.create.content.trains.bogey.AbstractBogeyBlock;
|
|||
import com.simibubi.create.foundation.blockEntity.IMultiBlockEntityContainer;
|
||||
import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour;
|
||||
import com.simibubi.create.foundation.utility.BlockHelper;
|
||||
import com.simibubi.create.foundation.utility.ICoordinate;
|
||||
import com.simibubi.create.infrastructure.config.AllConfigs;
|
||||
|
||||
import net.createmod.catnip.data.Iterate;
|
||||
|
@ -86,7 +89,6 @@ import net.minecraft.core.BlockPos;
|
|||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Direction.Axis;
|
||||
import net.minecraft.core.HolderGetter;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
|
@ -1403,7 +1405,7 @@ public abstract class Contraption {
|
|||
public void expandBoundsAroundAxis(Axis axis) {
|
||||
Set<BlockPos> blocks = getBlocks().keySet();
|
||||
|
||||
int radius = (int) (Math.ceil(Math.sqrt(getRadius(blocks, axis))));
|
||||
int radius = (int) (Math.ceil(getRadius(blocks, axis)));
|
||||
|
||||
int maxX = radius + 2;
|
||||
int maxY = radius + 2;
|
||||
|
@ -1412,13 +1414,13 @@ public abstract class Contraption {
|
|||
int minY = -radius - 1;
|
||||
int minZ = -radius - 1;
|
||||
|
||||
if (axis == Direction.Axis.X) {
|
||||
if (axis == Axis.X) {
|
||||
maxX = (int) bounds.maxX;
|
||||
minX = (int) bounds.minX;
|
||||
} else if (axis == Direction.Axis.Y) {
|
||||
} else if (axis == Axis.Y) {
|
||||
maxY = (int) bounds.maxY;
|
||||
minY = (int) bounds.minY;
|
||||
} else if (axis == Direction.Axis.Z) {
|
||||
} else if (axis == Axis.Z) {
|
||||
maxZ = (int) bounds.maxZ;
|
||||
minZ = (int) bounds.minZ;
|
||||
}
|
||||
|
@ -1503,32 +1505,38 @@ public abstract class Contraption {
|
|||
});
|
||||
}
|
||||
|
||||
public static float getRadius(Set<BlockPos> blocks, Direction.Axis axis) {
|
||||
public static double getRadius(Iterable<? extends Vec3i> blocks, Axis axis) {
|
||||
Axis axisA;
|
||||
Axis axisB;
|
||||
|
||||
switch (axis) {
|
||||
case X:
|
||||
return getMaxDistSqr(blocks, BlockPos::getY, BlockPos::getZ);
|
||||
case Y:
|
||||
return getMaxDistSqr(blocks, BlockPos::getX, BlockPos::getZ);
|
||||
case Z:
|
||||
return getMaxDistSqr(blocks, BlockPos::getX, BlockPos::getY);
|
||||
case X -> {
|
||||
axisA = Axis.Y;
|
||||
axisB = Axis.Z;
|
||||
}
|
||||
case Y -> {
|
||||
axisA = Axis.X;
|
||||
axisB = Axis.Z;
|
||||
}
|
||||
case Z -> {
|
||||
axisA = Axis.X;
|
||||
axisB = Axis.Y;
|
||||
}
|
||||
default -> throw new IllegalStateException("Unexpected value: " + axis);
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Impossible axis");
|
||||
}
|
||||
int maxDistSq = 0;
|
||||
for (Vec3i vec : blocks) {
|
||||
int a = vec.get(axisA);
|
||||
int b = vec.get(axisB);
|
||||
|
||||
public static float getMaxDistSqr(Set<BlockPos> blocks, ICoordinate one, ICoordinate other) {
|
||||
float maxDistSq = -1;
|
||||
for (BlockPos pos : blocks) {
|
||||
float a = one.get(pos);
|
||||
float b = other.get(pos);
|
||||
|
||||
float distSq = a * a + b * b;
|
||||
int distSq = a * a + b * b;
|
||||
|
||||
if (distSq > maxDistSq)
|
||||
maxDistSq = distSq;
|
||||
}
|
||||
|
||||
return maxDistSq;
|
||||
return Math.sqrt(maxDistSq);
|
||||
}
|
||||
|
||||
public MountedStorageManager getStorage() {
|
||||
|
|
|
@ -57,12 +57,15 @@ public class HarvesterMovementBehaviour implements MovementBehaviour {
|
|||
@Override
|
||||
public void visitNewPosition(MovementContext context, BlockPos pos) {
|
||||
Level world = context.world;
|
||||
BlockState stateVisited = world.getBlockState(pos);
|
||||
boolean notCropButCuttable = false;
|
||||
|
||||
if (world.isClientSide)
|
||||
return;
|
||||
|
||||
BlockState stateVisited = world.getBlockState(pos);
|
||||
if (stateVisited.isAir() || AllBlockTags.NON_HARVESTABLE.matches(stateVisited))
|
||||
return;
|
||||
|
||||
boolean notCropButCuttable = false;
|
||||
|
||||
if (!isValidCrop(world, pos, stateVisited)) {
|
||||
if (isValidOther(world, pos, stateVisited))
|
||||
notCropButCuttable = true;
|
||||
|
|
|
@ -1,13 +1,25 @@
|
|||
package com.simibubi.create.content.equipment.potatoCannon;
|
||||
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
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 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.Registry;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.world.entity.item.FallingBlockEntity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
|
||||
import net.neoforged.neoforge.common.SpecialPlantable;
|
||||
|
||||
public class AllPotatoProjectileBlockHitActions {
|
||||
public static void init() {
|
||||
|
@ -18,4 +30,89 @@ public class AllPotatoProjectileBlockHitActions {
|
|||
private static void register(String name, MapCodec<? extends PotatoProjectileBlockHitAction> codec) {
|
||||
Registry.register(CreateBuiltInRegistries.POTATO_PROJECTILE_BLOCK_HIT_ACTION, Create.asResource(name), codec);
|
||||
}
|
||||
|
||||
public record PlantCrop(Holder<Block> cropBlock) implements PotatoProjectileBlockHitAction {
|
||||
public static final MapCodec<PlantCrop> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
BuiltInRegistries.BLOCK.holderByNameCodec().fieldOf("block").forGetter(PlantCrop::cropBlock)
|
||||
).apply(instance, PlantCrop::new));
|
||||
|
||||
public PlantCrop(Block cropBlock) {
|
||||
this(cropBlock.builtInRegistryHolder());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(LevelAccessor level, ItemStack projectile, BlockHitResult ray) {
|
||||
if (level.isClientSide())
|
||||
return true;
|
||||
|
||||
BlockPos hitPos = ray.getBlockPos();
|
||||
if (level instanceof Level l && !l.isLoaded(hitPos))
|
||||
return true;
|
||||
Direction face = ray.getDirection();
|
||||
if (face != Direction.UP)
|
||||
return false;
|
||||
BlockPos placePos = hitPos.relative(face);
|
||||
if (!level.getBlockState(placePos)
|
||||
.canBeReplaced())
|
||||
return false;
|
||||
if (!(cropBlock.value() instanceof SpecialPlantable specialPlantable))
|
||||
return false;
|
||||
if (specialPlantable.canPlacePlantAtPosition(projectile, level, placePos, null))
|
||||
specialPlantable.spawnPlantAtPosition(projectile, level, placePos, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileBlockHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
public record PlaceBlockOnGround(Holder<Block> block) implements PotatoProjectileBlockHitAction {
|
||||
public static final MapCodec<PlaceBlockOnGround> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
BuiltInRegistries.BLOCK.holderByNameCodec().fieldOf("block").forGetter(PlaceBlockOnGround::block)
|
||||
).apply(instance, PlaceBlockOnGround::new));
|
||||
|
||||
public PlaceBlockOnGround(Block block) {
|
||||
this(block.builtInRegistryHolder());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(LevelAccessor levelAccessor, ItemStack projectile, BlockHitResult ray) {
|
||||
if (levelAccessor.isClientSide())
|
||||
return true;
|
||||
|
||||
BlockPos hitPos = ray.getBlockPos();
|
||||
if (levelAccessor instanceof Level l && !l.isLoaded(hitPos))
|
||||
return true;
|
||||
Direction face = ray.getDirection();
|
||||
BlockPos placePos = hitPos.relative(face);
|
||||
if (!levelAccessor.getBlockState(placePos)
|
||||
.canBeReplaced())
|
||||
return false;
|
||||
|
||||
if (face == Direction.UP) {
|
||||
levelAccessor.setBlock(placePos, block.value()
|
||||
.defaultBlockState(), 3);
|
||||
} else if (levelAccessor instanceof Level level) {
|
||||
double y = ray.getLocation().y - 0.5;
|
||||
if (!level.isEmptyBlock(placePos.above()))
|
||||
y = Math.min(y, placePos.getY());
|
||||
if (!level.isEmptyBlock(placePos.below()))
|
||||
y = Math.max(y, placePos.getY());
|
||||
|
||||
FallingBlockEntity falling = FallingBlockEntityAccessor.create$callInit(level, placePos.getX() + 0.5, y,
|
||||
placePos.getZ() + 0.5, block.value().defaultBlockState());
|
||||
falling.time = 1;
|
||||
level.addFreshEntity(falling);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileBlockHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,49 @@
|
|||
package com.simibubi.create.content.equipment.potatoCannon;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import com.simibubi.create.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 com.simibubi.create.foundation.codec.CreateCodecs;
|
||||
|
||||
import net.createmod.catnip.data.WorldAttached;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.util.ExtraCodecs;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.animal.Fox;
|
||||
import net.minecraft.world.entity.monster.ZombieVillager;
|
||||
import net.minecraft.world.food.FoodProperties;
|
||||
import net.minecraft.world.food.FoodProperties.PossibleEffect;
|
||||
import net.minecraft.world.food.Foods;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.component.SuspiciousStewEffects;
|
||||
import net.minecraft.world.item.component.SuspiciousStewEffects.Entry;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.EntityHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import net.neoforged.neoforge.common.util.FakePlayer;
|
||||
import net.neoforged.neoforge.event.EventHooks;
|
||||
import net.neoforged.neoforge.event.entity.EntityTeleportEvent;
|
||||
|
||||
public class AllPotatoProjectileEntityHitActions {
|
||||
public static void init() {
|
||||
|
@ -26,4 +58,195 @@ public class AllPotatoProjectileEntityHitActions {
|
|||
private static void register(String name, MapCodec<? extends PotatoProjectileEntityHitAction> codec) {
|
||||
Registry.register(CreateBuiltInRegistries.POTATO_PROJECTILE_ENTITY_HIT_ACTION, Create.asResource(name), codec);
|
||||
}
|
||||
|
||||
public record SetOnFire(int ticks) implements PotatoProjectileEntityHitAction {
|
||||
public static final MapCodec<SetOnFire> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
ExtraCodecs.POSITIVE_INT.fieldOf("ticks").forGetter(SetOnFire::ticks)
|
||||
).apply(instance, SetOnFire::new));
|
||||
|
||||
public static SetOnFire seconds(int seconds) {
|
||||
return new SetOnFire(seconds * 20);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(ItemStack projectile, EntityHitResult ray, Type type) {
|
||||
ray.getEntity()
|
||||
.setRemainingFireTicks(ticks);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileEntityHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
public record PotionEffect(Holder<MobEffect> effect, int level, int ticks,
|
||||
boolean recoverable) implements PotatoProjectileEntityHitAction {
|
||||
public static final MapCodec<PotionEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
BuiltInRegistries.MOB_EFFECT.holderByNameCodec().fieldOf("effect").forGetter(PotionEffect::effect),
|
||||
ExtraCodecs.POSITIVE_INT.fieldOf("level").forGetter(PotionEffect::level),
|
||||
ExtraCodecs.POSITIVE_INT.fieldOf("ticks").forGetter(PotionEffect::ticks),
|
||||
Codec.BOOL.fieldOf("recoverable").forGetter(PotionEffect::recoverable)
|
||||
).apply(instance, PotionEffect::new));
|
||||
|
||||
@Override
|
||||
public boolean execute(ItemStack projectile, EntityHitResult ray, Type type) {
|
||||
Entity entity = ray.getEntity();
|
||||
if (entity.level().isClientSide)
|
||||
return true;
|
||||
if (entity instanceof LivingEntity)
|
||||
applyEffect((LivingEntity) entity, new MobEffectInstance(effect, ticks, level - 1));
|
||||
return !recoverable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileEntityHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
public record FoodEffects(FoodProperties foodProperty,
|
||||
boolean recoverable) implements PotatoProjectileEntityHitAction {
|
||||
public static final MapCodec<FoodEffects> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
FoodProperties.DIRECT_CODEC.fieldOf("food_property").forGetter(FoodEffects::foodProperty),
|
||||
Codec.BOOL.fieldOf("recoverable").forGetter(FoodEffects::recoverable)
|
||||
).apply(instance, FoodEffects::new));
|
||||
|
||||
@Override
|
||||
public boolean execute(ItemStack projectile, EntityHitResult ray, Type type) {
|
||||
Entity entity = ray.getEntity();
|
||||
if (entity.level().isClientSide)
|
||||
return true;
|
||||
|
||||
if (entity instanceof LivingEntity livingEntity) {
|
||||
for (PossibleEffect effect : foodProperty.effects()) {
|
||||
if (livingEntity.getRandom().nextFloat() < effect.probability())
|
||||
applyEffect(livingEntity, effect.effect());
|
||||
}
|
||||
}
|
||||
return !recoverable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileEntityHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
public record ChorusTeleport(double teleportDiameter) implements PotatoProjectileEntityHitAction {
|
||||
public static final MapCodec<ChorusTeleport> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
CreateCodecs.POSITIVE_DOUBLE.fieldOf("teleport_diameter").forGetter(ChorusTeleport::teleportDiameter)
|
||||
).apply(instance, ChorusTeleport::new));
|
||||
|
||||
@Override
|
||||
public boolean execute(ItemStack projectile, EntityHitResult ray, Type type) {
|
||||
Entity entity = ray.getEntity();
|
||||
Level level = entity.getCommandSenderWorld();
|
||||
if (level.isClientSide)
|
||||
return true;
|
||||
if (!(entity instanceof LivingEntity livingEntity))
|
||||
return false;
|
||||
|
||||
double entityX = livingEntity.getX();
|
||||
double entityY = livingEntity.getY();
|
||||
double entityZ = livingEntity.getZ();
|
||||
|
||||
for (int teleportTry = 0; teleportTry < 16; ++teleportTry) {
|
||||
double teleportX = entityX + (livingEntity.getRandom()
|
||||
.nextDouble() - 0.5D) * teleportDiameter;
|
||||
double teleportY = Mth.clamp(entityY + (livingEntity.getRandom()
|
||||
.nextInt((int) teleportDiameter) - (int) (teleportDiameter / 2)), 0.0D, level.getHeight() - 1);
|
||||
double teleportZ = entityZ + (livingEntity.getRandom()
|
||||
.nextDouble() - 0.5D) * teleportDiameter;
|
||||
|
||||
EntityTeleportEvent.ChorusFruit event =
|
||||
EventHooks.onChorusFruitTeleport(livingEntity, teleportX, teleportY, teleportZ);
|
||||
if (event.isCanceled())
|
||||
return false;
|
||||
if (livingEntity.randomTeleport(event.getTargetX(), event.getTargetY(), event.getTargetZ(), true)) {
|
||||
if (livingEntity.isPassenger())
|
||||
livingEntity.stopRiding();
|
||||
|
||||
SoundEvent soundevent =
|
||||
livingEntity instanceof Fox ? SoundEvents.FOX_TELEPORT : SoundEvents.CHORUS_FRUIT_TELEPORT;
|
||||
level.playSound(null, entityX, entityY, entityZ, soundevent, SoundSource.PLAYERS, 1.0F, 1.0F);
|
||||
livingEntity.playSound(soundevent, 1.0F, 1.0F);
|
||||
livingEntity.setDeltaMovement(Vec3.ZERO);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileEntityHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
public enum CureZombieVillager implements PotatoProjectileEntityHitAction {
|
||||
INSTANCE;
|
||||
|
||||
private static final FoodEffects EFFECT = new FoodEffects(Foods.GOLDEN_APPLE, false);
|
||||
private static final GameProfile ZOMBIE_CONVERTER_NAME =
|
||||
new GameProfile(UUID.fromString("be12d3dc-27d3-4992-8c97-66be53fd49c5"), "Converter");
|
||||
private static final WorldAttached<FakePlayer> ZOMBIE_CONVERTERS =
|
||||
new WorldAttached<>(w -> new FakePlayer((ServerLevel) w, ZOMBIE_CONVERTER_NAME));
|
||||
|
||||
public static final MapCodec<CureZombieVillager> CODEC = MapCodec.unit(INSTANCE);
|
||||
|
||||
@Override
|
||||
public boolean execute(ItemStack projectile, EntityHitResult ray, Type type) {
|
||||
Entity entity = ray.getEntity();
|
||||
Level world = entity.level();
|
||||
|
||||
if (!(entity instanceof ZombieVillager zombieVillager) || !zombieVillager.hasEffect(MobEffects.WEAKNESS))
|
||||
return EFFECT.execute(projectile, ray, type);
|
||||
if (world.isClientSide)
|
||||
return false;
|
||||
|
||||
FakePlayer dummy = ZOMBIE_CONVERTERS.get(world);
|
||||
dummy.setItemInHand(InteractionHand.MAIN_HAND, new ItemStack(Items.GOLDEN_APPLE, 1));
|
||||
zombieVillager.mobInteract(dummy, InteractionHand.MAIN_HAND);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileEntityHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
public enum SuspiciousStew implements PotatoProjectileEntityHitAction {
|
||||
INSTANCE;
|
||||
|
||||
public static final MapCodec<SuspiciousStew> CODEC = MapCodec.unit(INSTANCE);
|
||||
|
||||
@Override
|
||||
public boolean execute(ItemStack projectile, EntityHitResult ray, Type type) {
|
||||
if (ray.getEntity() instanceof LivingEntity livingEntity) {
|
||||
SuspiciousStewEffects stew = projectile.getOrDefault(DataComponents.SUSPICIOUS_STEW_EFFECTS, SuspiciousStewEffects.EMPTY);
|
||||
for (Entry effect : stew.effects())
|
||||
livingEntity.addEffect(effect.createEffectInstance());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileEntityHitAction> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyEffect(LivingEntity entity, MobEffectInstance effect) {
|
||||
if (effect.getEffect().value().isInstantenous()) {
|
||||
effect.getEffect().value()
|
||||
.applyInstantenousEffect(null, null, entity, effect.getDuration(), 1.0);
|
||||
} else {
|
||||
entity.addEffect(effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,23 @@
|
|||
package com.simibubi.create.content.equipment.potatoCannon;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import com.simibubi.create.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 dev.engine_room.flywheel.lib.transform.TransformStack;
|
||||
import net.createmod.catnip.math.AngleHelper;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
|
||||
public class AllPotatoProjectileRenderModes {
|
||||
public static void init() {
|
||||
|
@ -23,4 +30,96 @@ public class AllPotatoProjectileRenderModes {
|
|||
private static void register(String name, MapCodec<? extends PotatoProjectileRenderMode> codec) {
|
||||
Registry.register(CreateBuiltInRegistries.POTATO_PROJECTILE_RENDER_MODE, Create.asResource(name), codec);
|
||||
}
|
||||
|
||||
public enum Billboard implements PotatoProjectileRenderMode {
|
||||
INSTANCE;
|
||||
|
||||
public static final MapCodec<Billboard> CODEC = MapCodec.unit(INSTANCE);
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void transform(PoseStack ms, PotatoProjectileEntity entity, float pt) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
Vec3 p1 = mc.getCameraEntity()
|
||||
.getEyePosition(pt);
|
||||
Vec3 diff = entity.getBoundingBox()
|
||||
.getCenter()
|
||||
.subtract(p1);
|
||||
|
||||
TransformStack.of(ms)
|
||||
.rotateYDegrees(AngleHelper.deg(Mth.atan2(diff.x, diff.z)) + 180)
|
||||
.rotateXDegrees(AngleHelper.deg(Mth.atan2(diff.y, Mth.sqrt((float) (diff.x * diff.x + diff.z * diff.z)))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileRenderMode> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Tumble implements PotatoProjectileRenderMode {
|
||||
INSTANCE;
|
||||
|
||||
public static final MapCodec<Tumble> CODEC = MapCodec.unit(INSTANCE);
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void transform(PoseStack ms, PotatoProjectileEntity entity, float pt) {
|
||||
Billboard.INSTANCE.transform(ms, entity, pt);
|
||||
TransformStack.of(ms)
|
||||
.rotateZDegrees((entity.tickCount + pt) * 2 * entityRandom(entity, 16))
|
||||
.rotateXDegrees((entity.tickCount + pt) * entityRandom(entity, 32));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileRenderMode> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
public record TowardMotion(int spriteAngleOffset, float spin) implements PotatoProjectileRenderMode {
|
||||
public static final MapCodec<TowardMotion> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
Codec.INT.fieldOf("sprite_angle_offset").forGetter(i -> i.spriteAngleOffset),
|
||||
Codec.FLOAT.fieldOf("spin").forGetter(i -> i.spin)
|
||||
).apply(instance, TowardMotion::new));
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void transform(PoseStack ms, PotatoProjectileEntity entity, float pt) {
|
||||
Vec3 diff = entity.getDeltaMovement();
|
||||
TransformStack.of(ms)
|
||||
.rotateYDegrees(AngleHelper.deg(Mth.atan2(diff.x, diff.z)))
|
||||
.rotateXDegrees(270
|
||||
+ AngleHelper.deg(Mth.atan2(diff.y, -Mth.sqrt((float) (diff.x * diff.x + diff.z * diff.z)))));
|
||||
TransformStack.of(ms)
|
||||
.rotateYDegrees((entity.tickCount + pt) * 20 * spin + entityRandom(entity, 360))
|
||||
.rotateZDegrees(-spriteAngleOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileRenderMode> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
public record StuckToEntity(Vec3 offset) implements PotatoProjectileRenderMode {
|
||||
public static final MapCodec<StuckToEntity> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
Vec3.CODEC.fieldOf("offset").forGetter(i -> i.offset)
|
||||
).apply(instance, StuckToEntity::new));
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void transform(PoseStack ms, PotatoProjectileEntity entity, float pt) {
|
||||
TransformStack.of(ms).rotateYDegrees(AngleHelper.deg(Mth.atan2(offset.x, offset.z)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends PotatoProjectileRenderMode> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
private static int entityRandom(Entity entity, int maxValue) {
|
||||
return (System.identityHashCode(entity) * 31) % maxValue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,15 +3,15 @@ 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 com.simibubi.create.content.equipment.potatoCannon.AllPotatoProjectileBlockHitActions.PlaceBlockOnGround;
|
||||
import com.simibubi.create.content.equipment.potatoCannon.AllPotatoProjectileBlockHitActions.PlantCrop;
|
||||
import com.simibubi.create.content.equipment.potatoCannon.AllPotatoProjectileEntityHitActions.ChorusTeleport;
|
||||
import com.simibubi.create.content.equipment.potatoCannon.AllPotatoProjectileEntityHitActions.CureZombieVillager;
|
||||
import com.simibubi.create.content.equipment.potatoCannon.AllPotatoProjectileEntityHitActions.FoodEffects;
|
||||
import com.simibubi.create.content.equipment.potatoCannon.AllPotatoProjectileEntityHitActions.PotionEffect;
|
||||
import com.simibubi.create.content.equipment.potatoCannon.AllPotatoProjectileEntityHitActions.SetOnFire;
|
||||
import com.simibubi.create.content.equipment.potatoCannon.AllPotatoProjectileEntityHitActions.SuspiciousStew;
|
||||
|
||||
import net.minecraft.data.worldgen.BootstrapContext;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
|
@ -21,32 +21,34 @@ 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 final ResourceKey<PotatoCannonProjectileType> FALLBACK = ResourceKey.create(CreateRegistries.POTATO_PROJECTILE_TYPE, Create.asResource("fallback"));
|
||||
|
||||
public static void bootstrap(BootstrapContext<PotatoCannonProjectileType> ctx) {
|
||||
create("fallback")
|
||||
register(ctx, "fallback", new PotatoCannonProjectileType.Builder()
|
||||
.damage(0)
|
||||
.register(ctx);
|
||||
.build());
|
||||
|
||||
create("potato")
|
||||
register(ctx, "potato", new PotatoCannonProjectileType.Builder()
|
||||
.damage(5)
|
||||
.reloadTicks(15)
|
||||
.velocity(1.25f)
|
||||
.knockback(1.5f)
|
||||
.renderTumbling()
|
||||
.onBlockHit(new PlantCrop(Blocks.POTATOES))
|
||||
.registerAndAssign(ctx, Items.POTATO);
|
||||
.addItems(Items.POTATO)
|
||||
.build());
|
||||
|
||||
create("baked_potato")
|
||||
register(ctx, "baked_potato", new PotatoCannonProjectileType.Builder()
|
||||
.damage(5)
|
||||
.reloadTicks(15)
|
||||
.velocity(1.25f)
|
||||
.knockback(0.5f)
|
||||
.renderTumbling()
|
||||
.preEntityHit(SetOnFire.seconds(3))
|
||||
.registerAndAssign(ctx, Items.BAKED_POTATO);
|
||||
.addItems(Items.BAKED_POTATO)
|
||||
.build());
|
||||
|
||||
create("carrot")
|
||||
register(ctx, "carrot", new PotatoCannonProjectileType.Builder()
|
||||
.damage(4)
|
||||
.reloadTicks(12)
|
||||
.velocity(1.45f)
|
||||
|
@ -54,18 +56,20 @@ public class AllPotatoProjectileTypes {
|
|||
.renderTowardMotion(140, 1)
|
||||
.soundPitch(1.5f)
|
||||
.onBlockHit(new PlantCrop(Blocks.CARROTS))
|
||||
.registerAndAssign(ctx, Items.CARROT);
|
||||
.addItems(Items.CARROT)
|
||||
.build());
|
||||
|
||||
create("golden_carrot")
|
||||
register(ctx, "golden_carrot", new PotatoCannonProjectileType.Builder()
|
||||
.damage(12)
|
||||
.reloadTicks(15)
|
||||
.velocity(1.45f)
|
||||
.knockback(0.5f)
|
||||
.renderTowardMotion(140, 2)
|
||||
.soundPitch(1.5f)
|
||||
.registerAndAssign(ctx, Items.GOLDEN_CARROT);
|
||||
.addItems(Items.GOLDEN_CARROT)
|
||||
.build());
|
||||
|
||||
create("sweet_berry")
|
||||
register(ctx, "sweet_berry", new PotatoCannonProjectileType.Builder()
|
||||
.damage(3)
|
||||
.reloadTicks(10)
|
||||
.knockback(0.1f)
|
||||
|
@ -73,9 +77,10 @@ public class AllPotatoProjectileTypes {
|
|||
.renderTumbling()
|
||||
.splitInto(3)
|
||||
.soundPitch(1.25f)
|
||||
.registerAndAssign(ctx, Items.SWEET_BERRIES);
|
||||
.addItems(Items.SWEET_BERRIES)
|
||||
.build());
|
||||
|
||||
create("glow_berry")
|
||||
register(ctx, "glow_berry", new PotatoCannonProjectileType.Builder()
|
||||
.damage(2)
|
||||
.reloadTicks(10)
|
||||
.knockback(0.05f)
|
||||
|
@ -84,9 +89,10 @@ public class AllPotatoProjectileTypes {
|
|||
.splitInto(2)
|
||||
.soundPitch(1.2f)
|
||||
.onEntityHit(new PotionEffect(MobEffects.GLOWING, 1, 200, false))
|
||||
.registerAndAssign(ctx, Items.GLOW_BERRIES);
|
||||
.addItems(Items.GLOW_BERRIES)
|
||||
.build());
|
||||
|
||||
create("chocolate_berry")
|
||||
register(ctx, "chocolate_berry", new PotatoCannonProjectileType.Builder()
|
||||
.damage(4)
|
||||
.reloadTicks(10)
|
||||
.knockback(0.2f)
|
||||
|
@ -94,36 +100,40 @@ public class AllPotatoProjectileTypes {
|
|||
.renderTumbling()
|
||||
.splitInto(3)
|
||||
.soundPitch(1.25f)
|
||||
.registerAndAssign(ctx, AllItems.CHOCOLATE_BERRIES.get());
|
||||
.addItems(AllItems.CHOCOLATE_BERRIES.get())
|
||||
.build());
|
||||
|
||||
create("poison_potato")
|
||||
register(ctx, "poison_potato", new PotatoCannonProjectileType.Builder()
|
||||
.damage(5)
|
||||
.reloadTicks(15)
|
||||
.knockback(0.05f)
|
||||
.velocity(1.25f)
|
||||
.renderTumbling()
|
||||
.onEntityHit(new PotionEffect(MobEffects.POISON, 1, 160, true))
|
||||
.registerAndAssign(ctx, Items.POISONOUS_POTATO);
|
||||
.addItems(Items.POISONOUS_POTATO)
|
||||
.build());
|
||||
|
||||
create("chorus_fruit")
|
||||
register(ctx, "chorus_fruit", new PotatoCannonProjectileType.Builder()
|
||||
.damage(3)
|
||||
.reloadTicks(15)
|
||||
.velocity(1.20f)
|
||||
.knockback(0.05f)
|
||||
.renderTumbling()
|
||||
.onEntityHit(new ChorusTeleport(20))
|
||||
.registerAndAssign(ctx, Items.CHORUS_FRUIT);
|
||||
.addItems(Items.CHORUS_FRUIT)
|
||||
.build());
|
||||
|
||||
create("apple")
|
||||
register(ctx, "apple", new PotatoCannonProjectileType.Builder()
|
||||
.damage(5)
|
||||
.reloadTicks(10)
|
||||
.velocity(1.45f)
|
||||
.knockback(0.5f)
|
||||
.renderTumbling()
|
||||
.soundPitch(1.1f)
|
||||
.registerAndAssign(ctx, Items.APPLE);
|
||||
.addItems(Items.APPLE)
|
||||
.build());
|
||||
|
||||
create("honeyed_apple")
|
||||
register(ctx, "honeyed_apple", new PotatoCannonProjectileType.Builder()
|
||||
.damage(6)
|
||||
.reloadTicks(15)
|
||||
.velocity(1.35f)
|
||||
|
@ -131,9 +141,10 @@ public class AllPotatoProjectileTypes {
|
|||
.renderTumbling()
|
||||
.soundPitch(1.1f)
|
||||
.onEntityHit(new PotionEffect(MobEffects.MOVEMENT_SLOWDOWN, 2, 160, true))
|
||||
.registerAndAssign(ctx, AllItems.HONEYED_APPLE.get());
|
||||
.addItems(AllItems.HONEYED_APPLE.get())
|
||||
.build());
|
||||
|
||||
create("golden_apple")
|
||||
register(ctx, "golden_apple", new PotatoCannonProjectileType.Builder()
|
||||
.damage(1)
|
||||
.reloadTicks(100)
|
||||
.velocity(1.45f)
|
||||
|
@ -141,9 +152,10 @@ public class AllPotatoProjectileTypes {
|
|||
.renderTumbling()
|
||||
.soundPitch(1.1f)
|
||||
.onEntityHit(CureZombieVillager.INSTANCE)
|
||||
.registerAndAssign(ctx, Items.GOLDEN_APPLE);
|
||||
.addItems(Items.GOLDEN_APPLE)
|
||||
.build());
|
||||
|
||||
create("enchanted_golden_apple")
|
||||
register(ctx, "enchanted_golden_apple", new PotatoCannonProjectileType.Builder()
|
||||
.damage(1)
|
||||
.reloadTicks(100)
|
||||
.velocity(1.45f)
|
||||
|
@ -151,27 +163,30 @@ public class AllPotatoProjectileTypes {
|
|||
.renderTumbling()
|
||||
.soundPitch(1.1f)
|
||||
.onEntityHit(new FoodEffects(Foods.ENCHANTED_GOLDEN_APPLE, false))
|
||||
.registerAndAssign(ctx, Items.ENCHANTED_GOLDEN_APPLE);
|
||||
.addItems(Items.ENCHANTED_GOLDEN_APPLE)
|
||||
.build());
|
||||
|
||||
create("beetroot")
|
||||
register(ctx, "beetroot", new PotatoCannonProjectileType.Builder()
|
||||
.damage(2)
|
||||
.reloadTicks(5)
|
||||
.velocity(1.6f)
|
||||
.knockback(0.1f)
|
||||
.renderTowardMotion(140, 2)
|
||||
.soundPitch(1.6f)
|
||||
.registerAndAssign(ctx, Items.BEETROOT);
|
||||
.addItems(Items.BEETROOT)
|
||||
.build());
|
||||
|
||||
create("melon_slice")
|
||||
register(ctx, "melon_slice", new PotatoCannonProjectileType.Builder()
|
||||
.damage(3)
|
||||
.reloadTicks(8)
|
||||
.knockback(0.1f)
|
||||
.velocity(1.45f)
|
||||
.renderTumbling()
|
||||
.soundPitch(1.5f)
|
||||
.registerAndAssign(ctx, Items.MELON_SLICE);
|
||||
.addItems(Items.MELON_SLICE)
|
||||
.build());
|
||||
|
||||
create("glistering_melon")
|
||||
register(ctx, "glistering_melon", new PotatoCannonProjectileType.Builder()
|
||||
.damage(5)
|
||||
.reloadTicks(8)
|
||||
.knockback(0.1f)
|
||||
|
@ -179,9 +194,10 @@ public class AllPotatoProjectileTypes {
|
|||
.renderTumbling()
|
||||
.soundPitch(1.5f)
|
||||
.onEntityHit(new PotionEffect(MobEffects.GLOWING, 1, 100, true))
|
||||
.registerAndAssign(ctx, Items.GLISTERING_MELON_SLICE);
|
||||
.addItems(Items.GLISTERING_MELON_SLICE)
|
||||
.build());
|
||||
|
||||
create("melon_block")
|
||||
register(ctx, "melon_block", new PotatoCannonProjectileType.Builder()
|
||||
.damage(8)
|
||||
.reloadTicks(20)
|
||||
.knockback(2.0f)
|
||||
|
@ -189,9 +205,10 @@ public class AllPotatoProjectileTypes {
|
|||
.renderTumbling()
|
||||
.soundPitch(0.9f)
|
||||
.onBlockHit(new PlaceBlockOnGround(Blocks.MELON))
|
||||
.registerAndAssign(ctx, Blocks.MELON);
|
||||
.addItems(Blocks.MELON)
|
||||
.build());
|
||||
|
||||
create("pumpkin_block")
|
||||
register(ctx, "pumpkin_block", new PotatoCannonProjectileType.Builder()
|
||||
.damage(6)
|
||||
.reloadTicks(15)
|
||||
.knockback(2.0f)
|
||||
|
@ -199,9 +216,10 @@ public class AllPotatoProjectileTypes {
|
|||
.renderTumbling()
|
||||
.soundPitch(0.9f)
|
||||
.onBlockHit(new PlaceBlockOnGround(Blocks.PUMPKIN))
|
||||
.registerAndAssign(ctx, Blocks.PUMPKIN);
|
||||
.addItems(Blocks.PUMPKIN)
|
||||
.build());
|
||||
|
||||
create("pumpkin_pie")
|
||||
register(ctx, "pumpkin_pie", new PotatoCannonProjectileType.Builder()
|
||||
.damage(7)
|
||||
.reloadTicks(15)
|
||||
.knockback(0.05f)
|
||||
|
@ -209,18 +227,20 @@ public class AllPotatoProjectileTypes {
|
|||
.renderTumbling()
|
||||
.sticky()
|
||||
.soundPitch(1.1f)
|
||||
.registerAndAssign(ctx, Items.PUMPKIN_PIE);
|
||||
.addItems(Items.PUMPKIN_PIE)
|
||||
.build());
|
||||
|
||||
create("cake")
|
||||
register(ctx, "cake", new PotatoCannonProjectileType.Builder()
|
||||
.damage(8)
|
||||
.reloadTicks(15)
|
||||
.knockback(0.1f)
|
||||
.velocity(1.1f)
|
||||
.renderTumbling()
|
||||
.sticky()
|
||||
.registerAndAssign(ctx, Items.CAKE);
|
||||
.addItems(Items.CAKE)
|
||||
.build());
|
||||
|
||||
create("blaze_cake")
|
||||
register(ctx, "blaze_cake", new PotatoCannonProjectileType.Builder()
|
||||
.damage(15)
|
||||
.reloadTicks(20)
|
||||
.knockback(0.3f)
|
||||
|
@ -228,18 +248,20 @@ public class AllPotatoProjectileTypes {
|
|||
.renderTumbling()
|
||||
.sticky()
|
||||
.preEntityHit(SetOnFire.seconds(12))
|
||||
.registerAndAssign(ctx, AllItems.BLAZE_CAKE.get());
|
||||
.addItems(AllItems.BLAZE_CAKE.get())
|
||||
.build());
|
||||
|
||||
create("fish")
|
||||
register(ctx, "fish", new PotatoCannonProjectileType.Builder()
|
||||
.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);
|
||||
.addItems(Items.COD, Items.COOKED_COD, Items.SALMON, Items.COOKED_SALMON, Items.TROPICAL_FISH)
|
||||
.build());
|
||||
|
||||
create("pufferfish")
|
||||
register(ctx, "pufferfish", new PotatoCannonProjectileType.Builder()
|
||||
.damage(4)
|
||||
.knockback(0.4f)
|
||||
.velocity(1.1f)
|
||||
|
@ -247,9 +269,10 @@ public class AllPotatoProjectileTypes {
|
|||
.sticky()
|
||||
.onEntityHit(new FoodEffects(Foods.PUFFERFISH, false))
|
||||
.soundPitch(1.1f)
|
||||
.registerAndAssign(ctx, Items.PUFFERFISH);
|
||||
.addItems(Items.PUFFERFISH)
|
||||
.build());
|
||||
|
||||
create("suspicious_stew")
|
||||
register(ctx, "suspicious_stew", new PotatoCannonProjectileType.Builder()
|
||||
.damage(3)
|
||||
.reloadTicks(40)
|
||||
.knockback(0.2f)
|
||||
|
@ -257,10 +280,11 @@ public class AllPotatoProjectileTypes {
|
|||
.renderTowardMotion(140, 1)
|
||||
.dropStack(Items.BOWL.getDefaultInstance())
|
||||
.onEntityHit(SuspiciousStew.INSTANCE)
|
||||
.registerAndAssign(ctx, Items.SUSPICIOUS_STEW);
|
||||
.addItems(Items.SUSPICIOUS_STEW)
|
||||
.build());
|
||||
}
|
||||
|
||||
private static PotatoCannonProjectileType.Builder create(String name) {
|
||||
return new PotatoCannonProjectileType.Builder(Create.asResource(name));
|
||||
private static void register(BootstrapContext<PotatoCannonProjectileType> ctx, String name, PotatoCannonProjectileType type) {
|
||||
ctx.register(ResourceKey.create(CreateRegistries.POTATO_PROJECTILE_TYPE, Create.asResource(name)), type);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,15 +11,14 @@ import com.simibubi.create.AllEnchantments;
|
|||
import com.simibubi.create.AllEntityTypes;
|
||||
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;
|
||||
import com.simibubi.create.foundation.item.render.SimpleCustomRenderer;
|
||||
import com.simibubi.create.foundation.utility.CreateLang;
|
||||
import com.simibubi.create.foundation.utility.GlobalRegistryAccess;
|
||||
import com.simibubi.create.infrastructure.config.AllConfigs;
|
||||
|
||||
import net.createmod.catnip.animation.AnimationTickHolder;
|
||||
import net.createmod.catnip.math.VecHelper;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
@ -56,15 +55,171 @@ import net.minecraft.world.phys.Vec3;
|
|||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
import net.neoforged.neoforge.client.extensions.common.IClientItemExtensions;
|
||||
import net.neoforged.neoforge.server.ServerLifecycleHooks;
|
||||
|
||||
public class PotatoCannonItem extends ProjectileWeaponItem implements CustomArmPoseItem {
|
||||
|
||||
public static ItemStack CLIENT_CURRENT_AMMO = ItemStack.EMPTY;
|
||||
public static final int MAX_DAMAGE = 100;
|
||||
|
||||
public PotatoCannonItem(Properties properties) {
|
||||
super(properties.durability(MAX_DAMAGE));
|
||||
super(properties);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Ammo getAmmo(Player player, ItemStack heldStack) {
|
||||
ItemStack ammoStack = player.getProjectile(heldStack);
|
||||
if (ammoStack.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Optional<Holder.Reference<PotatoCannonProjectileType>> optionalType = PotatoCannonProjectileType.getTypeForItem(player.level().registryAccess(), ammoStack.getItem());
|
||||
if (optionalType.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Ammo(ammoStack, optionalType.get().value());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shootProjectile(LivingEntity shooter, Projectile projectile, int index, float velocity, float inaccuracy, float angle, @Nullable LivingEntity target) {}
|
||||
|
||||
@Override
|
||||
protected void shoot(ServerLevel level, LivingEntity shooter, InteractionHand hand, ItemStack weapon, List<ItemStack> projectileItems, float velocity, float inaccuracy, boolean isCrit, @Nullable LivingEntity target) {}
|
||||
|
||||
@Override
|
||||
public InteractionResult useOn(UseOnContext context) {
|
||||
return use(context.getLevel(), context.getPlayer(), context.getHand()).getResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
|
||||
ItemStack heldStack = player.getItemInHand(hand);
|
||||
if (ShootableGadgetItemMethods.shouldSwap(player, heldStack, hand, s -> s.getItem() instanceof PotatoCannonItem)) {
|
||||
return InteractionResultHolder.fail(heldStack);
|
||||
}
|
||||
|
||||
Ammo ammo = getAmmo(player, heldStack);
|
||||
if (ammo == null) {
|
||||
return InteractionResultHolder.pass(heldStack);
|
||||
}
|
||||
ItemStack ammoStack = ammo.stack();
|
||||
PotatoCannonProjectileType projectileType = ammo.type();
|
||||
|
||||
if (level.isClientSide) {
|
||||
CreateClient.POTATO_CANNON_RENDER_HANDLER.dontAnimateItem(hand);
|
||||
return InteractionResultHolder.success(heldStack);
|
||||
}
|
||||
|
||||
Vec3 barrelPos = ShootableGadgetItemMethods.getGunBarrelVec(player, hand == InteractionHand.MAIN_HAND,
|
||||
new Vec3(.75f, -0.15f, 1.5f));
|
||||
Vec3 correction =
|
||||
ShootableGadgetItemMethods.getGunBarrelVec(player, hand == InteractionHand.MAIN_HAND, new Vec3(-.05f, 0, 0))
|
||||
.subtract(player.position()
|
||||
.add(0, player.getEyeHeight(), 0));
|
||||
|
||||
Vec3 lookVec = player.getLookAngle();
|
||||
Vec3 motion = lookVec.add(correction)
|
||||
.normalize()
|
||||
.scale(2)
|
||||
.scale(projectileType.velocityMultiplier());
|
||||
|
||||
float soundPitch = projectileType.soundPitch() + (level.getRandom().nextFloat() - .5f) / 4f;
|
||||
|
||||
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();
|
||||
|
||||
ItemStack ammoStackCopy = ammoStack.copy();
|
||||
|
||||
for (int i = 0; i < projectileType.split(); i++) {
|
||||
PotatoProjectileEntity projectile = AllEntityTypes.POTATO_PROJECTILE.create(level);
|
||||
projectile.setItem(ammoStackCopy);
|
||||
projectile.setEnchantmentEffectsFromCannon(heldStack);
|
||||
|
||||
Vec3 splitMotion = motion;
|
||||
if (spray) {
|
||||
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));
|
||||
}
|
||||
|
||||
if (i != 0)
|
||||
projectile.recoveryChance = 0;
|
||||
|
||||
projectile.setPos(barrelPos.x, barrelPos.y, barrelPos.z);
|
||||
projectile.setDeltaMovement(splitMotion);
|
||||
projectile.setOwner(player);
|
||||
level.addFreshEntity(projectile);
|
||||
}
|
||||
|
||||
if (!player.isCreative()) {
|
||||
ammoStack.shrink(1);
|
||||
if (ammoStack.isEmpty())
|
||||
player.getInventory().removeItem(ammoStack);
|
||||
}
|
||||
|
||||
if (!BacktankUtil.canAbsorbDamage(player, maxUses()))
|
||||
heldStack.hurtAndBreak(1, player, LivingEntity.getSlotForHand(hand));
|
||||
|
||||
ShootableGadgetItemMethods.applyCooldown(player, heldStack, hand, s -> s.getItem() instanceof PotatoCannonItem, projectileType.reloadTicks());
|
||||
ShootableGadgetItemMethods.sendPackets(player,
|
||||
b -> new PotatoCannonPacket(barrelPos, lookVec.normalize(), ammoStack, hand, soundPitch, b));
|
||||
return InteractionResultHolder.success(heldStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void appendHoverText(ItemStack stack, TooltipContext context, List<Component> tooltip, TooltipFlag flag) {
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
if (player == null) {
|
||||
super.appendHoverText(stack, context, tooltip, flag);
|
||||
return;
|
||||
}
|
||||
|
||||
Ammo ammo = getAmmo(player, stack);
|
||||
if (ammo == null) {
|
||||
super.appendHoverText(stack, context, tooltip, flag);
|
||||
return;
|
||||
}
|
||||
ItemStack ammoStack = ammo.stack();
|
||||
PotatoCannonProjectileType type = ammo.type();
|
||||
|
||||
HolderLookup.Provider registries = context.registries();
|
||||
if (registries == null)
|
||||
return;
|
||||
|
||||
HolderLookup<Enchantment> lookup = registries.lookupOrThrow(Registries.ENCHANTMENT);
|
||||
int power = stack.getEnchantmentLevel(lookup.getOrThrow(Enchantments.POWER));
|
||||
int punch = stack.getEnchantmentLevel(lookup.getOrThrow(Enchantments.PUNCH));
|
||||
final float additionalDamageMult = 1 + power * .2f;
|
||||
final float additionalKnockback = punch * .5f;
|
||||
|
||||
String _attack = "potato_cannon.ammo.attack_damage";
|
||||
String _reload = "potato_cannon.ammo.reload_ticks";
|
||||
String _knockback = "potato_cannon.ammo.knockback";
|
||||
|
||||
tooltip.add(CommonComponents.EMPTY);
|
||||
tooltip.add(Component.translatable(ammoStack.getDescriptionId()).append(Component.literal(":"))
|
||||
.withStyle(ChatFormatting.GRAY));
|
||||
MutableComponent spacing = CommonComponents.space();
|
||||
ChatFormatting green = ChatFormatting.GREEN;
|
||||
ChatFormatting darkGreen = ChatFormatting.DARK_GREEN;
|
||||
|
||||
float damageF = type.damage() * additionalDamageMult;
|
||||
MutableComponent damage = Component.literal(damageF == Mth.floor(damageF) ? "" + Mth.floor(damageF) : "" + damageF);
|
||||
MutableComponent reloadTicks = Component.literal("" + type.reloadTicks());
|
||||
MutableComponent knockback =
|
||||
Component.literal("" + (type.knockback() + additionalKnockback));
|
||||
|
||||
damage = damage.withStyle(additionalDamageMult > 1 ? green : darkGreen);
|
||||
knockback = knockback.withStyle(additionalKnockback > 0 ? green : darkGreen);
|
||||
reloadTicks = reloadTicks.withStyle(darkGreen);
|
||||
|
||||
tooltip.add(spacing.plainCopy()
|
||||
.append(CreateLang.translateDirect(_attack, damage)
|
||||
.withStyle(darkGreen)));
|
||||
tooltip.add(spacing.plainCopy()
|
||||
.append(CreateLang.translateDirect(_reload, reloadTicks)
|
||||
.withStyle(darkGreen)));
|
||||
tooltip.add(spacing.plainCopy()
|
||||
.append(CreateLang.translateDirect(_knockback, knockback)
|
||||
.withStyle(darkGreen)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -72,6 +227,22 @@ public class PotatoCannonItem extends ProjectileWeaponItem implements CustomArmP
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) {
|
||||
return slotChanged || newStack.getItem() != oldStack.getItem();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<ItemStack> getAllSupportedProjectiles() {
|
||||
return stack -> PotatoCannonProjectileType.getTypeForItem(GlobalRegistryAccess.getOrThrow(), stack.getItem())
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultProjectileRange() {
|
||||
return 15;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsEnchantment(ItemStack stack, Holder<Enchantment> enchantment) {
|
||||
if (enchantment.is(Enchantments.POWER))
|
||||
|
@ -87,11 +258,6 @@ public class PotatoCannonItem extends ProjectileWeaponItem implements CustomArmP
|
|||
return super.supportsEnchantment(stack, enchantment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult useOn(UseOnContext context) {
|
||||
return use(context.getLevel(), context.getPlayer(), context.getHand()).getResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBarVisible(ItemStack stack) {
|
||||
return BacktankUtil.isBarVisible(stack, maxUses());
|
||||
|
@ -107,190 +273,13 @@ public class PotatoCannonItem extends ProjectileWeaponItem implements CustomArmP
|
|||
return BacktankUtil.getBarColor(stack, maxUses());
|
||||
}
|
||||
|
||||
private int maxUses() {
|
||||
private static int maxUses() {
|
||||
return AllConfigs.server().equipment.maxPotatoCannonShots.get();
|
||||
}
|
||||
|
||||
public boolean isCannon(ItemStack stack) {
|
||||
return stack.getItem() instanceof PotatoCannonItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shootProjectile(LivingEntity shooter, Projectile projectile, int index, float velocity, float inaccuracy, float angle, @Nullable LivingEntity target) {}
|
||||
|
||||
@Override
|
||||
protected void shoot(ServerLevel level, LivingEntity shooter, InteractionHand hand, ItemStack weapon, List<ItemStack> projectileItems, float velocity, float inaccuracy, boolean isCrit, @Nullable LivingEntity target) {}
|
||||
|
||||
@Override
|
||||
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
|
||||
ItemStack stack = player.getItemInHand(hand);
|
||||
return findAmmoInInventory(level, player, stack).map(ammoIn -> {
|
||||
if (ShootableGadgetItemMethods.shouldSwap(player, stack, hand, this::isCannon))
|
||||
return InteractionResultHolder.fail(stack);
|
||||
|
||||
if (level.isClientSide) {
|
||||
CreateClient.POTATO_CANNON_RENDER_HANDLER.dontAnimateItem(hand);
|
||||
return InteractionResultHolder.success(stack);
|
||||
}
|
||||
|
||||
Vec3 barrelPos = ShootableGadgetItemMethods.getGunBarrelVec(player, hand == InteractionHand.MAIN_HAND,
|
||||
new Vec3(.75f, -0.15f, 1.5f));
|
||||
Vec3 correction =
|
||||
ShootableGadgetItemMethods.getGunBarrelVec(player, hand == InteractionHand.MAIN_HAND, new Vec3(-.05f, 0, 0))
|
||||
.subtract(player.position()
|
||||
.add(0, player.getEyeHeight(), 0));
|
||||
|
||||
ItemStack itemStack = ammoIn.copy();
|
||||
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.velocityMultiplier());
|
||||
|
||||
float soundPitch = projectileType.soundPitch() + (level.getRandom().nextFloat() - .5f) / 4f;
|
||||
|
||||
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.split(); i++) {
|
||||
PotatoProjectileEntity projectile = AllEntityTypes.POTATO_PROJECTILE.create(level);
|
||||
projectile.setItem(itemStack);
|
||||
projectile.setEnchantmentEffectsFromCannon(stack);
|
||||
|
||||
Vec3 splitMotion = motion;
|
||||
if (spray) {
|
||||
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));
|
||||
}
|
||||
|
||||
if (i != 0)
|
||||
projectile.recoveryChance = 0;
|
||||
|
||||
projectile.setPos(barrelPos.x, barrelPos.y, barrelPos.z);
|
||||
projectile.setDeltaMovement(splitMotion);
|
||||
projectile.setOwner(player);
|
||||
level.addFreshEntity(projectile);
|
||||
}
|
||||
|
||||
if (!player.isCreative()) {
|
||||
ammoIn.shrink(1);
|
||||
if (ammoIn.isEmpty())
|
||||
player.getInventory().removeItem(ammoIn);
|
||||
}
|
||||
|
||||
if (!BacktankUtil.canAbsorbDamage(player, maxUses()))
|
||||
stack.hurtAndBreak(1, player, LivingEntity.getSlotForHand(hand));
|
||||
|
||||
Integer cooldown =
|
||||
findAmmoInInventory(level, player, stack).flatMap(i -> PotatoCannonProjectileType.getTypeForStack(level, i))
|
||||
.map(potatoCannonProjectileType -> potatoCannonProjectileType.reloadTicks())
|
||||
.orElse(10);
|
||||
|
||||
ShootableGadgetItemMethods.applyCooldown(player, stack, hand, this::isCannon, cooldown);
|
||||
ShootableGadgetItemMethods.sendPackets(player,
|
||||
b -> new PotatoCannonPacket(barrelPos, hand, b, soundPitch, lookVec.normalize(), itemStack));
|
||||
return InteractionResultHolder.success(stack);
|
||||
})
|
||||
.orElse(InteractionResultHolder.pass(stack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) {
|
||||
return slotChanged || newStack.getItem() != oldStack.getItem();
|
||||
}
|
||||
|
||||
private Optional<ItemStack> findAmmoInInventory(Level level, Player player, ItemStack held) {
|
||||
ItemStack findAmmo = player.getProjectile(held);
|
||||
return PotatoCannonProjectileType.getTypeForStack(level, findAmmo)
|
||||
.map($ -> findAmmo);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static Optional<ItemStack> getAmmoforPreview(ItemStack cannon) {
|
||||
if (AnimationTickHolder.getTicks() % 3 != 0)
|
||||
return Optional.of(CLIENT_CURRENT_AMMO)
|
||||
.filter(stack -> !stack.isEmpty());
|
||||
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
CLIENT_CURRENT_AMMO = ItemStack.EMPTY;
|
||||
if (player == null)
|
||||
return Optional.empty();
|
||||
ItemStack findAmmo = player.getProjectile(cannon);
|
||||
Optional<ItemStack> found = PotatoCannonProjectileType.getTypeForStack(Minecraft.getInstance().level, findAmmo)
|
||||
.map($ -> findAmmo);
|
||||
found.ifPresent(stack -> CLIENT_CURRENT_AMMO = stack);
|
||||
return found;
|
||||
}
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void appendHoverText(ItemStack stack, TooltipContext context, List<Component> tooltip, TooltipFlag flag) {
|
||||
HolderLookup.Provider registries = context.registries();
|
||||
if (registries != null) {
|
||||
HolderLookup.RegistryLookup<Enchantment> enchantLookup = registries.lookupOrThrow(Registries.ENCHANTMENT);
|
||||
int power = stack.getEnchantmentLevel(enchantLookup.get(Enchantments.POWER).orElseThrow().getDelegate());
|
||||
int punch = stack.getEnchantmentLevel(enchantLookup.get(Enchantments.PUNCH).orElseThrow().getDelegate());
|
||||
final float additionalDamageMult = 1 + power * .2f;
|
||||
final float additionalKnockback = punch * .5f;
|
||||
|
||||
getAmmoforPreview(stack).ifPresent(ammo -> {
|
||||
String _attack = "potato_cannon.ammo.attack_damage";
|
||||
String _reload = "potato_cannon.ammo.reload_ticks";
|
||||
String _knockback = "potato_cannon.ammo.knockback";
|
||||
|
||||
tooltip.add(CommonComponents.EMPTY);
|
||||
tooltip.add(Component.translatable(ammo.getDescriptionId()).append(Component.literal(":"))
|
||||
.withStyle(ChatFormatting.GRAY));
|
||||
PotatoCannonProjectileType type = PotatoCannonProjectileType.getTypeForStack(Minecraft.getInstance().level, ammo)
|
||||
.get();
|
||||
MutableComponent spacing = CommonComponents.space();
|
||||
ChatFormatting green = ChatFormatting.GREEN;
|
||||
ChatFormatting darkGreen = ChatFormatting.DARK_GREEN;
|
||||
|
||||
float damageF = type.damage() * additionalDamageMult;
|
||||
MutableComponent damage = Component.literal(
|
||||
damageF == Mth.floor(damageF) ? "" + Mth.floor(damageF) : "" + damageF);
|
||||
MutableComponent reloadTicks = Component.literal("" + type.reloadTicks());
|
||||
MutableComponent knockback =
|
||||
Component.literal("" + (type.knockback() + additionalKnockback));
|
||||
|
||||
damage = damage.withStyle(additionalDamageMult > 1 ? green : darkGreen);
|
||||
knockback = knockback.withStyle(additionalKnockback > 0 ? green : darkGreen);
|
||||
reloadTicks = reloadTicks.withStyle(darkGreen);
|
||||
|
||||
tooltip.add(spacing.plainCopy()
|
||||
.append(CreateLang.translateDirect(_attack, damage)
|
||||
.withStyle(darkGreen)));
|
||||
tooltip.add(spacing.plainCopy()
|
||||
.append(CreateLang.translateDirect(_reload, reloadTicks)
|
||||
.withStyle(darkGreen)));
|
||||
tooltip.add(spacing.plainCopy()
|
||||
.append(CreateLang.translateDirect(_knockback, knockback)
|
||||
.withStyle(darkGreen)));
|
||||
});
|
||||
}
|
||||
super.appendHoverText(stack, context, tooltip, flag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<ItemStack> getAllSupportedProjectiles() {
|
||||
Level level = ServerLifecycleHooks.getCurrentServer().getLevel(Level.OVERWORLD);
|
||||
return stack -> PotatoCannonProjectileType.getTypeForStack(level, stack)
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onEntitySwing(ItemStack stack, LivingEntity entity, InteractionHand hand) {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -307,14 +296,12 @@ public class PotatoCannonItem extends ProjectileWeaponItem implements CustomArmP
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultProjectileRange() {
|
||||
return 15;
|
||||
}
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void initializeClient(Consumer<IClientItemExtensions> consumer) {
|
||||
consumer.accept(SimpleCustomRenderer.create(this, new PotatoCannonItemRenderer()));
|
||||
}
|
||||
|
||||
public record Ammo(ItemStack stack, PotatoCannonProjectileType type) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,47 +5,69 @@ import com.mojang.math.Axis;
|
|||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.content.equipment.potatoCannon.PotatoCannonItem.Ammo;
|
||||
import com.simibubi.create.foundation.item.render.CustomRenderedItemModel;
|
||||
import com.simibubi.create.foundation.item.render.CustomRenderedItemModelRenderer;
|
||||
import com.simibubi.create.foundation.item.render.PartialItemModelRenderer;
|
||||
|
||||
import dev.engine_room.flywheel.lib.model.baked.PartialModel;
|
||||
import dev.engine_room.flywheel.lib.transform.TransformStack;
|
||||
import net.createmod.catnip.animation.AnimationTickHolder;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.entity.ItemRenderer;
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.HumanoidArm;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import net.neoforged.neoforge.client.IItemDecorator;
|
||||
|
||||
public class PotatoCannonItemRenderer extends CustomRenderedItemModelRenderer {
|
||||
public static final IItemDecorator DECORATOR = (guiGraphics, font, stack, xOffset, yOffset) -> {
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Ammo ammo = PotatoCannonItem.getAmmo(player, stack);
|
||||
if (ammo == null || AllItems.POTATO_CANNON.is(ammo.stack())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PoseStack poseStack = guiGraphics.pose();
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(xOffset, yOffset + 8, 100);
|
||||
poseStack.scale(.5f, .5f, .5f);
|
||||
guiGraphics.renderItem(ammo.stack(), 0, 0);
|
||||
poseStack.popPose();
|
||||
return false;
|
||||
};
|
||||
|
||||
protected static final PartialModel COG = PartialModel.of(Create.asResource("item/potato_cannon/cog"));
|
||||
|
||||
@Override
|
||||
protected void render(ItemStack stack, CustomRenderedItemModel model, PartialItemModelRenderer renderer,
|
||||
ItemDisplayContext transformType, PoseStack ms, MultiBufferSource buffer, int light, int overlay) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
ItemRenderer itemRenderer = mc.getItemRenderer();
|
||||
renderer.render(model.getOriginalModel(), light);
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
LocalPlayer player = mc.player;
|
||||
boolean mainHand = player.getMainHandItem() == stack;
|
||||
boolean offHand = player.getOffhandItem() == stack;
|
||||
boolean leftHanded = player.getMainArm() == HumanoidArm.LEFT;
|
||||
|
||||
float offset = .5f / 16;
|
||||
float worldTime = AnimationTickHolder.getRenderTime() / 10;
|
||||
float angle = worldTime * -25;
|
||||
float speed = CreateClient.POTATO_CANNON_RENDER_HANDLER.getAnimation(mainHand ^ leftHanded,
|
||||
AnimationTickHolder.getPartialTicks());
|
||||
float angle = AnimationTickHolder.getRenderTime() * -2.5f;
|
||||
|
||||
if (player != null) {
|
||||
boolean inMainHand = player.getMainHandItem() == stack;
|
||||
boolean inOffHand = player.getOffhandItem() == stack;
|
||||
|
||||
if (inMainHand || inOffHand) {
|
||||
boolean leftHanded = player.getMainArm() == HumanoidArm.LEFT;
|
||||
float speed = CreateClient.POTATO_CANNON_RENDER_HANDLER.getAnimation(inMainHand ^ leftHanded,
|
||||
AnimationTickHolder.getPartialTicks());
|
||||
angle += 360 * Mth.clamp(speed * 5, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (mainHand || offHand)
|
||||
angle += 360 * Mth.clamp(speed * 5, 0, 1);
|
||||
angle %= 360;
|
||||
float offset = .5f / 16;
|
||||
|
||||
ms.pushPose();
|
||||
ms.translate(0, offset, 0);
|
||||
|
@ -53,20 +75,5 @@ public class PotatoCannonItemRenderer extends CustomRenderedItemModelRenderer {
|
|||
ms.translate(0, -offset, 0);
|
||||
renderer.render(COG.get(), light);
|
||||
ms.popPose();
|
||||
|
||||
if (transformType == ItemDisplayContext.GUI) {
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,20 +17,20 @@ import net.neoforged.api.distmarker.OnlyIn;
|
|||
|
||||
public class PotatoCannonPacket extends ShootGadgetPacket {
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, PotatoCannonPacket> STREAM_CODEC = StreamCodec.composite(
|
||||
CatnipStreamCodecs.VEC3, packet -> packet.location,
|
||||
CatnipStreamCodecs.HAND, packet -> packet.hand,
|
||||
ByteBufCodecs.BOOL, packet -> packet.self,
|
||||
ByteBufCodecs.FLOAT, packet -> packet.pitch,
|
||||
CatnipStreamCodecs.VEC3, packet -> packet.motion,
|
||||
ItemStack.STREAM_CODEC, packet -> packet.item,
|
||||
PotatoCannonPacket::new
|
||||
CatnipStreamCodecs.VEC3, packet -> packet.location,
|
||||
CatnipStreamCodecs.VEC3, packet -> packet.motion,
|
||||
ItemStack.STREAM_CODEC, packet -> packet.item,
|
||||
CatnipStreamCodecs.HAND, packet -> packet.hand,
|
||||
ByteBufCodecs.FLOAT, packet -> packet.pitch,
|
||||
ByteBufCodecs.BOOL, packet -> packet.self,
|
||||
PotatoCannonPacket::new
|
||||
);
|
||||
|
||||
private final float pitch;
|
||||
private final Vec3 motion;
|
||||
private final ItemStack item;
|
||||
|
||||
public PotatoCannonPacket(Vec3 location, InteractionHand hand, boolean self, float pitch, Vec3 motion, ItemStack item) {
|
||||
public PotatoCannonPacket(Vec3 location, Vec3 motion, ItemStack item, InteractionHand hand, float pitch, boolean self) {
|
||||
super(location, hand, self);
|
||||
this.motion = motion;
|
||||
this.item = item;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package com.simibubi.create.content.equipment.potatoCannon;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.content.equipment.zapper.ShootableGadgetRenderHandler;
|
||||
import com.simibubi.create.foundation.particle.AirParticleData;
|
||||
|
||||
|
@ -26,8 +25,7 @@ public class PotatoCannonRenderHandler extends ShootableGadgetRenderHandler {
|
|||
|
||||
@Override
|
||||
protected boolean appliesTo(ItemStack stack) {
|
||||
return AllItems.POTATO_CANNON.get()
|
||||
.isCannon(stack);
|
||||
return stack.getItem() instanceof PotatoCannonItem;
|
||||
}
|
||||
|
||||
public void beforeShoot(float nextPitch, Vec3 location, Vec3 motion, ItemStack stack) {
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package com.simibubi.create.content.equipment.potatoCannon;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
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.content.equipment.potatoCannon.AllPotatoProjectileRenderModes.StuckToEntity;
|
||||
import com.simibubi.create.foundation.advancement.AllAdvancements;
|
||||
import com.simibubi.create.foundation.damageTypes.CreateDamageSources;
|
||||
import com.simibubi.create.foundation.particle.AirParticleData;
|
||||
|
@ -56,28 +58,17 @@ public class PotatoProjectileEntity extends AbstractHurtingProjectile implements
|
|||
protected float additionalKnockback = 0;
|
||||
protected float recoveryChance = 0;
|
||||
|
||||
public PotatoProjectileEntity(EntityType<? extends AbstractHurtingProjectile> type, Level world) {
|
||||
super(type, world);
|
||||
}
|
||||
|
||||
public ItemStack getItem() {
|
||||
return stack;
|
||||
public PotatoProjectileEntity(EntityType<? extends AbstractHurtingProjectile> type, Level level) {
|
||||
super(type, level);
|
||||
}
|
||||
|
||||
public void setItem(ItemStack stack) {
|
||||
this.stack = stack;
|
||||
}
|
||||
|
||||
public PotatoCannonProjectileType getProjectileType() {
|
||||
if (type == null)
|
||||
type = PotatoCannonProjectileType.getTypeForStack(level(), stack)
|
||||
.orElseGet(() ->
|
||||
level().registryAccess()
|
||||
.lookupOrThrow(CreateRegistries.POTATO_PROJECTILE_TYPE)
|
||||
.getOrThrow(AllPotatoProjectileTypes.FALLBACK)
|
||||
.value()
|
||||
);
|
||||
return type;
|
||||
type = PotatoCannonProjectileType.getTypeForItem(level().registryAccess(), stack.getItem())
|
||||
.orElseGet(() -> level().registryAccess()
|
||||
.registryOrThrow(CreateRegistries.POTATO_PROJECTILE_TYPE)
|
||||
.getHolderOrThrow(AllPotatoProjectileTypes.FALLBACK))
|
||||
.value();
|
||||
}
|
||||
|
||||
public void setEnchantmentEffectsFromCannon(ItemStack cannon) {
|
||||
|
@ -89,9 +80,18 @@ public class PotatoProjectileEntity extends AbstractHurtingProjectile implements
|
|||
recoveryChance = .125f + recovery * .125f;
|
||||
}
|
||||
|
||||
public ItemStack getItem() {
|
||||
return stack;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PotatoCannonProjectileType getProjectileType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readAdditionalSaveData(CompoundTag nbt) {
|
||||
stack = ItemStack.parseOptional(this.registryAccess(), nbt.getCompound("Item"));
|
||||
setItem(ItemStack.parseOptional(this.registryAccess(), nbt.getCompound("Item")));
|
||||
additionalDamageMult = nbt.getFloat("AdditionalDamage");
|
||||
additionalKnockback = nbt.getFloat("AdditionalKnockback");
|
||||
recoveryChance = nbt.getFloat("Recovery");
|
||||
|
@ -107,6 +107,7 @@ public class PotatoProjectileEntity extends AbstractHurtingProjectile implements
|
|||
super.addAdditionalSaveData(nbt);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Entity getStuckEntity() {
|
||||
if (stuckEntity == null)
|
||||
return null;
|
||||
|
@ -118,7 +119,7 @@ public class PotatoProjectileEntity extends AbstractHurtingProjectile implements
|
|||
public void setStuckEntity(Entity stuckEntity) {
|
||||
this.stuckEntity = stuckEntity;
|
||||
this.stuckOffset = position().subtract(stuckEntity.position());
|
||||
this.stuckRenderer = new PotatoProjectileRenderMode.StuckToEntity(stuckOffset);
|
||||
this.stuckRenderer = new StuckToEntity(stuckOffset);
|
||||
this.stuckFallSpeed = 0.0;
|
||||
setDeltaMovement(Vec3.ZERO);
|
||||
}
|
||||
|
@ -127,27 +128,26 @@ public class PotatoProjectileEntity extends AbstractHurtingProjectile implements
|
|||
if (getStuckEntity() != null)
|
||||
return stuckRenderer;
|
||||
|
||||
return getProjectileType().renderMode();
|
||||
return type.renderMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
PotatoCannonProjectileType projectileType = getProjectileType();
|
||||
|
||||
Entity stuckEntity = getStuckEntity();
|
||||
if (stuckEntity != null) {
|
||||
if (getY() < stuckEntity.getY() - 0.1) {
|
||||
pop(position());
|
||||
kill();
|
||||
} else {
|
||||
stuckFallSpeed += 0.007 * projectileType.gravityMultiplier();
|
||||
stuckFallSpeed += 0.007 * type.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.gravityMultiplier(), 0)
|
||||
.scale(projectileType.drag()));
|
||||
setDeltaMovement(getDeltaMovement().add(0, -0.05 * type.gravityMultiplier(), 0)
|
||||
.scale(type.drag()));
|
||||
}
|
||||
|
||||
super.tick();
|
||||
|
@ -177,9 +177,8 @@ public class PotatoProjectileEntity extends AbstractHurtingProjectile implements
|
|||
|
||||
Vec3 hit = ray.getLocation();
|
||||
Entity target = ray.getEntity();
|
||||
PotatoCannonProjectileType projectileType = getProjectileType();
|
||||
float damage = projectileType.damage() * additionalDamageMult;
|
||||
float knockback = projectileType.knockback() + additionalKnockback;
|
||||
float damage = type.damage() * additionalDamageMult;
|
||||
float knockback = type.knockback() + additionalKnockback;
|
||||
Entity owner = this.getOwner();
|
||||
|
||||
if (!target.isAlive())
|
||||
|
@ -202,7 +201,7 @@ public class PotatoProjectileEntity extends AbstractHurtingProjectile implements
|
|||
|
||||
if (target instanceof WitherBoss && ((WitherBoss) target).isPowered())
|
||||
return;
|
||||
if (projectileType.preEntityHit(stack, ray))
|
||||
if (type.preEntityHit(stack, ray))
|
||||
return;
|
||||
|
||||
boolean targetIsEnderman = target.getType() == EntityType.ENDERMAN;
|
||||
|
@ -221,12 +220,13 @@ public class PotatoProjectileEntity extends AbstractHurtingProjectile implements
|
|||
if (targetIsEnderman)
|
||||
return;
|
||||
|
||||
if (!projectileType.onEntityHit(stack, ray) && onServer)
|
||||
if (!type.onEntityHit(stack, ray) && onServer) {
|
||||
if (random.nextDouble() <= recoveryChance) {
|
||||
recoverItem();
|
||||
} else {
|
||||
spawnAtLocation(type.dropStack());
|
||||
}
|
||||
|
||||
spawnAtLocation(projectileType.dropStack());
|
||||
}
|
||||
|
||||
if (!(target instanceof LivingEntity livingentity)) {
|
||||
playHitSound(level(), position());
|
||||
|
@ -287,11 +287,13 @@ public class PotatoProjectileEntity extends AbstractHurtingProjectile implements
|
|||
protected void onHitBlock(BlockHitResult ray) {
|
||||
Vec3 hit = ray.getLocation();
|
||||
pop(hit);
|
||||
if (!getProjectileType().onBlockHit(level(), stack, ray) && !level().isClientSide)
|
||||
if (random.nextDouble() <= recoveryChance)
|
||||
if (!type.onBlockHit(level(), stack, ray) && !level().isClientSide) {
|
||||
if (random.nextDouble() <= recoveryChance) {
|
||||
recoverItem();
|
||||
|
||||
spawnAtLocation(getProjectileType().dropStack());
|
||||
} else {
|
||||
spawnAtLocation(getProjectileType().dropStack());
|
||||
}
|
||||
}
|
||||
|
||||
super.onHitBlock(ray);
|
||||
kill();
|
||||
|
|
|
@ -5,7 +5,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.simibubi.create.api.registry.CreateRegistries;
|
||||
import com.simibubi.create.api.registry.CreateBuiltInRegistries;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus.Internal;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
@ -24,6 +24,7 @@ import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap;
|
|||
import net.createmod.catnip.math.VecHelper;
|
||||
import net.createmod.catnip.theme.Color;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.core.particles.BlockParticleOption;
|
||||
|
@ -58,11 +59,7 @@ import net.minecraft.world.level.block.state.BlockState;
|
|||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.neoforge.registries.DeferredRegister;
|
||||
public class AllFanProcessingTypes {
|
||||
private static final DeferredRegister<FanProcessingType> REGISTER = DeferredRegister.create(CreateRegistries.FAN_PROCESSING_TYPE, Create.ID);
|
||||
|
||||
public static final BlastingType BLASTING = register("blasting", new BlastingType());
|
||||
public static final HauntingType HAUNTING = register("haunting", new HauntingType());
|
||||
public static final SmokingType SMOKING = register("smoking", new SmokingType());
|
||||
|
@ -81,13 +78,11 @@ public class AllFanProcessingTypes {
|
|||
}
|
||||
|
||||
private static <T extends FanProcessingType> T register(String name, T type) {
|
||||
REGISTER.register(name, () -> type);
|
||||
return type;
|
||||
return Registry.register(CreateBuiltInRegistries.FAN_PROCESSING_TYPE, Create.asResource(name), type);
|
||||
}
|
||||
|
||||
@Internal
|
||||
public static void register(IEventBus eventBus) {
|
||||
REGISTER.register(eventBus);
|
||||
public static void init() {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
|
|
@ -9,7 +9,7 @@ import org.jetbrains.annotations.ApiStatus.Internal;
|
|||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.api.registry.CreateRegistries;
|
||||
import com.simibubi.create.api.registry.CreateBuiltInRegistries;
|
||||
import com.simibubi.create.content.kinetics.base.KineticBlockEntity;
|
||||
import com.simibubi.create.content.kinetics.belt.BeltBlock;
|
||||
import com.simibubi.create.content.kinetics.belt.BeltBlockEntity;
|
||||
|
@ -37,6 +37,7 @@ import com.simibubi.create.foundation.item.SmartInventory;
|
|||
import net.createmod.catnip.math.VecHelper;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.world.Containers;
|
||||
|
@ -59,15 +60,11 @@ import net.minecraft.world.level.block.state.BlockState;
|
|||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.neoforge.items.IItemHandler;
|
||||
import net.neoforged.neoforge.items.ItemHandlerHelper;
|
||||
import net.neoforged.neoforge.items.wrapper.SidedInvWrapper;
|
||||
import net.neoforged.neoforge.registries.DeferredRegister;
|
||||
|
||||
public class AllArmInteractionPointTypes {
|
||||
private static final DeferredRegister<ArmInteractionPointType> REGISTER = DeferredRegister.create(CreateRegistries.ARM_INTERACTION_POINT_TYPE, Create.ID);
|
||||
|
||||
static {
|
||||
register("basin", new BasinType());
|
||||
register("belt", new BeltType());
|
||||
|
@ -89,12 +86,11 @@ public class AllArmInteractionPointTypes {
|
|||
}
|
||||
|
||||
private static <T extends ArmInteractionPointType> void register(String name, T type) {
|
||||
REGISTER.register(name, () -> type);
|
||||
Registry.register(CreateBuiltInRegistries.ARM_INTERACTION_POINT_TYPE, Create.asResource(name), type);
|
||||
}
|
||||
|
||||
@Internal
|
||||
public static void register(IEventBus eventBus) {
|
||||
REGISTER.register(eventBus);
|
||||
public static void init() {
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -27,7 +27,6 @@ import com.simibubi.create.foundation.item.ItemHelper;
|
|||
import com.simibubi.create.foundation.recipe.RecipeConditions;
|
||||
import com.simibubi.create.foundation.recipe.RecipeFinder;
|
||||
import com.simibubi.create.foundation.utility.AbstractBlockBreakQueue;
|
||||
import com.simibubi.create.foundation.utility.TreeCutter;
|
||||
import com.simibubi.create.infrastructure.config.AllConfigs;
|
||||
|
||||
import net.createmod.catnip.math.VecHelper;
|
||||
|
|
|
@ -10,7 +10,6 @@ import com.simibubi.create.content.contraptions.render.ContraptionMatrices;
|
|||
import com.simibubi.create.content.kinetics.base.BlockBreakingMovementBehaviour;
|
||||
import com.simibubi.create.foundation.damageTypes.CreateDamageSources;
|
||||
import com.simibubi.create.foundation.utility.AbstractBlockBreakQueue;
|
||||
import com.simibubi.create.foundation.utility.TreeCutter;
|
||||
import com.simibubi.create.foundation.virtualWorld.VirtualRenderWorld;
|
||||
|
||||
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
|
||||
|
@ -25,6 +24,7 @@ import net.minecraft.world.item.ItemStack;
|
|||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
import net.neoforged.neoforge.items.ItemHandlerHelper;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package com.simibubi.create.foundation.utility;
|
||||
package com.simibubi.create.content.kinetics.saw;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -18,6 +18,7 @@ import com.simibubi.create.AllTags;
|
|||
import com.simibubi.create.AllTags.AllBlockTags;
|
||||
import com.simibubi.create.compat.Mods;
|
||||
import com.simibubi.create.compat.dynamictrees.DynamicTree;
|
||||
import com.simibubi.create.foundation.utility.AbstractBlockBreakQueue;
|
||||
|
||||
import net.createmod.catnip.data.Iterate;
|
||||
import net.minecraft.core.BlockPos;
|
|
@ -49,7 +49,6 @@ import net.minecraft.world.item.context.UseOnContext;
|
|||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import net.neoforged.neoforge.items.ItemHandlerHelper;
|
||||
import net.neoforged.neoforge.items.ItemStackHandler;
|
||||
|
||||
|
@ -216,6 +215,8 @@ public class PackageItem extends Item {
|
|||
ItemStack itemstack = contents.getStackInSlot(i);
|
||||
if (itemstack.isEmpty())
|
||||
continue;
|
||||
if (itemstack.getItem() instanceof SpawnEggItem)
|
||||
continue;
|
||||
if (visibleNames > 2) {
|
||||
skippedNames++;
|
||||
continue;
|
||||
|
|
|
@ -3,11 +3,9 @@ package com.simibubi.create.content.logistics.item.filter.attribute;
|
|||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus.Internal;
|
||||
|
||||
import com.simibubi.create.AllRecipeTypes;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.api.registry.CreateRegistries;
|
||||
import com.simibubi.create.api.registry.CreateBuiltInRegistries;
|
||||
import com.simibubi.create.content.kinetics.fan.processing.AllFanProcessingTypes;
|
||||
import com.simibubi.create.content.logistics.item.filter.attribute.attributes.AddedByAttribute;
|
||||
import com.simibubi.create.content.logistics.item.filter.attribute.attributes.BookAuthorAttribute;
|
||||
|
@ -20,6 +18,7 @@ import com.simibubi.create.content.logistics.item.filter.attribute.attributes.In
|
|||
import com.simibubi.create.content.logistics.item.filter.attribute.attributes.ItemNameAttribute;
|
||||
import com.simibubi.create.content.logistics.item.filter.attribute.attributes.ShulkerFillLevelAttribute;
|
||||
|
||||
import net.minecraft.core.Registry;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
|
@ -37,12 +36,9 @@ import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity;
|
|||
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.neoforge.capabilities.Capabilities;
|
||||
import net.neoforged.neoforge.registries.DeferredRegister;
|
||||
|
||||
// TODO - Documentation
|
||||
public class AllItemAttributeTypes {
|
||||
private static final DeferredRegister<ItemAttributeType> REGISTER = DeferredRegister.create(CreateRegistries.ITEM_ATTRIBUTE_TYPE, Create.ID);
|
||||
|
||||
public static final ItemAttributeType
|
||||
PLACEABLE = singleton("placeable", s -> s.getItem() instanceof BlockItem),
|
||||
CONSUMABLE = singleton("consumable", s -> s.has(DataComponents.FOOD)),
|
||||
|
@ -103,12 +99,8 @@ public class AllItemAttributeTypes {
|
|||
}
|
||||
|
||||
private static ItemAttributeType register(String id, ItemAttributeType type) {
|
||||
REGISTER.register(id, () -> type);
|
||||
return type;
|
||||
return Registry.register(CreateBuiltInRegistries.ITEM_ATTRIBUTE_TYPE, Create.asResource(id), type);
|
||||
}
|
||||
|
||||
@Internal
|
||||
public static void register(IEventBus modEventBus) {
|
||||
REGISTER.register(modEventBus);
|
||||
}
|
||||
public static void init() {}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import java.util.List;
|
|||
|
||||
import com.simibubi.create.AllBlockEntityTypes;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.api.equipment.goggles.IHaveHoveringInformation;
|
||||
import com.simibubi.create.content.logistics.box.PackageItem;
|
||||
import com.simibubi.create.content.logistics.box.PackageStyles;
|
||||
|
@ -29,6 +30,8 @@ import net.minecraft.network.chat.Component;
|
|||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.ItemInteractionResult;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
|
@ -49,6 +52,7 @@ public class FrogportBlockEntity extends PackagePortBlockEntity implements IHave
|
|||
public LerpedFloat animationProgress;
|
||||
public LerpedFloat anticipationProgress;
|
||||
public boolean currentlyDepositing;
|
||||
public boolean goggles;
|
||||
|
||||
public boolean sendAnticipate;
|
||||
|
||||
|
@ -56,7 +60,7 @@ public class FrogportBlockEntity extends PackagePortBlockEntity implements IHave
|
|||
|
||||
private boolean failedLastExport;
|
||||
private FrogportSounds sounds;
|
||||
|
||||
|
||||
private ItemStack deferAnimationStart;
|
||||
private boolean deferAnimationInward;
|
||||
|
||||
|
@ -70,6 +74,7 @@ public class FrogportBlockEntity extends PackagePortBlockEntity implements IHave
|
|||
manualOpenAnimationProgress = LerpedFloat.linear()
|
||||
.startWithValue(0)
|
||||
.chase(0, 0.35, Chaser.LINEAR);
|
||||
goggles = false;
|
||||
}
|
||||
|
||||
public static void registerCapabilities(RegisterCapabilitiesEvent event) {
|
||||
|
@ -132,14 +137,14 @@ public class FrogportBlockEntity extends PackagePortBlockEntity implements IHave
|
|||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
|
||||
if (deferAnimationStart != null) {
|
||||
startAnimation(deferAnimationStart, deferAnimationInward);
|
||||
deferAnimationStart = null;
|
||||
}
|
||||
|
||||
if (anticipationProgress.getValue() == 1)
|
||||
anticipationProgress.updateChaseTarget(0);
|
||||
anticipationProgress.startWithValue(0);
|
||||
|
||||
manualOpenAnimationProgress.updateChaseTarget(openTracker.openCount > 0 ? 1 : 0);
|
||||
boolean wasOpen = manualOpenAnimationProgress.getValue() > 0;
|
||||
|
@ -321,6 +326,8 @@ public class FrogportBlockEntity extends PackagePortBlockEntity implements IHave
|
|||
}
|
||||
if (failedLastExport)
|
||||
NBTHelper.putMarker(tag, "FailedLastExport");
|
||||
if (goggles)
|
||||
NBTHelper.putMarker(tag, "Goggles");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -328,6 +335,7 @@ public class FrogportBlockEntity extends PackagePortBlockEntity implements IHave
|
|||
super.read(tag, registries, clientPacket);
|
||||
passiveYaw = tag.getFloat("PlacedYaw");
|
||||
failedLastExport = tag.getBoolean("FailedLastExport");
|
||||
goggles = tag.getBoolean("Goggles");
|
||||
if (!clientPacket)
|
||||
animatedPackage = null;
|
||||
if (tag.contains("AnimatedPackage")) {
|
||||
|
@ -361,4 +369,22 @@ public class FrogportBlockEntity extends PackagePortBlockEntity implements IHave
|
|||
sounds.open(level, worldPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemInteractionResult use(Player player) {
|
||||
if (player == null)
|
||||
return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
|
||||
|
||||
ItemStack mainHandItem = player.getMainHandItem();
|
||||
if (!goggles && AllItems.GOGGLES.isIn(mainHandItem)) {
|
||||
goggles = true;
|
||||
if (!level.isClientSide()) {
|
||||
notifyUpdate();
|
||||
level.playSound(null, worldPosition, SoundEvents.ARMOR_EQUIP_GOLD.value(), SoundSource.BLOCKS, 0.5f, 1.0f);
|
||||
}
|
||||
return ItemInteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
return super.use(player);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ public class FrogportRenderer extends SmartBlockEntityRenderer<FrogportBlockEnti
|
|||
.overlay(overlay)
|
||||
.renderInto(ms, buffer.getBuffer(RenderType.cutoutMipped()));
|
||||
|
||||
SuperByteBuffer head = CachedBuffers.partial(AllPartialModels.FROGPORT_HEAD, blockEntity.getBlockState());
|
||||
SuperByteBuffer head = CachedBuffers.partial(blockEntity.goggles ? AllPartialModels.FROGPORT_HEAD_GOGGLES : AllPartialModels.FROGPORT_HEAD, blockEntity.getBlockState());
|
||||
|
||||
head.center()
|
||||
.rotateYDegrees(yaw)
|
||||
|
|
|
@ -22,7 +22,7 @@ import net.minecraft.world.phys.Vec3;
|
|||
|
||||
public class FrogportVisual extends AbstractBlockEntityVisual<FrogportBlockEntity> implements SimpleDynamicVisual {
|
||||
private final TransformedInstance body;
|
||||
private final TransformedInstance head;
|
||||
private TransformedInstance head;
|
||||
private final TransformedInstance tongue;
|
||||
private final TransformedInstance rig;
|
||||
private final TransformedInstance box;
|
||||
|
@ -32,6 +32,7 @@ public class FrogportVisual extends AbstractBlockEntityVisual<FrogportBlockEntit
|
|||
private float lastHeadPitch = Float.NaN;
|
||||
private float lastTonguePitch = Float.NaN;
|
||||
private float lastTongueLength = Float.NaN;
|
||||
private boolean lastGoggles = false;
|
||||
|
||||
public FrogportVisual(VisualizationContext ctx, FrogportBlockEntity blockEntity, float partialTick) {
|
||||
super(ctx, blockEntity, partialTick);
|
||||
|
@ -68,6 +69,8 @@ public class FrogportVisual extends AbstractBlockEntityVisual<FrogportBlockEntit
|
|||
}
|
||||
|
||||
private void animate(float partialTicks) {
|
||||
updateGoggles();
|
||||
|
||||
float yaw = blockEntity.getYaw();
|
||||
|
||||
float headPitch = 80;
|
||||
|
@ -170,6 +173,28 @@ if (yaw != lastYaw) {
|
|||
}
|
||||
}
|
||||
|
||||
public void updateGoggles() {
|
||||
if (blockEntity.goggles && !lastGoggles) {
|
||||
head.delete();
|
||||
head = instancerProvider()
|
||||
.instancer(InstanceTypes.TRANSFORMED, Models.partial(AllPartialModels.FROGPORT_HEAD_GOGGLES))
|
||||
.createInstance();
|
||||
lastHeadPitch = -1;
|
||||
updateLight(0);
|
||||
lastGoggles = true;
|
||||
}
|
||||
|
||||
if (!blockEntity.goggles && lastGoggles) {
|
||||
head.delete();
|
||||
head = instancerProvider()
|
||||
.instancer(InstanceTypes.TRANSFORMED, Models.partial(AllPartialModels.FROGPORT_HEAD))
|
||||
.createInstance();
|
||||
lastHeadPitch = -1;
|
||||
updateLight(0);
|
||||
lastGoggles = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void renderPackage(Vec3 diff, float scale, float itemDistance) {
|
||||
if (blockEntity.animatedPackage == null || scale < 0.45) {
|
||||
rig.handle()
|
||||
|
|
|
@ -7,9 +7,6 @@ import java.util.Optional;
|
|||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.createmod.catnip.animation.AnimationTickHolder;
|
||||
import net.createmod.catnip.platform.CatnipServices;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
@ -25,10 +22,12 @@ import com.simibubi.create.foundation.gui.widget.IconButton;
|
|||
import com.simibubi.create.foundation.gui.widget.ScrollInput;
|
||||
import com.simibubi.create.foundation.utility.CreateLang;
|
||||
|
||||
import net.createmod.catnip.animation.AnimationTickHolder;
|
||||
import net.createmod.catnip.animation.LerpedFloat;
|
||||
import net.createmod.catnip.animation.LerpedFloat.Chaser;
|
||||
import net.createmod.catnip.gui.UIRenderHelper;
|
||||
import net.createmod.catnip.gui.element.GuiGameElement;
|
||||
import net.createmod.catnip.platform.CatnipServices;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
|
@ -127,13 +126,20 @@ public class StockKeeperCategoryScreen extends AbstractSimiContainerScreen<Stock
|
|||
|
||||
ItemStack stackInSlot = menu.proxyInventory.getStackInSlot(0)
|
||||
.copy();
|
||||
if (!stackInSlot.isEmpty())
|
||||
stackInSlot.set(DataComponents.CUSTOM_NAME, Component.literal(editorEditBox.getValue()));
|
||||
boolean empty = stackInSlot.isEmpty();
|
||||
|
||||
if (editingIndex == -1)
|
||||
schedule.add(stackInSlot);
|
||||
else
|
||||
schedule.set(editingIndex, stackInSlot);
|
||||
if (empty && editingIndex != -1)
|
||||
schedule.remove(editingIndex);
|
||||
|
||||
if (!empty) {
|
||||
String value = editorEditBox.getValue();
|
||||
stackInSlot.set(DataComponents.CUSTOM_NAME, value.isBlank() ? null : Component.literal(value));
|
||||
|
||||
if (editingIndex == -1)
|
||||
schedule.add(stackInSlot);
|
||||
else
|
||||
schedule.set(editingIndex, stackInSlot);
|
||||
}
|
||||
|
||||
CatnipServices.NETWORK.sendToServer(new GhostItemSubmitPacket(ItemStack.EMPTY, 0));
|
||||
|
||||
|
|
|
@ -261,7 +261,7 @@ public class StockKeeperRequestScreen extends AbstractSimiContainerScreen<StockK
|
|||
|
||||
extraAreas.add(new Rect2i(0, y + windowHeight - 15 - leftHeight, x, height));
|
||||
if (encodeRequester)
|
||||
extraAreas.add(new Rect2i(x + windowWidth, y + windowHeight - 15 - rightHeight, rightHeight, rightHeight));
|
||||
extraAreas.add(new Rect2i(x + windowWidth, y + windowHeight - 15 - rightHeight, rightHeight + 10, rightHeight));
|
||||
|
||||
if (initial) {
|
||||
playUiSound(SoundEvents.WOOD_HIT, 0.5f, 1.5f);
|
||||
|
@ -1078,9 +1078,16 @@ public class StockKeeperRequestScreen extends AbstractSimiContainerScreen<StockK
|
|||
if (indexOf >= blockEntity.categories.size())
|
||||
continue;
|
||||
|
||||
hiddenCategories.remove(indexOf);
|
||||
if (!entry.hidden)
|
||||
if (!entry.hidden) {
|
||||
hiddenCategories.add(indexOf);
|
||||
playUiSound(SoundEvents.ITEM_FRAME_ROTATE_ITEM, 0.75f, 1.5f);
|
||||
}
|
||||
|
||||
else {
|
||||
hiddenCategories.remove(indexOf);
|
||||
playUiSound(SoundEvents.ITEM_FRAME_ROTATE_ITEM, 0.75f, 0.675f);
|
||||
}
|
||||
|
||||
refreshSearchNextTick = true;
|
||||
moveToTopNextTick = false;
|
||||
return true;
|
||||
|
|
|
@ -18,7 +18,7 @@ public class TableClothFilteringBehaviour extends FilteringBehaviour {
|
|||
|
||||
public TableClothFilteringBehaviour(TableClothBlockEntity be) {
|
||||
super(be, new TableClothFilterSlot(be));
|
||||
withPredicate(is -> !(is.getItem() instanceof FilterItem));
|
||||
withPredicate(is -> !(is.getItem() instanceof FilterItem) && !(is.getItem() instanceof ShoppingListItem));
|
||||
count = 1;
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ public class TableClothFilteringBehaviour extends FilteringBehaviour {
|
|||
public void setValueSettings(Player player, ValueSettings settings, boolean ctrlDown) {
|
||||
if (getValueSettings().equals(settings))
|
||||
return;
|
||||
count = settings.value();
|
||||
count = Math.max(1, settings.value());
|
||||
blockEntity.setChanged();
|
||||
blockEntity.sendData();
|
||||
playFeedbackSound(this);
|
||||
|
|
|
@ -4,7 +4,6 @@ import org.apache.commons.lang3.mutable.MutableObject;
|
|||
|
||||
import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour;
|
||||
import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour.TransportedResult;
|
||||
import com.simibubi.create.content.logistics.box.PackageItem;
|
||||
import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlockEntity;
|
||||
import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext;
|
||||
import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats;
|
||||
|
@ -12,7 +11,6 @@ import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour
|
|||
|
||||
import net.minecraft.core.BlockPos.MutableBlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
|
@ -42,12 +40,8 @@ public class ItemNameDisplaySource extends SingleLineDisplaySource {
|
|||
});
|
||||
|
||||
ItemStack stack = stackHolder.getValue();
|
||||
if (stack != null && !stack.isEmpty()) {
|
||||
Component hoverName = stack.getHoverName();
|
||||
if (PackageItem.isPackage(stack))
|
||||
hoverName = Component.literal(PackageItem.getAddress(stack));
|
||||
combined = combined.append(hoverName);
|
||||
}
|
||||
if (stack != null && !stack.isEmpty())
|
||||
combined = combined.append(stack.getHoverName());
|
||||
}
|
||||
|
||||
return combined;
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
package com.simibubi.create.content.redstone.displayLink.source;
|
||||
|
||||
import com.simibubi.create.content.kinetics.chainConveyor.ChainConveyorBlockEntity;
|
||||
import com.simibubi.create.content.kinetics.chainConveyor.ChainConveyorPackage;
|
||||
import com.simibubi.create.content.logistics.box.PackageItem;
|
||||
import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext;
|
||||
import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats;
|
||||
import com.simibubi.create.content.redstone.smartObserver.SmartObserverBlock;
|
||||
import com.simibubi.create.content.redstone.smartObserver.SmartObserverBlockEntity;
|
||||
import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour;
|
||||
import com.simibubi.create.foundation.blockEntity.behaviour.inventory.InvManipulationBehaviour;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
|
||||
import net.neoforged.neoforge.items.IItemHandler;
|
||||
|
||||
public class PackageAddressDisplaySource extends SingleLineDisplaySource {
|
||||
|
||||
@Override
|
||||
protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) {
|
||||
BlockEntity sourceBE = context.getSourceBlockEntity();
|
||||
if (!(sourceBE instanceof SmartObserverBlockEntity cobe))
|
||||
return EMPTY_LINE;
|
||||
|
||||
InvManipulationBehaviour invManipulationBehaviour = cobe.getBehaviour(InvManipulationBehaviour.TYPE);
|
||||
FilteringBehaviour filteringBehaviour = cobe.getBehaviour(FilteringBehaviour.TYPE);
|
||||
IItemHandler handler = invManipulationBehaviour.getInventory();
|
||||
|
||||
if (handler == null) {
|
||||
BlockPos targetPos = cobe.getBlockPos().relative(SmartObserverBlock.getTargetDirection(cobe.getBlockState()));
|
||||
|
||||
if (context.level().getBlockEntity(targetPos) instanceof ChainConveyorBlockEntity ccbe)
|
||||
for (ChainConveyorPackage box : ccbe.getLoopingPackages())
|
||||
if (filteringBehaviour.test(box.item))
|
||||
return Component.literal(PackageItem.getAddress(box.item));
|
||||
|
||||
return EMPTY_LINE;
|
||||
}
|
||||
|
||||
for (int i = 0; i < handler.getSlots(); i++) {
|
||||
ItemStack stack = handler.getStackInSlot(i);
|
||||
if (PackageItem.isPackage(stack) && filteringBehaviour.test(stack))
|
||||
return Component.literal(PackageItem.getAddress(stack));
|
||||
}
|
||||
|
||||
return EMPTY_LINE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTranslationKey() {
|
||||
return "read_package_address";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean allowsLabeling(DisplayLinkContext context) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFlapDisplayLayoutName(DisplayLinkContext context) {
|
||||
return "Default";
|
||||
}
|
||||
|
||||
}
|
|
@ -18,9 +18,11 @@ public abstract class PercentOrProgressBarDisplaySource extends NumericSingleLin
|
|||
|
||||
@Override
|
||||
protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) {
|
||||
Float currentLevel = getProgress(context);
|
||||
if (currentLevel == null)
|
||||
Float rawProgress = this.getProgress(context);
|
||||
if (rawProgress == null)
|
||||
return EMPTY_LINE;
|
||||
// clamp just in case - #7371
|
||||
float currentLevel = Mth.clamp(rawProgress, 0, 1);
|
||||
if (!progressBarActive(context))
|
||||
return formatNumeric(context, currentLevel);
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ import com.simibubi.create.content.fluids.FluidTransportBehaviour;
|
|||
import com.simibubi.create.content.fluids.PipeConnection.Flow;
|
||||
import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour;
|
||||
import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour.TransportedResult;
|
||||
import com.simibubi.create.content.kinetics.chainConveyor.ChainConveyorBlockEntity;
|
||||
import com.simibubi.create.content.kinetics.chainConveyor.ChainConveyorPackage;
|
||||
import com.simibubi.create.content.redstone.DirectedDirectionalBlock;
|
||||
import com.simibubi.create.content.redstone.FilteredDetectorFilterSlot;
|
||||
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
|
||||
|
@ -112,6 +114,16 @@ public class SmartObserverBlockEntity extends SmartBlockEntity {
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Detect packages looping on a chain conveyor
|
||||
if (level.getBlockEntity(targetPos) instanceof ChainConveyorBlockEntity ccbe) {
|
||||
for (ChainConveyorPackage box : ccbe.getLoopingPackages())
|
||||
if (filtering.test(box.item)) {
|
||||
activate();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (observedInventory.hasInventory()) {
|
||||
boolean skipInv = invVersionTracker.stillWaiting(observedInventory);
|
||||
|
|
|
@ -137,6 +137,7 @@ public class ToolSelectionScreen extends Screen {
|
|||
matrixStack.popPose();
|
||||
}
|
||||
|
||||
RenderSystem.setShaderColor(1, 1, 1, 1);
|
||||
RenderSystem.disableBlend();
|
||||
matrixStack.popPose();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package com.simibubi.create.foundation.utility;
|
||||
package com.simibubi.create.foundation;
|
||||
|
||||
import java.util.List;
|
||||
|
|
@ -4,6 +4,7 @@ import java.util.function.Supplier;
|
|||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.content.contraptions.ContraptionHandler;
|
||||
|
@ -28,6 +29,7 @@ import com.simibubi.create.content.equipment.clipboard.ClipboardValueSettingsHan
|
|||
import com.simibubi.create.content.equipment.extendoGrip.ExtendoGripRenderHandler;
|
||||
import com.simibubi.create.content.equipment.goggles.GoggleOverlayRenderer;
|
||||
import com.simibubi.create.content.equipment.hats.CreateHatArmorLayer;
|
||||
import com.simibubi.create.content.equipment.potatoCannon.PotatoCannonItemRenderer;
|
||||
import com.simibubi.create.content.equipment.toolbox.ToolboxHandlerClient;
|
||||
import com.simibubi.create.content.equipment.zapper.ZapperItem;
|
||||
import com.simibubi.create.content.equipment.zapper.terrainzapper.WorldshaperRenderHandler;
|
||||
|
@ -103,6 +105,7 @@ import net.neoforged.neoforge.client.event.ClientTickEvent;
|
|||
import net.neoforged.neoforge.client.event.EntityRenderersEvent;
|
||||
import net.neoforged.neoforge.client.event.RegisterClientReloadListenersEvent;
|
||||
import net.neoforged.neoforge.client.event.RegisterGuiLayersEvent;
|
||||
import net.neoforged.neoforge.client.event.RegisterItemDecorationsEvent;
|
||||
import net.neoforged.neoforge.client.event.RenderLevelStageEvent;
|
||||
import net.neoforged.neoforge.client.event.RenderLevelStageEvent.Stage;
|
||||
import net.neoforged.neoforge.client.event.ViewportEvent;
|
||||
|
@ -386,6 +389,11 @@ public class ClientEvents {
|
|||
event.registerAbove(VanillaGuiLayers.HOTBAR, Create.asResource("toolbox"), ToolboxHandlerClient.OVERLAY);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void registerItemDecorations(RegisterItemDecorationsEvent event) {
|
||||
event.register(AllItems.POTATO_CANNON, PotatoCannonItemRenderer.DECORATOR);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onLoadComplete(FMLLoadCompleteEvent event) {
|
||||
ModContainer createContainer = ModList.get()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package com.simibubi.create.foundation.utility;
|
||||
package com.simibubi.create.foundation.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -17,6 +17,7 @@ import net.minecraft.client.resources.model.ModelResourceLocation;
|
|||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.neoforge.client.event.ModelEvent;
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
package com.simibubi.create.foundation.utility;
|
||||
|
||||
import net.minecraft.client.color.block.BlockColor;
|
||||
import net.minecraft.client.color.item.ItemColor;
|
||||
import net.minecraft.client.renderer.BiomeColors;
|
||||
import net.minecraft.world.level.GrassColor;
|
||||
import net.minecraft.world.level.block.RedStoneWireBlock;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
|
||||
public class ColorHandlers {
|
||||
|
||||
public static BlockColor getGrassyBlock() {
|
||||
return (state, world, pos, layer) -> pos != null && world != null ? BiomeColors.getAverageGrassColor(world, pos)
|
||||
: GrassColor.get(0.5D, 1.0D);
|
||||
}
|
||||
|
||||
public static ItemColor getGrassyItem() {
|
||||
return (stack, layer) -> GrassColor.get(0.5D, 1.0D);
|
||||
}
|
||||
|
||||
public static BlockColor getRedstonePower() {
|
||||
return (state, world, pos, layer) -> RedStoneWireBlock
|
||||
.getColorForPower(pos != null && world != null ? state.getValue(BlockStateProperties.POWER) : 0);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package com.simibubi.create.foundation.utility;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.createmod.catnip.platform.CatnipServices;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
||||
import net.neoforged.neoforge.server.ServerLifecycleHooks;
|
||||
|
||||
public final class GlobalRegistryAccess {
|
||||
private static Supplier<@Nullable RegistryAccess> supplier;
|
||||
|
||||
static {
|
||||
CatnipServices.PLATFORM.executeOnClientOnly(() -> () -> supplier = () -> {
|
||||
ClientPacketListener packetListener = Minecraft.getInstance().getConnection();
|
||||
if (packetListener == null) {
|
||||
return null;
|
||||
}
|
||||
return packetListener.registryAccess();
|
||||
});
|
||||
|
||||
if (supplier == null) {
|
||||
supplier = () -> {
|
||||
MinecraftServer server = ServerLifecycleHooks.getCurrentServer();
|
||||
if (server == null) {
|
||||
return null;
|
||||
}
|
||||
return server.registryAccess();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static RegistryAccess get() {
|
||||
return supplier.get();
|
||||
}
|
||||
|
||||
public static RegistryAccess getOrThrow() {
|
||||
RegistryAccess registryAccess = get();
|
||||
if (registryAccess == null) {
|
||||
throw new IllegalStateException("Could not get RegistryAccess");
|
||||
}
|
||||
return registryAccess;
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
package com.simibubi.create.foundation.utility;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ICoordinate {
|
||||
float get(BlockPos from);
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.simibubi.create.impl.registry;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus.Internal;
|
||||
|
||||
import com.simibubi.create.api.equipment.potatoCannon.PotatoCannonProjectileType;
|
||||
import com.simibubi.create.api.registry.CreateRegistries;
|
||||
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.EventBusSubscriber;
|
||||
import net.neoforged.fml.common.EventBusSubscriber.Bus;
|
||||
import net.neoforged.neoforge.registries.DataPackRegistryEvent;
|
||||
|
||||
@EventBusSubscriber(bus = Bus.MOD)
|
||||
public class CreateRegistriesImpl {
|
||||
@Internal
|
||||
@SubscribeEvent
|
||||
public static void registerDatapackRegistries(DataPackRegistryEvent.NewRegistry event) {
|
||||
event.dataPackRegistry(
|
||||
CreateRegistries.POTATO_PROJECTILE_TYPE,
|
||||
PotatoCannonProjectileType.CODEC,
|
||||
PotatoCannonProjectileType.CODEC
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.simibubi.create.foundation.utility;
|
||||
package com.simibubi.create.infrastructure;
|
||||
|
||||
import static com.simibubi.create.AllBlocks.ADJUSTABLE_CHAIN_GEARSHIFT;
|
||||
import static com.simibubi.create.AllBlocks.ANDESITE_ENCASED_SHAFT;
|
|
@ -130,6 +130,9 @@ public class CreateRegistrateTags {
|
|||
prov.tag(AllBlockTags.SUGAR_CANE_VARIANTS.tag)
|
||||
.add(Blocks.SUGAR_CANE);
|
||||
|
||||
prov.tag(AllBlockTags.NON_HARVESTABLE.tag)
|
||||
.add(Blocks.FIRE);
|
||||
|
||||
prov.tag(AllBlockTags.CORALS.tag)
|
||||
.add(Blocks.DEAD_TUBE_CORAL, Blocks.DEAD_BRAIN_CORAL, Blocks.DEAD_BUBBLE_CORAL, Blocks.DEAD_FIRE_CORAL,
|
||||
Blocks.DEAD_HORN_CORAL, Blocks.TUBE_CORAL, Blocks.BRAIN_CORAL, Blocks.BUBBLE_CORAL,
|
||||
|
|
|
@ -19,11 +19,13 @@ import net.minecraft.gametest.framework.GameTest;
|
|||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.projectile.Arrow;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.CropBlock;
|
||||
import net.minecraft.world.level.block.LeverBlock;
|
||||
import net.minecraft.world.level.block.RedstoneLampBlock;
|
||||
|
||||
import net.neoforged.neoforge.fluids.FluidStack;
|
||||
|
||||
@GameTestGroup(path = "contraptions")
|
||||
|
@ -230,4 +232,48 @@ public class TestContraptions {
|
|||
// public static void trainObserver(CreateGameTestHelper helper) {
|
||||
// helper.fail("NYI");
|
||||
// }
|
||||
|
||||
@GameTest(template = "dispensers_dont_fight")
|
||||
public static void dispensersDontFight(CreateGameTestHelper helper) {
|
||||
helper.pullLever(2, 3, 1);
|
||||
BlockPos bottom = new BlockPos(6, 4, 1);
|
||||
BlockPos top = new BlockPos(6, 6, 1);
|
||||
BlockPos dispenser = new BlockPos(3, 4, 1);
|
||||
|
||||
helper.succeedWhen(() -> {
|
||||
helper.assertEntitiesPresent(EntityType.ARROW, bottom, 3, 0);
|
||||
helper.assertEntityNotPresent(EntityType.ARROW, top);
|
||||
helper.assertBlockPresent(Blocks.DISPENSER, dispenser);
|
||||
helper.assertContainerContains(dispenser, new ItemStack(Items.ARROW, 2));
|
||||
});
|
||||
}
|
||||
|
||||
@GameTest(template = "dispensers_refill")
|
||||
public static void dispensersRefill(CreateGameTestHelper helper) {
|
||||
BlockPos lever = new BlockPos(2, 3, 1);
|
||||
helper.pullLever(lever);
|
||||
BlockPos barrel = lever.above();
|
||||
BlockPos dispenser = barrel.east();
|
||||
|
||||
helper.succeedWhen(() -> {
|
||||
helper.assertBlockPresent(Blocks.DISPENSER, dispenser);
|
||||
helper.assertContainerContains(dispenser, new ItemStack(Items.SPECTRAL_ARROW, 2));
|
||||
helper.assertContainerEmpty(barrel);
|
||||
});
|
||||
}
|
||||
|
||||
@GameTest(template = "vaults_protect_fuel")
|
||||
public static void vaultsProtectFuel(CreateGameTestHelper helper) {
|
||||
BlockPos lever = new BlockPos(2, 2, 1);
|
||||
helper.pullLever(lever);
|
||||
BlockPos barrelLamp = new BlockPos(1, 3, 3);
|
||||
BlockPos vaultLamp = barrelLamp.east(2);
|
||||
|
||||
helper.runAtTickTime(10, () -> helper.pullLever(lever));
|
||||
|
||||
helper.succeedWhen(() -> {
|
||||
helper.assertBlockProperty(barrelLamp, RedstoneLampBlock.LIT, false);
|
||||
helper.assertBlockProperty(vaultLamp, RedstoneLampBlock.LIT, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableBoolean;
|
||||
|
||||
import com.simibubi.create.AllBlockEntityTypes;
|
||||
import com.simibubi.create.content.fluids.hosePulley.HosePulleyFluidHandler;
|
||||
import com.simibubi.create.content.fluids.pipes.valve.FluidValveBlock;
|
||||
|
@ -16,20 +18,26 @@ import com.simibubi.create.infrastructure.gametest.GameTestGroup;
|
|||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.gametest.framework.GameTest;
|
||||
import net.minecraft.gametest.framework.GameTestAssertException;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.monster.Zombie;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.alchemy.PotionContents;
|
||||
import net.minecraft.world.item.alchemy.Potions;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.FarmBlock;
|
||||
import net.minecraft.world.level.block.LeverBlock;
|
||||
import net.minecraft.world.level.block.RedstoneLampBlock;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
|
||||
import net.neoforged.neoforge.fluids.FluidStack;
|
||||
import net.neoforged.neoforge.fluids.FluidType;
|
||||
import net.neoforged.neoforge.fluids.capability.IFluidHandler;
|
||||
|
@ -301,4 +309,59 @@ public class TestFluids {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
@GameTest(template = "open_pipes")
|
||||
public static void openPipes(CreateGameTestHelper helper) {
|
||||
BlockPos effects = new BlockPos(2, 4, 2);
|
||||
BlockPos removers = new BlockPos(3, 5, 2);
|
||||
|
||||
BlockPos firstSeat = new BlockPos(4, 2, 1);
|
||||
BlockPos secondSeat = firstSeat.south(2);
|
||||
|
||||
Zombie firstZombie = helper.spawn(EntityType.ZOMBIE, firstSeat);
|
||||
Zombie secondZombie = helper.spawn(EntityType.ZOMBIE, secondSeat);
|
||||
|
||||
helper.pullLever(effects);
|
||||
|
||||
MutableBoolean stage1 = new MutableBoolean(true);
|
||||
|
||||
helper.succeedWhen(() -> {
|
||||
if (stage1.booleanValue()) {
|
||||
helper.assertTrue(firstZombie.isOnFire(), "not ignited");
|
||||
helper.assertFalse(secondZombie.getActiveEffects().isEmpty(), "no effects");
|
||||
// success, stage 2 time
|
||||
stage1.setFalse();
|
||||
helper.pullLever(effects);
|
||||
helper.pullLever(removers);
|
||||
helper.fail("switching stages");
|
||||
} else {
|
||||
helper.assertFalse(firstZombie.isOnFire(), "not extinguished");
|
||||
helper.assertTrue(secondZombie.getActiveEffects().isEmpty(), "has effects");
|
||||
// all done
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@GameTest(template = "spouting", timeoutTicks = CreateGameTestHelper.TEN_SECONDS)
|
||||
public static void spouting(CreateGameTestHelper helper) {
|
||||
BlockPos farmland = new BlockPos(3, 2, 3);
|
||||
BlockPos depot = new BlockPos(5, 2, 1);
|
||||
helper.pullLever(2, 3, 2);
|
||||
ItemStack waterBottle = PotionContents.createItemStack(Items.POTION, Potions.WATER);
|
||||
|
||||
helper.succeedWhen(() -> {
|
||||
// lava
|
||||
helper.assertBlockPresent(Blocks.LAVA_CAULDRON, 3, 2, 1);
|
||||
// water
|
||||
helper.assertBlockProperty(farmland, FarmBlock.MOISTURE, 7);
|
||||
helper.assertBlockPresent(Blocks.MUD, farmland.east(1));
|
||||
helper.assertBlockPresent(Blocks.MUD, farmland.east(2));
|
||||
helper.assertBlockPresent(Blocks.MUD, farmland.east(3));
|
||||
helper.assertBlockPresent(Blocks.WATER_CAULDRON, farmland.east(4));
|
||||
|
||||
helper.assertContainerContains(depot, Items.WATER_BUCKET);
|
||||
helper.assertContainerContains(depot.east(1), waterBottle);
|
||||
helper.assertContainerContains(depot.east(2), Items.GRASS_BLOCK);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -419,4 +419,22 @@ public class TestItems {
|
|||
helper.assertNixiePower(halfPearlNixie, 8);
|
||||
});
|
||||
}
|
||||
|
||||
@GameTest(template = "fan_processing", timeoutTicks = CreateGameTestHelper.TEN_SECONDS)
|
||||
public static void fanProcessing(CreateGameTestHelper helper) {
|
||||
// why does the redstone explode
|
||||
BlockPos.betweenClosed(new BlockPos(2, 7, 3), new BlockPos(11, 7, 3)).forEach(
|
||||
pos -> helper.setBlock(pos, Blocks.REDSTONE_WIRE)
|
||||
);
|
||||
helper.pullLever(1, 7, 3);
|
||||
List<BlockPos> lamps = List.of(
|
||||
new BlockPos(1, 2, 1), new BlockPos(5, 2, 1), new BlockPos(7, 2, 1),
|
||||
new BlockPos(9, 2, 1), new BlockPos(11, 2, 1)
|
||||
);
|
||||
helper.succeedWhen(() -> {
|
||||
for (BlockPos lamp : lamps) {
|
||||
helper.assertBlockProperty(lamp, RedstoneLampBlock.LIT, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1139,6 +1139,7 @@
|
|||
"create.display_source.list_items": "List matching Items",
|
||||
"create.display_source.fluid_amount": "Amount of matching Fluids",
|
||||
"create.display_source.list_fluids": "List matching Fluids",
|
||||
"create.display_source.read_package_address": "Read Package Address",
|
||||
"create.display_source.nixie_tube": "Copy Nixie Tubes",
|
||||
"create.display_source.fill_level": "Container Fill Level",
|
||||
"create.display_source.fill_level.display": "Display Format",
|
||||
|
|
|
@ -2,79 +2,78 @@
|
|||
# www.blender.org
|
||||
mtllib conveyor_wheel.mtl
|
||||
o Cube.002
|
||||
v 0.965990 0.875000 -0.625000
|
||||
v 0.965990 0.125000 -0.625000
|
||||
v 0.034010 0.875000 -0.624999
|
||||
v 0.034010 0.125000 -0.624999
|
||||
v 0.000000 0.875000 0.000000
|
||||
v 0.062500 0.875000 0.000000
|
||||
v 0.937500 0.875000 0.000000
|
||||
v 1.000000 0.875000 0.000000
|
||||
v 0.062500 0.875000 -0.476712
|
||||
v 0.062500 0.875000 -0.556218
|
||||
v 0.937500 0.875000 -0.556218
|
||||
v 0.937500 0.875000 -0.476713
|
||||
v -0.295495 0.875000 -0.295494
|
||||
v -0.295495 0.125000 -0.295494
|
||||
v -0.207106 0.875000 -0.207106
|
||||
v 1.625000 0.875000 0.965990
|
||||
v 1.625000 0.125000 0.965990
|
||||
v 1.624999 0.875000 0.034010
|
||||
v 1.624999 0.125000 0.034010
|
||||
v 1.000000 0.875000 0.062500
|
||||
v 1.000000 0.875000 0.937500
|
||||
v 1.000000 0.875000 1.000000
|
||||
v 1.476712 0.875000 0.062500
|
||||
v 1.556218 0.875000 0.062500
|
||||
v 1.556218 0.875000 0.937500
|
||||
v 1.476713 0.875000 0.937500
|
||||
v 1.295495 0.125000 1.295495
|
||||
v 1.295494 0.875000 -0.295495
|
||||
v 1.295494 0.125000 -0.295495
|
||||
v 1.207106 0.875000 -0.207106
|
||||
v 0.034010 0.875000 1.625000
|
||||
v 0.034010 0.125000 1.625000
|
||||
v 0.965990 0.875000 1.624999
|
||||
v 0.965990 0.125000 1.624999
|
||||
v 0.937500 0.875000 1.000000
|
||||
v 0.062500 0.875000 1.000000
|
||||
v 0.000000 0.875000 1.000000
|
||||
v 0.937500 0.875000 1.476712
|
||||
v 0.937500 0.875000 1.556218
|
||||
v 0.062500 0.875000 1.556218
|
||||
v 0.062500 0.875000 1.476713
|
||||
v -0.295495 0.125000 1.295495
|
||||
v 1.295494 0.875000 1.295494
|
||||
v 1.207106 0.875000 1.207106
|
||||
v -0.625000 0.875000 0.034010
|
||||
v -0.625000 0.125000 0.034010
|
||||
v -0.624999 0.875000 0.965990
|
||||
v -0.624999 0.125000 0.965990
|
||||
v 0.000000 0.875000 0.937500
|
||||
v 0.000000 0.875000 0.062500
|
||||
v -0.476712 0.875000 0.937500
|
||||
v -0.556218 0.875000 0.937500
|
||||
v -0.556218 0.875000 0.062500
|
||||
v -0.476713 0.875000 0.062500
|
||||
v -0.295494 0.875000 1.295494
|
||||
v -0.207106 0.875000 1.207106
|
||||
v 0.500000 0.875000 0.500000
|
||||
v -0.246859 0.875000 -0.246859
|
||||
v -0.246859 0.875000 1.246859
|
||||
v 1.246859 0.875000 1.246859
|
||||
v 1.246859 0.875000 -0.246859
|
||||
v -0.499999 0.125000 0.914213
|
||||
v 0.085787 0.125000 -0.499999
|
||||
v 1.207106 0.125000 -0.207106
|
||||
v -0.207106 0.125000 -0.207106
|
||||
v 1.499999 0.125000 0.085787
|
||||
v 1.207107 0.125000 1.207107
|
||||
v 0.914213 0.125000 1.499999
|
||||
v -0.207107 0.125000 1.207106
|
||||
v -0.500000 0.125000 0.085787
|
||||
v 0.914213 0.125000 -0.500000
|
||||
v 1.500000 0.125000 0.914213
|
||||
v 0.085787 0.125000 1.500000
|
||||
v 0.965990 0.870000 -0.625000
|
||||
v 0.965990 0.130000 -0.625000
|
||||
v 0.034010 0.870000 -0.624999
|
||||
v 0.034010 0.130000 -0.624999
|
||||
v 0.000000 0.870000 -0.000000
|
||||
v 0.062500 0.870000 -0.000000
|
||||
v 0.937500 0.870000 -0.000000
|
||||
v 1.000000 0.870000 -0.000000
|
||||
v 0.062500 0.870000 -0.476712
|
||||
v 0.062500 0.870000 -0.556218
|
||||
v 0.937500 0.870000 -0.556218
|
||||
v 0.937500 0.870000 -0.476713
|
||||
v -0.295495 0.870000 -0.295494
|
||||
v -0.295495 0.130000 -0.295494
|
||||
v -0.207106 0.870000 -0.207106
|
||||
v 1.625000 0.870000 0.965990
|
||||
v 1.625000 0.130000 0.965990
|
||||
v 1.624999 0.870000 0.034010
|
||||
v 1.624999 0.130000 0.034010
|
||||
v 1.000000 0.870000 0.062500
|
||||
v 1.000000 0.870000 0.937500
|
||||
v 1.000000 0.870000 1.000000
|
||||
v 1.476712 0.870000 0.062500
|
||||
v 1.556218 0.870000 0.062500
|
||||
v 1.556218 0.870000 0.937500
|
||||
v 1.476713 0.870000 0.937500
|
||||
v 1.295495 0.130000 1.295495
|
||||
v 1.295494 0.870000 -0.295495
|
||||
v 1.295494 0.130000 -0.295495
|
||||
v 1.207106 0.870000 -0.207106
|
||||
v 0.034010 0.870000 1.625000
|
||||
v 0.034010 0.130000 1.625000
|
||||
v 0.965990 0.870000 1.624999
|
||||
v 0.965990 0.130000 1.624999
|
||||
v 0.937500 0.870000 1.000000
|
||||
v 0.062500 0.870000 1.000000
|
||||
v 0.000000 0.870000 1.000000
|
||||
v 0.937500 0.870000 1.476712
|
||||
v 0.937500 0.870000 1.556218
|
||||
v 0.062500 0.870000 1.556218
|
||||
v 0.062500 0.870000 1.476713
|
||||
v -0.295495 0.130000 1.295495
|
||||
v 1.295494 0.870000 1.295494
|
||||
v 1.207106 0.870000 1.207106
|
||||
v -0.625000 0.870000 0.034010
|
||||
v -0.625000 0.130000 0.034010
|
||||
v -0.624999 0.870000 0.965990
|
||||
v -0.624999 0.130000 0.965990
|
||||
v 0.000000 0.870000 0.937500
|
||||
v 0.000000 0.870000 0.062500
|
||||
v -0.476712 0.870000 0.937500
|
||||
v -0.556218 0.870000 0.937500
|
||||
v -0.556218 0.870000 0.062500
|
||||
v -0.476713 0.870000 0.062500
|
||||
v -0.295494 0.870000 1.295494
|
||||
v -0.207106 0.870000 1.207106
|
||||
v -0.246859 0.870000 -0.246859
|
||||
v -0.246859 0.870000 1.246859
|
||||
v 1.246859 0.870000 1.246859
|
||||
v 1.246859 0.870000 -0.246859
|
||||
v -0.499999 0.130000 0.914213
|
||||
v 0.085787 0.130000 -0.499999
|
||||
v 1.207106 0.130000 -0.207106
|
||||
v -0.207106 0.130000 -0.207106
|
||||
v 1.499999 0.130000 0.085787
|
||||
v 1.207107 0.130000 1.207107
|
||||
v 0.914213 0.130000 1.499999
|
||||
v -0.207107 0.130000 1.207106
|
||||
v -0.500000 0.130000 0.085787
|
||||
v 0.914213 0.130000 -0.500000
|
||||
v 1.500000 0.130000 0.914213
|
||||
v 0.085787 0.130000 1.500000
|
||||
v 0.500000 0.112500 0.500000
|
||||
v -0.499999 0.112500 0.914213
|
||||
v 0.085787 0.112500 -0.499999
|
||||
|
@ -114,25 +113,17 @@ vt 0.031250 0.925857
|
|||
vt 0.468750 0.925857
|
||||
vt 0.982995 0.750000
|
||||
vt 0.982995 0.375000
|
||||
vt 0.750000 0.937500
|
||||
vt 0.559359 0.937500
|
||||
vt 0.727903 0.768956
|
||||
vt 0.750000 0.791054
|
||||
vt 0.531250 0.965609
|
||||
vt 0.750000 0.965610
|
||||
vt 0.772097 0.768957
|
||||
vt 0.750000 0.791054
|
||||
vt 0.031250 0.925857
|
||||
vt 0.031250 0.687500
|
||||
vt 0.468750 0.687500
|
||||
vt 0.468750 0.925857
|
||||
vt 0.968750 0.965609
|
||||
vt 0.940641 0.937500
|
||||
vt 0.750000 0.937500
|
||||
vt 0.750000 0.965610
|
||||
vt 0.559360 0.937500
|
||||
vt 0.531250 0.965610
|
||||
vt 0.750000 0.965610
|
||||
vt 0.517005 1.000000
|
||||
vt 0.750000 1.000000
|
||||
vt 0.982995 1.000000
|
||||
|
@ -145,93 +136,92 @@ vt 0.031250 0.593750
|
|||
vt 0.031250 0.625000
|
||||
vt 0.000000 0.625000
|
||||
vt 0.482995 0.687500
|
||||
vt 0.042893 0.625000
|
||||
vt 0.457107 0.625000
|
||||
vt 0.500000 0.609375
|
||||
vt 0.000000 0.609375
|
||||
s 0
|
||||
s 1
|
||||
usemtl casing
|
||||
f 14/1/1 13/2/1 3/3/1 4/4/1
|
||||
f 10/5/2 11/6/2 1/7/2 3/8/2
|
||||
f 58/9/2 15/10/2 9/11/2 10/12/2
|
||||
f 57/9/2 15/10/2 9/11/2 10/12/2
|
||||
f 10/5/2 9/13/2 12/14/2 11/6/2
|
||||
f 3/15/3 1/3/3 2/4/3 4/16/3
|
||||
f 2/16/4 1/15/4 28/2/4 29/1/4
|
||||
f 30/17/2 12/18/2 7/19/2 8/20/2
|
||||
f 11/21/2 12/18/2 30/17/2 61/22/2
|
||||
f 6/23/2 9/11/2 15/10/2 5/24/2
|
||||
f 9/25/2 6/26/2 7/27/2 12/28/2
|
||||
f 30/10/2 12/17/2 7/18/2 8/19/2
|
||||
f 11/20/2 12/17/2 30/10/2 60/9/2
|
||||
f 6/21/2 9/11/2 15/10/2 5/19/2
|
||||
f 9/13/2 6/22/2 7/23/2 12/14/2
|
||||
f 29/1/4 28/2/4 18/3/4 19/4/4
|
||||
f 24/5/2 25/6/2 16/7/2 18/8/2
|
||||
f 61/9/2 30/10/2 23/11/2 24/12/2
|
||||
f 60/9/2 30/10/2 23/11/2 24/12/2
|
||||
f 24/5/2 23/13/2 26/14/2 25/6/2
|
||||
f 18/15/5 16/3/5 17/4/5 19/16/5
|
||||
f 17/16/6 16/15/6 43/2/6 27/1/6
|
||||
f 44/17/2 26/18/2 21/19/2 22/20/2
|
||||
f 25/29/2 26/30/2 44/31/2 60/32/2
|
||||
f 20/23/2 23/11/2 30/10/2 8/24/2
|
||||
f 23/25/2 20/26/2 21/27/2 26/28/2
|
||||
f 44/10/2 26/17/2 21/18/2 22/19/2
|
||||
f 25/24/2 26/25/2 44/10/2 59/9/2
|
||||
f 20/21/2 23/11/2 30/10/2 8/19/2
|
||||
f 23/13/2 20/22/2 21/23/2 26/14/2
|
||||
f 27/1/6 43/2/6 33/3/6 34/4/6
|
||||
f 39/5/2 40/6/2 31/7/2 33/8/2
|
||||
f 60/32/2 44/10/2 38/33/2 39/34/2
|
||||
f 59/9/2 44/10/2 38/26/2 39/27/2
|
||||
f 39/5/2 38/13/2 41/14/2 40/6/2
|
||||
f 33/15/7 31/3/7 32/4/7 34/16/7
|
||||
f 32/16/8 31/15/8 55/2/8 42/1/8
|
||||
f 56/17/2 41/18/2 36/19/2 37/20/2
|
||||
f 40/21/2 41/18/2 56/17/2 59/35/2
|
||||
f 35/23/2 38/11/2 44/10/2 22/24/2
|
||||
f 38/25/2 35/26/2 36/27/2 41/28/2
|
||||
f 56/10/2 41/17/2 36/18/2 37/19/2
|
||||
f 40/20/2 41/17/2 56/10/2 58/9/2
|
||||
f 35/21/2 38/11/2 44/10/2 22/19/2
|
||||
f 38/13/2 35/22/2 36/23/2 41/14/2
|
||||
f 42/1/8 55/2/8 47/3/8 48/4/8
|
||||
f 52/5/2 53/6/2 45/7/2 47/8/2
|
||||
f 59/35/2 56/10/2 51/11/2 52/12/2
|
||||
f 58/9/2 56/10/2 51/11/2 52/12/2
|
||||
f 52/5/2 51/13/2 54/14/2 53/6/2
|
||||
f 47/15/9 45/3/9 46/4/9 48/16/9
|
||||
f 46/16/1 45/15/1 13/2/1 14/1/1
|
||||
f 15/17/2 54/18/2 50/19/2 5/20/2
|
||||
f 53/21/2 54/18/2 15/17/2 58/9/2
|
||||
f 49/23/2 51/11/2 56/10/2 37/24/2
|
||||
f 51/25/2 49/26/2 50/27/2 54/28/2
|
||||
f 45/36/2 53/21/2 58/9/2 13/37/2
|
||||
f 13/37/2 58/9/2 10/12/2 3/38/2
|
||||
f 55/37/2 59/35/2 52/12/2 47/38/2
|
||||
f 31/36/2 40/21/2 59/35/2 55/37/2
|
||||
f 43/37/2 60/32/2 39/34/2 33/36/2
|
||||
f 16/38/2 25/29/2 60/32/2 43/37/2
|
||||
f 28/37/2 61/9/2 24/12/2 18/38/2
|
||||
f 1/36/2 11/21/2 61/22/2 28/37/2
|
||||
f 4/39/10 63/40/10 65/41/10 14/42/10
|
||||
f 63/43/3 71/44/3 84/45/3 76/46/3
|
||||
f 19/47/10 17/39/10 72/48/10 66/49/10
|
||||
f 72/43/6 67/44/6 80/45/6 85/46/6
|
||||
f 19/39/10 66/40/10 64/41/10 29/42/10
|
||||
f 64/43/4 66/44/4 79/45/4 77/46/4
|
||||
f 34/47/10 32/39/10 73/48/10 68/49/10
|
||||
f 62/43/9 70/44/9 83/45/9 75/46/9
|
||||
f 34/39/10 68/40/10 67/41/10 27/42/10
|
||||
f 73/43/8 69/44/8 82/45/8 86/46/8
|
||||
f 48/47/10 46/39/10 70/48/10 62/49/10
|
||||
f 66/43/5 72/44/5 85/45/5 79/46/5
|
||||
f 48/39/10 62/40/10 69/41/10 42/42/10
|
||||
f 67/43/6 68/44/6 81/45/6 80/46/6
|
||||
f 70/43/1 65/44/1 78/45/1 83/46/1
|
||||
f 65/43/1 63/44/1 76/45/1 78/46/1
|
||||
f 70/49/10 46/47/10 14/42/10 65/41/10
|
||||
f 71/43/4 64/44/4 77/45/4 84/46/4
|
||||
f 73/49/10 32/47/10 42/42/10 69/41/10
|
||||
f 68/43/7 73/44/7 86/45/7 81/46/7
|
||||
f 72/49/10 17/47/10 27/42/10 67/41/10
|
||||
f 69/43/8 62/44/8 75/45/8 82/46/8
|
||||
f 71/49/10 2/47/10 29/42/10 64/41/10
|
||||
f 4/47/10 2/39/10 71/48/10 63/49/10
|
||||
f 76/43/10 84/46/10 74/50/10
|
||||
f 76/46/10 74/50/10 78/51/10
|
||||
f 79/43/10 85/46/10 74/50/10
|
||||
f 79/46/10 74/50/10 77/51/10
|
||||
f 81/43/10 86/46/10 74/50/10
|
||||
f 81/46/10 74/50/10 80/51/10
|
||||
f 75/43/10 83/46/10 74/50/10
|
||||
f 75/46/10 74/50/10 82/51/10
|
||||
f 74/50/10 83/43/10 78/51/10
|
||||
f 74/50/10 86/43/10 82/51/10
|
||||
f 74/50/10 85/43/10 80/51/10
|
||||
f 74/50/10 84/43/10 77/51/10
|
||||
f 15/10/2 54/17/2 50/18/2 5/19/2
|
||||
f 53/20/2 54/17/2 15/10/2 57/9/2
|
||||
f 49/21/2 51/11/2 56/10/2 37/19/2
|
||||
f 51/13/2 49/22/2 50/23/2 54/14/2
|
||||
f 45/28/2 53/20/2 57/9/2 13/29/2
|
||||
f 13/29/2 57/9/2 10/12/2 3/30/2
|
||||
f 55/29/2 58/9/2 52/12/2 47/30/2
|
||||
f 31/28/2 40/20/2 58/9/2 55/29/2
|
||||
f 43/29/2 59/9/2 39/27/2 33/28/2
|
||||
f 16/30/2 25/24/2 59/9/2 43/29/2
|
||||
f 28/29/2 60/9/2 24/12/2 18/30/2
|
||||
f 1/28/2 11/20/2 60/9/2 28/29/2
|
||||
f 4/31/10 62/32/10 64/33/10 14/34/10
|
||||
f 62/35/3 70/36/3 83/37/3 75/38/3
|
||||
f 19/39/10 17/31/10 71/32/10 65/40/10
|
||||
f 71/35/6 66/36/6 79/37/6 84/38/6
|
||||
f 19/31/10 65/32/10 63/33/10 29/34/10
|
||||
f 63/35/4 65/36/4 78/37/4 76/38/4
|
||||
f 34/39/10 32/31/10 72/32/10 67/40/10
|
||||
f 61/35/9 69/36/9 82/37/9 74/38/9
|
||||
f 34/31/10 67/32/10 66/33/10 27/34/10
|
||||
f 72/35/8 68/36/8 81/37/8 85/38/8
|
||||
f 48/39/10 46/31/10 69/32/10 61/40/10
|
||||
f 65/35/5 71/36/5 84/37/5 78/38/5
|
||||
f 48/31/10 61/32/10 68/33/10 42/34/10
|
||||
f 66/35/6 67/36/6 80/37/6 79/38/6
|
||||
f 69/35/1 64/36/1 77/37/1 82/38/1
|
||||
f 64/35/1 62/36/1 75/37/1 77/38/1
|
||||
f 69/40/10 46/39/10 14/34/10 64/33/10
|
||||
f 70/35/4 63/36/4 76/37/4 83/38/4
|
||||
f 72/40/10 32/39/10 42/34/10 68/33/10
|
||||
f 67/35/7 72/36/7 85/37/7 80/38/7
|
||||
f 71/40/10 17/39/10 27/34/10 66/33/10
|
||||
f 68/35/8 61/36/8 74/37/8 81/38/8
|
||||
f 70/40/10 2/39/10 29/34/10 63/33/10
|
||||
f 4/39/10 2/31/10 70/32/10 62/40/10
|
||||
f 75/35/10 83/38/10 73/41/10
|
||||
f 75/38/10 73/41/10 77/42/10
|
||||
f 78/35/10 84/38/10 73/41/10
|
||||
f 78/38/10 73/41/10 76/42/10
|
||||
f 80/35/10 85/38/10 73/41/10
|
||||
f 80/38/10 73/41/10 79/42/10
|
||||
f 74/35/10 82/38/10 73/41/10
|
||||
f 74/38/10 73/41/10 81/42/10
|
||||
f 73/41/10 82/35/10 77/42/10
|
||||
f 73/41/10 85/35/10 81/42/10
|
||||
f 73/41/10 84/35/10 79/42/10
|
||||
f 73/41/10 83/35/10 76/42/10
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
{
|
||||
"credit": "Made with Blockbench",
|
||||
"textures": {
|
||||
"0": "create:block/port2",
|
||||
"1": "create:block/port",
|
||||
"2": "create:block/froggles",
|
||||
"particle": "create:block/port2"
|
||||
},
|
||||
"render_type": "minecraft:cutout",
|
||||
"elements": [
|
||||
{
|
||||
"from": [2, 9, 2],
|
||||
"to": [14, 14, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 9, 11]},
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 6, 2.5], "texture": "#1"},
|
||||
"east": {"uv": [12, 0, 6, 2.5], "texture": "#1"},
|
||||
"south": {"uv": [6, 10, 12, 12.5], "texture": "#1"},
|
||||
"west": {"uv": [6, 0, 12, 2.5], "texture": "#1"},
|
||||
"up": {"uv": [0, 10, 6, 16], "rotation": 180, "texture": "#1"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [14, 9, 2],
|
||||
"to": [2, 14, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [20, 10, 11]},
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 6, 2.5], "texture": "#1"},
|
||||
"east": {"uv": [12, 0, 6, 2.5], "texture": "#1"},
|
||||
"south": {"uv": [6, 10, 12, 12.5], "texture": "#1"},
|
||||
"west": {"uv": [6, 0, 12, 2.5], "texture": "#1"},
|
||||
"up": {"uv": [0, 10, 6, 16], "rotation": 180, "texture": "#1"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [2, 10, 2],
|
||||
"to": [14, 10, 11],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 10, 11]},
|
||||
"faces": {
|
||||
"down": {"uv": [0, 0, 6, 4.5], "rotation": 180, "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [1.8, 11, 1.8],
|
||||
"to": [5, 14.2, 5],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [2, 11, 2]},
|
||||
"faces": {
|
||||
"north": {"uv": [4.5, 0, 6, 1.5], "texture": "#1"},
|
||||
"east": {"uv": [8, 5.5, 9.5, 7], "texture": "#1"},
|
||||
"south": {"uv": [8, 5.5, 9.5, 7], "texture": "#1"},
|
||||
"west": {"uv": [6, 0, 7.5, 1.5], "texture": "#1"},
|
||||
"up": {"uv": [4.5, 14.5, 6, 16], "rotation": 180, "texture": "#1"},
|
||||
"down": {"uv": [8, 5.5, 9.5, 7], "texture": "#1"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [11, 11, 1.8],
|
||||
"to": [14.2, 14.2, 5],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [11, 11, 2]},
|
||||
"faces": {
|
||||
"north": {"uv": [6, 0, 4.5, 1.5], "texture": "#1"},
|
||||
"east": {"uv": [7.5, 0, 6, 1.5], "texture": "#1"},
|
||||
"south": {"uv": [8, 5.5, 9.5, 7], "texture": "#1"},
|
||||
"west": {"uv": [8, 5.5, 9.5, 7], "texture": "#1"},
|
||||
"up": {"uv": [4.5, 14.5, 6, 16], "rotation": 270, "texture": "#1"},
|
||||
"down": {"uv": [8, 5.5, 9.5, 7], "texture": "#1"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "lense ext",
|
||||
"from": [1.6, 10, 1.6],
|
||||
"to": [14.4, 14.4, 6],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [2, 10, 2]},
|
||||
"faces": {
|
||||
"north": {"uv": [0, 12, 12, 16], "texture": "#2"},
|
||||
"east": {"uv": [16, 12, 12, 16], "texture": "#2"},
|
||||
"west": {"uv": [12, 12, 16, 16], "texture": "#2"},
|
||||
"up": {"uv": [12, 12, 0, 8], "texture": "#2"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "lense int",
|
||||
"from": [14.4, 10, 1.6],
|
||||
"to": [1.6, 14.4, 6],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [15, 10, 2]},
|
||||
"faces": {
|
||||
"north": {"uv": [0, 12, 12, 16], "texture": "#2"},
|
||||
"east": {"uv": [16, 12, 12, 16], "texture": "#2"},
|
||||
"west": {"uv": [12, 12, 16, 16], "texture": "#2"},
|
||||
"up": {"uv": [12, 12, 0, 8], "texture": "#2"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "strap ext",
|
||||
"from": [1.6, 10, 6],
|
||||
"to": [14.4, 14.4, 14.4],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [2, 10, 6]},
|
||||
"faces": {
|
||||
"east": {"uv": [8, 0, 0, 4], "texture": "#2"},
|
||||
"south": {"uv": [0, 4, 12, 8], "texture": "#2"},
|
||||
"west": {"uv": [0, 0, 8, 4], "texture": "#2"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "strap int",
|
||||
"from": [14.4, 10, 6],
|
||||
"to": [1.6, 14.4, 14.4],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [15, 10, 6]},
|
||||
"faces": {
|
||||
"east": {"uv": [8, 0, 0, 4], "texture": "#2"},
|
||||
"south": {"uv": [12, 4, 0, 8], "texture": "#2"},
|
||||
"west": {"uv": [0, 0, 8, 4], "texture": "#2"}
|
||||
}
|
||||
}
|
||||
],
|
||||
"groups": [
|
||||
{
|
||||
"name": "port_head",
|
||||
"origin": [8, 8, 8],
|
||||
"color": 0,
|
||||
"children": [0, 1, 2, 3, 4]
|
||||
},
|
||||
{
|
||||
"name": "froggles",
|
||||
"origin": [8, 8, 8],
|
||||
"color": 0,
|
||||
"children": [5, 6, 7, 8]
|
||||
}
|
||||
]
|
||||
}
|
BIN
src/main/resources/assets/create/textures/block/froggles.png
Normal file
After Width: | Height: | Size: 582 B |
Before Width: | Height: | Size: 259 B |
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 372 B After Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 238 B After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 373 B After Width: | Height: | Size: 7 KiB |
Before Width: | Height: | Size: 253 B After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 394 B After Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 262 B After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 402 B After Width: | Height: | Size: 6.8 KiB |