mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-27 23:47:38 +01:00
Add data driven potato cannon projectile types
- Allow defining custom potato cannon projectile types through JSON in datapacks - Separate PotatoCannonProjectileTypes into PotatoCannonProjectileType, PotatoProjectileTypeManager, and BuiltinPotatoProjectileTypes - Allow setting a custom render mode when building a projectile type - Prevent the potato cannon itself from being used as ammo
This commit is contained in:
parent
86b0d80c1b
commit
173eb6b7ab
11 changed files with 517 additions and 218 deletions
|
@ -11,7 +11,7 @@ import com.simibubi.create.api.behaviour.BlockSpoutingBehaviour;
|
|||
import com.simibubi.create.content.CreateItemGroup;
|
||||
import com.simibubi.create.content.contraptions.TorquePropagator;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController;
|
||||
import com.simibubi.create.content.curiosities.weapons.PotatoCannonProjectileTypes;
|
||||
import com.simibubi.create.content.curiosities.weapons.BuiltinPotatoProjectileTypes;
|
||||
import com.simibubi.create.content.logistics.RedstoneLinkNetworkHandler;
|
||||
import com.simibubi.create.content.palettes.AllPaletteBlocks;
|
||||
import com.simibubi.create.content.palettes.PalettesItemGroup;
|
||||
|
@ -121,7 +121,7 @@ public class Create {
|
|||
CapabilityMinecartController.register();
|
||||
AllPackets.registerPackets();
|
||||
SchematicInstances.register();
|
||||
PotatoCannonProjectileTypes.register();
|
||||
BuiltinPotatoProjectileTypes.register();
|
||||
|
||||
CHUNK_UTIL.init();
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
package com.simibubi.create.content.curiosities.weapons;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Predicate;
|
||||
|
@ -23,7 +20,6 @@ import net.minecraft.entity.monster.ZombieVillagerEntity;
|
|||
import net.minecraft.entity.passive.FoxEntity;
|
||||
import net.minecraft.item.Food;
|
||||
import net.minecraft.item.Foods;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.potion.Effect;
|
||||
|
@ -31,8 +27,6 @@ import net.minecraft.potion.EffectInstance;
|
|||
import net.minecraft.potion.Effects;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.IItemProvider;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
import net.minecraft.util.SoundEvents;
|
||||
|
@ -50,16 +44,14 @@ import net.minecraftforge.event.ForgeEventFactory;
|
|||
import net.minecraftforge.event.entity.living.EntityTeleportEvent;
|
||||
import net.minecraftforge.registries.IRegistryDelegate;
|
||||
|
||||
public class PotatoCannonProjectileTypes {
|
||||
public class BuiltinPotatoProjectileTypes {
|
||||
|
||||
private static final GameProfile ZOMBIE_CONVERTER_NAME =
|
||||
new GameProfile(UUID.fromString("be12d3dc-27d3-4992-8c97-66be53fd49c5"), "Converter");
|
||||
private static final WorldAttached<FakePlayer> ZOMBIE_CONVERTERS =
|
||||
new WorldAttached<>(w -> new FakePlayer((ServerWorld) w, ZOMBIE_CONVERTER_NAME));
|
||||
|
||||
public static final Map<ResourceLocation, PotatoCannonProjectileTypes> ALL = new HashMap<>();
|
||||
public static final Map<IRegistryDelegate<Item>, PotatoCannonProjectileTypes> ITEM_MAP = new HashMap<>();
|
||||
public static final PotatoCannonProjectileTypes
|
||||
public static final PotatoCannonProjectileType
|
||||
|
||||
FALLBACK = create("fallback").damage(0)
|
||||
.register(),
|
||||
|
@ -250,94 +242,11 @@ public class PotatoCannonProjectileTypes {
|
|||
.preEntityHit(setFire(12))
|
||||
.soundPitch(1.0f)
|
||||
.registerAndAssign(AllItems.BLAZE_CAKE.get())
|
||||
|
||||
;
|
||||
|
||||
public static void registerType(ResourceLocation resLoc, PotatoCannonProjectileTypes type) {
|
||||
synchronized (ALL) {
|
||||
ALL.put(resLoc, type);
|
||||
}
|
||||
}
|
||||
|
||||
public static void assignType(IRegistryDelegate<Item> item, PotatoCannonProjectileTypes type) {
|
||||
synchronized (ITEM_MAP) {
|
||||
ITEM_MAP.put(item, type);
|
||||
}
|
||||
}
|
||||
|
||||
public static Optional<PotatoCannonProjectileTypes> getProjectileTypeOf(ItemStack item) {
|
||||
if (item.isEmpty())
|
||||
return Optional.empty();
|
||||
return Optional.ofNullable(ITEM_MAP.get(item.getItem().delegate));
|
||||
}
|
||||
|
||||
public static void register() {}
|
||||
|
||||
private static PotatoCannonProjectileTypes.Builder create(String name) {
|
||||
return new PotatoCannonProjectileTypes.Builder(Create.asResource(name));
|
||||
}
|
||||
|
||||
private float gravityMultiplier = 1;
|
||||
private float velocityMultiplier = 1;
|
||||
private float drag = 0.99f;
|
||||
private float knockback = 1;
|
||||
private int reloadTicks = 10;
|
||||
private int damage = 1;
|
||||
private int split = 1;
|
||||
private float fwoompPitch = 1;
|
||||
private boolean sticky = false;
|
||||
private PotatoProjectileRenderMode renderMode = new PotatoProjectileRenderMode.Billboard();
|
||||
private Predicate<EntityRayTraceResult> preEntityHit = e -> false; // True if hit should be canceled
|
||||
private Predicate<EntityRayTraceResult> onEntityHit = e -> false; // True if shouldn't recover projectile
|
||||
private BiPredicate<IWorld, BlockRayTraceResult> onBlockHit = (w, ray) -> false;
|
||||
|
||||
public float getGravityMultiplier() {
|
||||
return gravityMultiplier;
|
||||
}
|
||||
|
||||
public float getDrag() {
|
||||
return drag;
|
||||
}
|
||||
|
||||
public int getSplit() {
|
||||
return split;
|
||||
}
|
||||
|
||||
public float getVelocityMultiplier() {
|
||||
return velocityMultiplier;
|
||||
}
|
||||
|
||||
public float getKnockback() {
|
||||
return knockback;
|
||||
}
|
||||
|
||||
public int getReloadTicks() {
|
||||
return reloadTicks;
|
||||
}
|
||||
|
||||
public float getSoundPitch() {
|
||||
return fwoompPitch;
|
||||
}
|
||||
|
||||
public PotatoProjectileRenderMode getRenderMode() {
|
||||
return renderMode;
|
||||
}
|
||||
|
||||
public int getDamage() {
|
||||
return damage;
|
||||
}
|
||||
|
||||
public boolean isSticky() { return sticky; }
|
||||
|
||||
public boolean preEntityHit(EntityRayTraceResult ray) {
|
||||
return preEntityHit.test(ray);
|
||||
}
|
||||
|
||||
public boolean onEntityHit(EntityRayTraceResult ray) {
|
||||
return onEntityHit.test(ray);
|
||||
}
|
||||
|
||||
public boolean onBlockHit(IWorld world, BlockRayTraceResult ray) {
|
||||
return onBlockHit.test(world, ray);
|
||||
private static PotatoCannonProjectileType.Builder create(String name) {
|
||||
return new PotatoCannonProjectileType.Builder(Create.asResource(name));
|
||||
}
|
||||
|
||||
private static Predicate<EntityRayTraceResult> setFire(int seconds) {
|
||||
|
@ -477,103 +386,6 @@ public class PotatoCannonProjectileTypes {
|
|||
};
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
protected ResourceLocation loc;
|
||||
protected PotatoCannonProjectileTypes result;
|
||||
|
||||
public Builder(ResourceLocation loc) {
|
||||
this.result = new PotatoCannonProjectileTypes();
|
||||
this.loc = loc;
|
||||
}
|
||||
|
||||
public Builder damage(int damage) {
|
||||
result.damage = damage;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder gravity(float modifier) {
|
||||
result.gravityMultiplier = modifier;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder knockback(float knockback) {
|
||||
result.knockback = knockback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder drag(float drag) {
|
||||
result.drag = drag;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder reloadTicks(int reload) {
|
||||
result.reloadTicks = reload;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder splitInto(int split) {
|
||||
result.split = split;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder soundPitch(float pitch) {
|
||||
result.fwoompPitch = pitch;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder velocity(float velocity) {
|
||||
result.velocityMultiplier = velocity;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder renderTumbling() {
|
||||
result.renderMode = new PotatoProjectileRenderMode.Tumble();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder renderBillboard() {
|
||||
result.renderMode = new PotatoProjectileRenderMode.Billboard();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder renderTowardMotion(int spriteAngle, float spin) {
|
||||
result.renderMode = new PotatoProjectileRenderMode.TowardMotion(spriteAngle, spin);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder sticky() {
|
||||
result.sticky = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder preEntityHit(Predicate<EntityRayTraceResult> callback) {
|
||||
result.preEntityHit = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder onEntityHit(Predicate<EntityRayTraceResult> callback) {
|
||||
result.onEntityHit = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder onBlockHit(BiPredicate<IWorld, BlockRayTraceResult> callback) {
|
||||
result.onBlockHit = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PotatoCannonProjectileTypes register() {
|
||||
registerType(loc, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public PotatoCannonProjectileTypes registerAndAssign(IItemProvider... items) {
|
||||
registerType(loc, result);
|
||||
for (IItemProvider provider : items)
|
||||
assignType(provider.asItem().delegate, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
public static void register() {}
|
||||
|
||||
}
|
|
@ -49,13 +49,12 @@ public class PotatoCannonItem extends ShootableItem {
|
|||
public static ItemStack CLIENT_CURRENT_AMMO = ItemStack.EMPTY;
|
||||
public static final int MAX_DAMAGE = 100;
|
||||
|
||||
public PotatoCannonItem(Properties p_i48487_1_) {
|
||||
super(p_i48487_1_);
|
||||
public PotatoCannonItem(Properties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAttackBlock(BlockState p_195938_1_, World p_195938_2_, BlockPos p_195938_3_,
|
||||
PlayerEntity p_195938_4_) {
|
||||
public boolean canAttackBlock(BlockState state, World world, BlockPos pos, PlayerEntity player) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -137,8 +136,8 @@ public class PotatoCannonItem extends ShootableItem {
|
|||
.subtract(player.position()
|
||||
.add(0, player.getEyeHeight(), 0));
|
||||
|
||||
PotatoCannonProjectileTypes projectileType = PotatoCannonProjectileTypes.getProjectileTypeOf(itemStack)
|
||||
.orElse(PotatoCannonProjectileTypes.FALLBACK);
|
||||
PotatoCannonProjectileType projectileType = PotatoProjectileTypeManager.getTypeForStack(itemStack)
|
||||
.orElse(BuiltinPotatoProjectileTypes.FALLBACK);
|
||||
Vector3d lookVec = player.getLookAngle();
|
||||
Vector3d motion = lookVec.add(correction)
|
||||
.normalize()
|
||||
|
@ -181,8 +180,8 @@ public class PotatoCannonItem extends ShootableItem {
|
|||
stack.hurtAndBreak(1, player, p -> p.broadcastBreakEvent(hand));
|
||||
|
||||
Integer cooldown =
|
||||
findAmmoInInventory(world, player, stack).flatMap(PotatoCannonProjectileTypes::getProjectileTypeOf)
|
||||
.map(PotatoCannonProjectileTypes::getReloadTicks)
|
||||
findAmmoInInventory(world, player, stack).flatMap(PotatoProjectileTypeManager::getTypeForStack)
|
||||
.map(PotatoCannonProjectileType::getReloadTicks)
|
||||
.orElse(10);
|
||||
|
||||
ShootableGadgetItemMethods.applyCooldown(player, stack, hand, this::isCannon, cooldown);
|
||||
|
@ -200,7 +199,7 @@ public class PotatoCannonItem extends ShootableItem {
|
|||
|
||||
private Optional<ItemStack> findAmmoInInventory(World world, PlayerEntity player, ItemStack held) {
|
||||
ItemStack findAmmo = player.getProjectile(held);
|
||||
return PotatoCannonProjectileTypes.getProjectileTypeOf(findAmmo)
|
||||
return PotatoProjectileTypeManager.getTypeForStack(findAmmo)
|
||||
.map($ -> findAmmo);
|
||||
}
|
||||
|
||||
|
@ -215,7 +214,7 @@ public class PotatoCannonItem extends ShootableItem {
|
|||
if (player == null)
|
||||
return Optional.empty();
|
||||
ItemStack findAmmo = player.getProjectile(cannon);
|
||||
Optional<ItemStack> found = PotatoCannonProjectileTypes.getProjectileTypeOf(findAmmo)
|
||||
Optional<ItemStack> found = PotatoProjectileTypeManager.getTypeForStack(findAmmo)
|
||||
.map($ -> findAmmo);
|
||||
found.ifPresent(stack -> CLIENT_CURRENT_AMMO = stack);
|
||||
return found;
|
||||
|
@ -237,7 +236,7 @@ public class PotatoCannonItem extends ShootableItem {
|
|||
tooltip.add(new StringTextComponent(""));
|
||||
tooltip.add(new TranslationTextComponent(ammo.getDescriptionId()).append(new StringTextComponent(":"))
|
||||
.withStyle(TextFormatting.GRAY));
|
||||
PotatoCannonProjectileTypes type = PotatoCannonProjectileTypes.getProjectileTypeOf(ammo)
|
||||
PotatoCannonProjectileType type = PotatoProjectileTypeManager.getTypeForStack(ammo)
|
||||
.get();
|
||||
StringTextComponent spacing = new StringTextComponent(" ");
|
||||
TextFormatting green = TextFormatting.GREEN;
|
||||
|
@ -269,7 +268,7 @@ public class PotatoCannonItem extends ShootableItem {
|
|||
|
||||
@Override
|
||||
public Predicate<ItemStack> getAllSupportedProjectiles() {
|
||||
return stack -> PotatoCannonProjectileTypes.getProjectileTypeOf(stack)
|
||||
return stack -> PotatoProjectileTypeManager.getTypeForStack(stack)
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,295 @@
|
|||
package com.simibubi.create.content.curiosities.weapons;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraft.util.IItemProvider;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.ResourceLocationException;
|
||||
import net.minecraft.util.math.BlockRayTraceResult;
|
||||
import net.minecraft.util.math.EntityRayTraceResult;
|
||||
import net.minecraft.world.IWorld;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import net.minecraftforge.registries.IRegistryDelegate;
|
||||
|
||||
public class PotatoCannonProjectileType {
|
||||
|
||||
private Set<IRegistryDelegate<Item>> items = new HashSet<>();
|
||||
|
||||
private int reloadTicks = 10;
|
||||
private int damage = 1;
|
||||
private int split = 1;
|
||||
private float knockback = 1;
|
||||
private float drag = 0.99f;
|
||||
private float velocityMultiplier = 1;
|
||||
private float gravityMultiplier = 1;
|
||||
private float soundPitch = 1;
|
||||
private boolean sticky = false;
|
||||
private PotatoProjectileRenderMode renderMode = PotatoProjectileRenderMode.Billboard.INSTANCE;
|
||||
|
||||
private Predicate<EntityRayTraceResult> preEntityHit = e -> false; // True if hit should be canceled
|
||||
private Predicate<EntityRayTraceResult> onEntityHit = e -> false; // True if shouldn't recover projectile
|
||||
private BiPredicate<IWorld, BlockRayTraceResult> onBlockHit = (w, ray) -> false;
|
||||
|
||||
protected PotatoCannonProjectileType() {
|
||||
}
|
||||
|
||||
public Set<IRegistryDelegate<Item>> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public int getReloadTicks() {
|
||||
return reloadTicks;
|
||||
}
|
||||
|
||||
public int getDamage() {
|
||||
return damage;
|
||||
}
|
||||
|
||||
public int getSplit() {
|
||||
return split;
|
||||
}
|
||||
|
||||
public float getKnockback() {
|
||||
return knockback;
|
||||
}
|
||||
|
||||
public float getDrag() {
|
||||
return drag;
|
||||
}
|
||||
|
||||
public float getVelocityMultiplier() {
|
||||
return velocityMultiplier;
|
||||
}
|
||||
|
||||
public float getGravityMultiplier() {
|
||||
return gravityMultiplier;
|
||||
}
|
||||
|
||||
public float getSoundPitch() {
|
||||
return soundPitch;
|
||||
}
|
||||
|
||||
public boolean isSticky() {
|
||||
return sticky;
|
||||
}
|
||||
|
||||
public PotatoProjectileRenderMode getRenderMode() {
|
||||
return renderMode;
|
||||
}
|
||||
|
||||
public boolean preEntityHit(EntityRayTraceResult ray) {
|
||||
return preEntityHit.test(ray);
|
||||
}
|
||||
|
||||
public boolean onEntityHit(EntityRayTraceResult ray) {
|
||||
return onEntityHit.test(ray);
|
||||
}
|
||||
|
||||
public boolean onBlockHit(IWorld world, BlockRayTraceResult ray) {
|
||||
return onBlockHit.test(world, ray);
|
||||
}
|
||||
|
||||
public static PotatoCannonProjectileType fromJson(JsonObject object) {
|
||||
PotatoCannonProjectileType type = new PotatoCannonProjectileType();
|
||||
try {
|
||||
JsonElement itemsElement = object.get("items");
|
||||
if (itemsElement != null && itemsElement.isJsonArray()) {
|
||||
for (JsonElement element : itemsElement.getAsJsonArray()) {
|
||||
if (element.isJsonPrimitive()) {
|
||||
JsonPrimitive primitive = element.getAsJsonPrimitive();
|
||||
if (primitive.isString()) {
|
||||
try {
|
||||
Item item = ForgeRegistries.ITEMS.getValue(new ResourceLocation(primitive.getAsString()));
|
||||
if (item != null) {
|
||||
type.items.add(item.delegate);
|
||||
}
|
||||
} catch (ResourceLocationException e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parseJsonPrimitive(object, "reload_ticks", JsonPrimitive::isNumber, primitive -> type.reloadTicks = primitive.getAsInt());
|
||||
parseJsonPrimitive(object, "damage", JsonPrimitive::isNumber, primitive -> type.damage = primitive.getAsInt());
|
||||
parseJsonPrimitive(object, "split", JsonPrimitive::isNumber, primitive -> type.split = primitive.getAsInt());
|
||||
parseJsonPrimitive(object, "knockback", JsonPrimitive::isNumber, primitive -> type.knockback = primitive.getAsFloat());
|
||||
parseJsonPrimitive(object, "drag", JsonPrimitive::isNumber, primitive -> type.drag = primitive.getAsFloat());
|
||||
parseJsonPrimitive(object, "velocity_multiplier", JsonPrimitive::isNumber, primitive -> type.velocityMultiplier = primitive.getAsFloat());
|
||||
parseJsonPrimitive(object, "gravity_multiplier", JsonPrimitive::isNumber, primitive -> type.gravityMultiplier = primitive.getAsFloat());
|
||||
parseJsonPrimitive(object, "sound_pitch", JsonPrimitive::isNumber, primitive -> type.soundPitch = primitive.getAsFloat());
|
||||
parseJsonPrimitive(object, "sticky", JsonPrimitive::isBoolean, primitive -> type.sticky = primitive.getAsBoolean());
|
||||
} catch (Exception e) {
|
||||
//
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
private static void parseJsonPrimitive(JsonObject object, String key, Predicate<JsonPrimitive> predicate, Consumer<JsonPrimitive> consumer) {
|
||||
JsonElement element = object.get(key);
|
||||
if (element != null && element.isJsonPrimitive()) {
|
||||
JsonPrimitive primitive = element.getAsJsonPrimitive();
|
||||
if (predicate.test(primitive)) {
|
||||
consumer.accept(primitive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void toBuffer(PotatoCannonProjectileType type, PacketBuffer buffer) {
|
||||
buffer.writeVarInt(type.items.size());
|
||||
for (IRegistryDelegate<Item> delegate : type.items) {
|
||||
buffer.writeResourceLocation(delegate.name());
|
||||
}
|
||||
buffer.writeInt(type.reloadTicks);
|
||||
buffer.writeInt(type.damage);
|
||||
buffer.writeInt(type.split);
|
||||
buffer.writeFloat(type.knockback);
|
||||
buffer.writeFloat(type.drag);
|
||||
buffer.writeFloat(type.velocityMultiplier);
|
||||
buffer.writeFloat(type.gravityMultiplier);
|
||||
buffer.writeFloat(type.soundPitch);
|
||||
buffer.writeBoolean(type.sticky);
|
||||
}
|
||||
|
||||
public static PotatoCannonProjectileType fromBuffer(PacketBuffer buffer) {
|
||||
PotatoCannonProjectileType type = new PotatoCannonProjectileType();
|
||||
int size = buffer.readVarInt();
|
||||
for (int i = 0; i < size; i++) {
|
||||
Item item = ForgeRegistries.ITEMS.getValue(buffer.readResourceLocation());
|
||||
if (item != null) {
|
||||
type.items.add(item.delegate);
|
||||
}
|
||||
}
|
||||
type.reloadTicks = buffer.readInt();
|
||||
type.damage = buffer.readInt();
|
||||
type.split = buffer.readInt();
|
||||
type.knockback = buffer.readFloat();
|
||||
type.drag = buffer.readFloat();
|
||||
type.velocityMultiplier = buffer.readFloat();
|
||||
type.gravityMultiplier = buffer.readFloat();
|
||||
type.soundPitch = buffer.readFloat();
|
||||
type.sticky = buffer.readBoolean();
|
||||
return type;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
protected ResourceLocation id;
|
||||
protected PotatoCannonProjectileType result;
|
||||
|
||||
public Builder(ResourceLocation id) {
|
||||
this.id = id;
|
||||
this.result = new PotatoCannonProjectileType();
|
||||
}
|
||||
|
||||
public Builder reloadTicks(int reload) {
|
||||
result.reloadTicks = reload;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder damage(int damage) {
|
||||
result.damage = damage;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder splitInto(int split) {
|
||||
result.split = split;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder knockback(float knockback) {
|
||||
result.knockback = knockback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder drag(float drag) {
|
||||
result.drag = drag;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder velocity(float velocity) {
|
||||
result.velocityMultiplier = velocity;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder gravity(float modifier) {
|
||||
result.gravityMultiplier = modifier;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder soundPitch(float pitch) {
|
||||
result.soundPitch = pitch;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder sticky() {
|
||||
result.sticky = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder renderMode(PotatoProjectileRenderMode renderMode) {
|
||||
result.renderMode = renderMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder renderBillboard() {
|
||||
renderMode(PotatoProjectileRenderMode.Billboard.INSTANCE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder renderTumbling() {
|
||||
renderMode(PotatoProjectileRenderMode.Tumble.INSTANCE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder renderTowardMotion(int spriteAngle, float spin) {
|
||||
renderMode(new PotatoProjectileRenderMode.TowardMotion(spriteAngle, spin));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder preEntityHit(Predicate<EntityRayTraceResult> callback) {
|
||||
result.preEntityHit = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder onEntityHit(Predicate<EntityRayTraceResult> callback) {
|
||||
result.onEntityHit = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder onBlockHit(BiPredicate<IWorld, BlockRayTraceResult> callback) {
|
||||
result.onBlockHit = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addItems(IItemProvider... items) {
|
||||
for (IItemProvider provider : items)
|
||||
result.items.add(provider.asItem().delegate);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PotatoCannonProjectileType register() {
|
||||
PotatoProjectileTypeManager.registerBuiltinType(id, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public PotatoCannonProjectileType registerAndAssign(IItemProvider... items) {
|
||||
addItems(items);
|
||||
register();
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -39,7 +39,7 @@ import net.minecraftforge.items.ItemHandlerHelper;
|
|||
|
||||
public class PotatoProjectileEntity extends DamagingProjectileEntity implements IEntityAdditionalSpawnData {
|
||||
|
||||
PotatoCannonProjectileTypes type;
|
||||
PotatoCannonProjectileType type;
|
||||
ItemStack stack = ItemStack.EMPTY;
|
||||
|
||||
Entity stuckEntity;
|
||||
|
@ -63,10 +63,10 @@ public class PotatoProjectileEntity extends DamagingProjectileEntity implements
|
|||
this.stack = stack;
|
||||
}
|
||||
|
||||
public PotatoCannonProjectileTypes getProjectileType() {
|
||||
public PotatoCannonProjectileType getProjectileType() {
|
||||
if (type == null)
|
||||
type = PotatoCannonProjectileTypes.getProjectileTypeOf(stack)
|
||||
.orElse(PotatoCannonProjectileTypes.FALLBACK);
|
||||
type = PotatoProjectileTypeManager.getTypeForStack(stack)
|
||||
.orElse(BuiltinPotatoProjectileTypes.FALLBACK);
|
||||
return type;
|
||||
}
|
||||
|
||||
|
@ -128,7 +128,7 @@ public class PotatoProjectileEntity extends DamagingProjectileEntity implements
|
|||
}
|
||||
|
||||
public void tick() {
|
||||
PotatoCannonProjectileTypes projectileType = getProjectileType();
|
||||
PotatoCannonProjectileType projectileType = getProjectileType();
|
||||
|
||||
Entity stuckEntity = getStuckEntity();
|
||||
if (stuckEntity != null) {
|
||||
|
@ -174,7 +174,7 @@ public class PotatoProjectileEntity extends DamagingProjectileEntity implements
|
|||
|
||||
Vector3d hit = ray.getLocation();
|
||||
Entity target = ray.getEntity();
|
||||
PotatoCannonProjectileTypes projectileType = getProjectileType();
|
||||
PotatoCannonProjectileType projectileType = getProjectileType();
|
||||
float damage = projectileType.getDamage() * additionalDamageMult;
|
||||
float knockback = projectileType.getKnockback() + additionalKnockback;
|
||||
Entity owner = this.getOwner();
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package com.simibubi.create.content.curiosities.weapons;
|
||||
|
||||
import static com.simibubi.create.content.curiosities.weapons.PotatoProjectileRenderMode.entityRandom;
|
||||
|
||||
import com.jozufozu.flywheel.util.transform.MatrixTransformStack;
|
||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
|
@ -20,6 +18,8 @@ public interface PotatoProjectileRenderMode {
|
|||
|
||||
public static class Billboard implements PotatoProjectileRenderMode {
|
||||
|
||||
public static final Billboard INSTANCE = new Billboard();
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void transform(MatrixStack ms, PotatoProjectileEntity entity, float pt) {
|
||||
|
@ -35,10 +35,13 @@ public interface PotatoProjectileRenderMode {
|
|||
.rotateX(180
|
||||
+ AngleHelper.deg(MathHelper.atan2(diff.y, -MathHelper.sqrt(diff.x * diff.x + diff.z * diff.z))));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Tumble extends Billboard {
|
||||
|
||||
public static final Tumble INSTANCE = new Tumble();
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void transform(MatrixStack ms, PotatoProjectileEntity entity, float pt) {
|
||||
|
@ -47,6 +50,7 @@ public interface PotatoProjectileRenderMode {
|
|||
.rotateZ((entity.tickCount + pt) * 2 * entityRandom(entity, 16))
|
||||
.rotateX((entity.tickCount + pt) * entityRandom(entity, 32));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class TowardMotion implements PotatoProjectileRenderMode {
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
package com.simibubi.create.content.curiosities.weapons;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.foundation.networking.AllPackets;
|
||||
import com.simibubi.create.foundation.networking.SimplePacketBase;
|
||||
|
||||
import net.minecraft.client.resources.JsonReloadListener;
|
||||
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraft.profiler.IProfiler;
|
||||
import net.minecraft.resources.IResourceManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.fml.network.NetworkEvent.Context;
|
||||
import net.minecraftforge.fml.network.PacketDistributor;
|
||||
import net.minecraftforge.registries.IRegistryDelegate;
|
||||
|
||||
public class PotatoProjectileTypeManager {
|
||||
|
||||
private static final Map<ResourceLocation, PotatoCannonProjectileType> BUILTIN_TYPE_MAP = new HashMap<>();
|
||||
private static final Map<ResourceLocation, PotatoCannonProjectileType> CUSTOM_TYPE_MAP = new HashMap<>();
|
||||
private static final Map<IRegistryDelegate<Item>, PotatoCannonProjectileType> ITEM_TO_TYPE_MAP = new HashMap<>();
|
||||
|
||||
public static void registerBuiltinType(ResourceLocation id, PotatoCannonProjectileType type) {
|
||||
synchronized (BUILTIN_TYPE_MAP) {
|
||||
BUILTIN_TYPE_MAP.put(id, type);
|
||||
}
|
||||
}
|
||||
|
||||
public static PotatoCannonProjectileType getBuiltinType(ResourceLocation id) {
|
||||
return BUILTIN_TYPE_MAP.get(id);
|
||||
}
|
||||
|
||||
public static PotatoCannonProjectileType getCustomType(ResourceLocation id) {
|
||||
return CUSTOM_TYPE_MAP.get(id);
|
||||
}
|
||||
|
||||
public static PotatoCannonProjectileType getTypeForItem(IRegistryDelegate<Item> item) {
|
||||
return ITEM_TO_TYPE_MAP.get(item);
|
||||
}
|
||||
|
||||
public static Optional<PotatoCannonProjectileType> getTypeForStack(ItemStack item) {
|
||||
if (item.isEmpty())
|
||||
return Optional.empty();
|
||||
return Optional.ofNullable(getTypeForItem(item.getItem().delegate));
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
CUSTOM_TYPE_MAP.clear();
|
||||
ITEM_TO_TYPE_MAP.clear();
|
||||
}
|
||||
|
||||
public static void fillItemMap() {
|
||||
for (Map.Entry<ResourceLocation, PotatoCannonProjectileType> entry : BUILTIN_TYPE_MAP.entrySet()) {
|
||||
PotatoCannonProjectileType type = entry.getValue();
|
||||
for (IRegistryDelegate<Item> delegate : type.getItems()) {
|
||||
ITEM_TO_TYPE_MAP.put(delegate, type);
|
||||
}
|
||||
}
|
||||
for (Map.Entry<ResourceLocation, PotatoCannonProjectileType> entry : CUSTOM_TYPE_MAP.entrySet()) {
|
||||
PotatoCannonProjectileType type = entry.getValue();
|
||||
for (IRegistryDelegate<Item> delegate : type.getItems()) {
|
||||
ITEM_TO_TYPE_MAP.put(delegate, type);
|
||||
}
|
||||
}
|
||||
ITEM_TO_TYPE_MAP.remove(AllItems.POTATO_CANNON.get().delegate);
|
||||
}
|
||||
|
||||
public static void toBuffer(PacketBuffer buffer) {
|
||||
buffer.writeVarInt(CUSTOM_TYPE_MAP.size());
|
||||
for (Map.Entry<ResourceLocation, PotatoCannonProjectileType> entry : CUSTOM_TYPE_MAP.entrySet()) {
|
||||
buffer.writeResourceLocation(entry.getKey());
|
||||
PotatoCannonProjectileType.toBuffer(entry.getValue(), buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public static void fromBuffer(PacketBuffer buffer) {
|
||||
clear();
|
||||
|
||||
int size = buffer.readVarInt();
|
||||
for (int i = 0; i < size; i++) {
|
||||
CUSTOM_TYPE_MAP.put(buffer.readResourceLocation(), PotatoCannonProjectileType.fromBuffer(buffer));
|
||||
}
|
||||
|
||||
fillItemMap();
|
||||
}
|
||||
|
||||
public static void syncTo(ServerPlayerEntity player) {
|
||||
AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> player), new SyncPacket());
|
||||
}
|
||||
|
||||
public static void syncToAll() {
|
||||
AllPackets.channel.send(PacketDistributor.ALL.noArg(), new SyncPacket());
|
||||
}
|
||||
|
||||
public static class ReloadListener extends JsonReloadListener {
|
||||
|
||||
private static final Gson GSON = new Gson();
|
||||
|
||||
public static final ReloadListener INSTANCE = new ReloadListener();
|
||||
|
||||
protected ReloadListener() {
|
||||
super(GSON, "potato_cannon_projectile_types");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void apply(Map<ResourceLocation, JsonElement> map, IResourceManager resourceManager, IProfiler profiler) {
|
||||
clear();
|
||||
|
||||
for (Map.Entry<ResourceLocation, JsonElement> entry : map.entrySet()) {
|
||||
JsonElement element = entry.getValue();
|
||||
if (element.isJsonObject()) {
|
||||
ResourceLocation id = entry.getKey();
|
||||
JsonObject object = element.getAsJsonObject();
|
||||
PotatoCannonProjectileType type = PotatoCannonProjectileType.fromJson(object);
|
||||
CUSTOM_TYPE_MAP.put(id, type);
|
||||
}
|
||||
}
|
||||
|
||||
fillItemMap();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class SyncPacket extends SimplePacketBase {
|
||||
|
||||
private PacketBuffer buffer;
|
||||
|
||||
public SyncPacket() {
|
||||
}
|
||||
|
||||
public SyncPacket(PacketBuffer buffer) {
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(PacketBuffer buffer) {
|
||||
toBuffer(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Supplier<Context> context) {
|
||||
context.get().enqueueWork(() -> {
|
||||
fromBuffer(buffer);
|
||||
});
|
||||
context.get().setPacketHandled(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -8,6 +8,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.tra
|
|||
import com.simibubi.create.content.contraptions.fluids.recipe.FluidTransferRecipes;
|
||||
import com.simibubi.create.content.contraptions.fluids.recipe.PotionMixingRecipeManager;
|
||||
import com.simibubi.create.content.contraptions.wrench.WrenchItem;
|
||||
import com.simibubi.create.content.curiosities.weapons.PotatoProjectileTypeManager;
|
||||
import com.simibubi.create.content.curiosities.zapper.ZapperInteractionHandler;
|
||||
import com.simibubi.create.content.curiosities.zapper.ZapperItem;
|
||||
import com.simibubi.create.content.logistics.item.LinkedControllerServerHandler;
|
||||
|
@ -42,7 +43,6 @@ import net.minecraftforge.event.entity.player.PlayerEvent;
|
|||
import net.minecraftforge.event.world.BlockEvent.FluidPlaceBlockEvent;
|
||||
import net.minecraftforge.event.world.ChunkEvent;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
import net.minecraftforge.eventbus.api.EventPriority;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
import net.minecraftforge.fml.event.server.FMLServerStoppingEvent;
|
||||
|
@ -118,7 +118,7 @@ public class CommonEvents {
|
|||
WrenchItem.wrenchInstaKillsMinecarts(event);
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.NORMAL)
|
||||
@SubscribeEvent
|
||||
public static void registerCommands(RegisterCommandsEvent event) {
|
||||
AllCommands.register(event.getDispatcher());
|
||||
}
|
||||
|
@ -128,6 +128,7 @@ public class CommonEvents {
|
|||
event.addListener(RecipeFinder.LISTENER);
|
||||
event.addListener(PotionMixingRecipeManager.LISTENER);
|
||||
event.addListener(FluidTransferRecipes.LISTENER);
|
||||
event.addListener(PotatoProjectileTypeManager.ReloadListener.INSTANCE);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package com.simibubi.create.foundation.mixin;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.simibubi.create.content.curiosities.weapons.PotatoProjectileTypeManager;
|
||||
|
||||
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||
import net.minecraft.network.NetworkManager;
|
||||
import net.minecraft.server.management.PlayerList;
|
||||
|
||||
@Mixin(PlayerList.class)
|
||||
public class PlayerListMixin {
|
||||
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/item/crafting/ServerRecipeBook;sendInitialRecipeBook(Lnet/minecraft/entity/player/ServerPlayerEntity;)V", shift = At.Shift.AFTER), method = "placeNewPlayer(Lnet/minecraft/network/NetworkManager;Lnet/minecraft/entity/player/ServerPlayerEntity;)V")
|
||||
private void afterSendRecipeBookOnPlaceNewPlayer(NetworkManager networkManager, ServerPlayerEntity player, CallbackInfo ci) {
|
||||
PotatoProjectileTypeManager.syncTo(player);
|
||||
}
|
||||
|
||||
@Inject(at = @At("TAIL"), method = "reloadResources()V")
|
||||
private void onReloadResources(CallbackInfo ci) {
|
||||
PotatoProjectileTypeManager.syncToAll();
|
||||
}
|
||||
}
|
|
@ -25,6 +25,7 @@ import com.simibubi.create.content.curiosities.bell.SoulPulseEffectPacket;
|
|||
import com.simibubi.create.content.curiosities.symmetry.SymmetryEffectPacket;
|
||||
import com.simibubi.create.content.curiosities.tools.BlueprintAssignCompleteRecipePacket;
|
||||
import com.simibubi.create.content.curiosities.tools.ExtendoGripInteractionPacket;
|
||||
import com.simibubi.create.content.curiosities.weapons.PotatoProjectileTypeManager;
|
||||
import com.simibubi.create.content.curiosities.weapons.PotatoCannonPacket;
|
||||
import com.simibubi.create.content.curiosities.zapper.ZapperBeamPacket;
|
||||
import com.simibubi.create.content.logistics.block.depot.EjectorElytraPacket;
|
||||
|
@ -117,6 +118,7 @@ public enum AllPackets {
|
|||
POTATO_CANNON(PotatoCannonPacket.class, PotatoCannonPacket::new, PLAY_TO_CLIENT),
|
||||
SOUL_PULSE(SoulPulseEffectPacket.class, SoulPulseEffectPacket::new, PLAY_TO_CLIENT),
|
||||
PERSISTENT_DATA(ISyncPersistentData.Packet.class, ISyncPersistentData.Packet::new, PLAY_TO_CLIENT),
|
||||
SYNC_POTATO_PROJECTILE_TYPES(PotatoProjectileTypeManager.SyncPacket.class, PotatoProjectileTypeManager.SyncPacket::new, PLAY_TO_CLIENT),
|
||||
|
||||
;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
"compatibilityLevel": "JAVA_8",
|
||||
"refmap": "create.refmap.json",
|
||||
"mixins": [
|
||||
"PlayerListMixin"
|
||||
],
|
||||
"client": [
|
||||
"BreakProgressMixin",
|
||||
|
|
Loading…
Reference in a new issue