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:
PepperBell 2021-09-18 17:40:57 -07:00
parent 86b0d80c1b
commit 173eb6b7ab
11 changed files with 517 additions and 218 deletions

View file

@ -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();

View file

@ -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() {}
}

View file

@ -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();
}

View file

@ -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;
}
}
}

View file

@ -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();

View file

@ -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 {

View file

@ -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);
}
}
}

View file

@ -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

View file

@ -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();
}
}

View file

@ -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),
;

View file

@ -5,6 +5,7 @@
"compatibilityLevel": "JAVA_8",
"refmap": "create.refmap.json",
"mixins": [
"PlayerListMixin"
],
"client": [
"BreakProgressMixin",