Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
kvnmtz committed Jan 12, 2025
2 parents 63823c0 + 3b7f5a3 commit 50d9828
Show file tree
Hide file tree
Showing 16 changed files with 458 additions and 11 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/pipeline.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ jobs:

- name: Build & Release
env:
GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # default token, will not trigger release events, use semantic-release plugins on 'success' instead
MODRINTH_PAT: ${{ secrets.MODRINTH_PAT }}
CURSEFORGE_PAT: ${{ secrets.CURSEFORGE_PAT }}
run: |
chmod +x ./build.sh
chmod +x ./gradlew
Expand Down
62 changes: 62 additions & 0 deletions create_version_curseforge.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// This is probably the worst API I ever had to interact with.

const axios = require('axios').default;
const FormData = require('form-data');
const fs = require("node:fs");

function escapeControlCharacters(str) {
return str.replace(/[\0-\x1F\x7F]/g, (char) => {
switch (char) {
case '\n':
return '\\n';
case '\r':
return '\\r';
case '\t':
return '\\t';
case '\b':
return '\\b';
case '\f':
return '\\f';
case '\v':
return '\\v';
case '\0':
return '\\0';
default:
return '\\x' + char.charCodeAt(0).toString(16).padStart(2, '0');
}
});
}

module.exports = {
verifyConditions: async (pluginConfig, context) => {
const {env} = context;
if (!env.CURSEFORGE_PAT.length) {
throw AggregateError('No Curseforge personal access token provided');
}
},
success: async (pluginConfig, context) => {
const {nextRelease} = context;
const version = nextRelease.version;
const changelog = escapeControlCharacters(nextRelease.notes);

const {env} = context;
const curseforgeToken = env.CURSEFORGE_PAT;

const formData = new FormData();
formData.append('metadata', `{
"changelog": "${changelog}",
"changelogType": "markdown",
"displayName": "Create: Mob Spawners ${version}",
"gameVersions": [9990, 10150, 7498],
"releaseType": "release"
}`);
formData.append('file', fs.createReadStream(`./build/reobfJar/create-mob-spawners-1.20.1-${version}.jar`));

let headers = formData.getHeaders();
headers['X-Api-Token'] = curseforgeToken;

await axios.post('https://minecraft.curseforge.com/api/projects/1175578/upload-file', formData, {
headers: headers,
});
}
}
4 changes: 1 addition & 3 deletions create_version_modrinth.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,8 @@ module.exports = {
let headers = formData.getHeaders();
headers.authorization = modrinthToken;

axios.post('https://api.modrinth.com/v2/version', formData, {
await axios.post('https://api.modrinth.com/v2/version', formData, {
headers: headers,
}).then(result => {
console.log(result.data);
});
}
}
1 change: 1 addition & 0 deletions release.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ module.exports = {
},
],
'./create_version_modrinth.js',
'./create_version_curseforge.js',
],
};
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import dev.kvnmtz.createmobspawners.items.registry.ModItems;
import dev.kvnmtz.createmobspawners.items.SoulCatcherItem;
import dev.kvnmtz.createmobspawners.network.PacketHandler;
import dev.kvnmtz.createmobspawners.ponder.PonderIndex;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
Expand Down Expand Up @@ -89,6 +90,7 @@ public static class ClientModEvents
public static void onClientSetup(FMLClientSetupEvent event)
{
BlockEntityRenderers.register(ModBlockEntities.SPAWNER_BE.get(), MechanicalSpawnerBlockEntityRenderer::new);
PonderIndex.register();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import dev.kvnmtz.createmobspawners.network.PacketHandler;
import dev.kvnmtz.createmobspawners.utils.DropUtils;
import dev.kvnmtz.createmobspawners.utils.ParticleUtils;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleTypes;
Expand Down Expand Up @@ -339,11 +338,13 @@ public void tick() {

if (level.isClientSide) {
if (level.random.nextInt(6) == 0) {
ParticleUtils.drawParticles(ParticleTypes.ENTITY_EFFECT, (ClientLevel) level, getBlockPos().getCenter(), 3, 0.2, 0.2, 0.2, new Vec3(205 / 255.0, 92 / 255.0, 171 / 255.0));
ParticleUtils.drawParticles(ParticleTypes.ENTITY_EFFECT, level, getBlockPos().getCenter(), 3, 0.2, 0.2, 0.2, new Vec3(205 / 255.0, 92 / 255.0, 171 / 255.0));
}
return;
}

if (isVirtual()) return;

if (delayTicks != -1) {
delayTicks--;
if (delayTicks == 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.AABB;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.event.RenderLivingEvent;
Expand All @@ -39,6 +40,7 @@
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.extensions.IForgeItem;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.entity.EntityLeaveLevelEvent;
import net.minecraftforge.event.entity.player.ItemTooltipEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
Expand Down Expand Up @@ -74,8 +76,10 @@ public ShrinkingEntityData(Player player, ItemStack itemStack, boolean hadAi) {
}
}

/// use on server
private static final HashMap<LivingEntity, ShrinkingEntityData> shrinkingEntities = new HashMap<>();

/// use on client
private static final HashMap<Entity, Long> shrinkingEntitiesToStartTimeMap = new HashMap<>();

public static void addShrinkingEntity(Entity entity) {
Expand Down Expand Up @@ -209,6 +213,13 @@ protected static void onRightClickEntity(PlayerInteractEvent.EntityInteract even
startCatchingEntity(target, player, itemStack);
}

@OnlyIn(Dist.CLIENT)
@SubscribeEvent
protected static void onEntityRemoved(EntityLeaveLevelEvent event) {
var entity = event.getEntity();
shrinkingEntitiesToStartTimeMap.remove(entity);
}

private static void cancelCatch(LivingEntity entity) {
var data = shrinkingEntities.get(entity);
if (data.hadAi && entity instanceof Mob mob) {
Expand All @@ -225,6 +236,11 @@ private static float getCatchingDuration(Entity entity) {
return (float) (1.3811 * Math.pow(volume, 0.5026));
}

public static int getCatchingDurationInTicks(AABB boundingBox) {
var volume = BoundingBoxUtils.getBoundingBoxVolume(boundingBox);
return Math.round((float) (1.3811 * Math.pow(volume, 0.5026)) * 20);
}

private static void onShrinkComplete(LivingEntity entity) {
var data = shrinkingEntities.get(entity);
if (data == null) return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ public void handle(Supplier<NetworkEvent.Context> ctx) {
ParticleUtils.drawParticleLine(ParticleTypes.WITCH, level, entityBoundingBox.getCenter(), pointInFrontOfPlayer, 0.5, Vec3.ZERO);
break;
case FINISHED:
SoulCatcherItem.removeShrinkingEntity(entity);
ParticleUtils.drawParticles(ParticleTypes.REVERSE_PORTAL, level, entityCenter, ParticleUtils.getParticleCountForEntity(entity), entityBoundingBox.getXsize() / 3, entityBoundingBox.getYsize() / 3, entityBoundingBox.getZsize() / 3, Vec3.ZERO);
break;
}
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/dev/kvnmtz/createmobspawners/ponder/PonderIndex.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package dev.kvnmtz.createmobspawners.ponder;

import com.simibubi.create.foundation.ponder.PonderRegistrationHelper;
import dev.kvnmtz.createmobspawners.CreateMobSpawners;
import dev.kvnmtz.createmobspawners.blocks.registry.ModBlocks;
import dev.kvnmtz.createmobspawners.items.registry.ModItems;
import dev.kvnmtz.createmobspawners.ponder.scenes.SoulCatcherScenes;
import dev.kvnmtz.createmobspawners.ponder.scenes.SpawnerScenes;

public class PonderIndex {
private static final PonderRegistrationHelper HELPER = new PonderRegistrationHelper(CreateMobSpawners.MOD_ID);

public static void register() {
HELPER.addStoryBoard(ModBlocks.SPAWNER.getId(), "spawner", SpawnerScenes::spawner);
HELPER.addStoryBoard(ModItems.EMPTY_SOUL_CATCHER.getId(), "soul_catcher", SoulCatcherScenes::soulCatcher);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
package dev.kvnmtz.createmobspawners.ponder.scenes;

import com.simibubi.create.foundation.ponder.PonderWorld;
import com.simibubi.create.foundation.ponder.SceneBuilder;
import com.simibubi.create.foundation.ponder.SceneBuildingUtil;
import com.simibubi.create.foundation.ponder.element.InputWindowElement;
import com.simibubi.create.foundation.utility.Pointing;
import dev.kvnmtz.createmobspawners.items.SoulCatcherItem;
import dev.kvnmtz.createmobspawners.items.registry.ModItems;
import dev.kvnmtz.createmobspawners.utils.ParticleUtils;
import net.minecraft.client.Minecraft;
import net.minecraft.core.particles.ItemParticleOption;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.animal.Pig;
import net.minecraft.world.entity.projectile.ThrownPotion;
import net.minecraft.world.item.*;
import net.minecraft.world.item.alchemy.PotionUtils;
import net.minecraft.world.item.alchemy.Potions;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.registries.ForgeRegistries;

import java.util.concurrent.atomic.AtomicReference;

public abstract class SoulCatcherScenes {
public static void soulCatcher(SceneBuilder scene, SceneBuildingUtil util) {
scene.title("soul_catcher", "Soul Catcher");
scene.showBasePlate();

scene.idle(5);

var pigPosition = new Vec3(2.5, 1, 2.5);
var pigCenter = pigPosition.add(0, 0.45f, 0);
var pigReference = new AtomicReference<Pig>();
var pigEntity = scene.world.createEntity(w -> {
var pig = EntityType.PIG.create(w);
if (pig == null) return null;

pig.setPosRaw(pig.xo = pigPosition.x, pig.yo = pigPosition.y, pig.zo = pigPosition.z);
pig.setYRot(pig.yRotO = 180);
pig.setYHeadRot(pig.yHeadRotO = 180);

pigReference.set(pig);

return pig;
});

scene.overlay.showText(60).placeNearTarget().pointAt(pigCenter).text("See this innocent pig? Let's catch it.");

scene.idleSeconds(3);

scene.overlay.showText(80).attachKeyFrame().placeNearTarget().pointAt(pigCenter).text("In order to catch a mob's soul, it needs to be weakened (e.g. with a Splash Potion of Healing)");

scene.idleSeconds(4);

var potionColor = new AtomicReference<>(0);
var potionEntity = scene.world.createEntity(w -> {
var potion = EntityType.POTION.create(w);
if (potion == null) return null;

var potionItem = ForgeRegistries.ITEMS.getValue(new ResourceLocation("minecraft:splash_potion"));
if (potionItem == null) return null;

var potionItemStack = potionItem.getDefaultInstance();
PotionUtils.setPotion(potionItemStack, Potions.WEAKNESS);
potion.setItem(potionItemStack);

potionColor.set(PotionUtils.getColor(potionItemStack));

var potionPosition = pigPosition.add(0, 2, 0);
potion.setPosRaw(potion.xo = potionPosition.x, potion.yo = potionPosition.y, potion.zo = potionPosition.z);

potion.shoot(0, 1.f, 0, 0.25f, 0f);

return potion;
});

scene.idle(14);

scene.world.modifyEntity(potionEntity, e -> {
var potion = (ThrownPotion) e;

var itemStack = potion.getItem();

var color = PotionUtils.getColor(itemStack);
var random = potion.level().random;

var splashOrigin = potion.position();

for (int i = 0; i < 8; ++i) {
potion.level().addParticle(new ItemParticleOption(ParticleTypes.ITEM, new ItemStack(Items.SPLASH_POTION)), splashOrigin.x, splashOrigin.y, splashOrigin.z, random.nextGaussian() * 0.15, random.nextDouble() * 0.2, random.nextGaussian() * 0.15);
}

var red = (float) (color >> 16 & 255) / 255.0F;
var blue = (float) (color >> 8 & 255) / 255.0F;
var green = (float) (color & 255) / 255.0F;

for (int i = 0; i < 100; ++i) {
var d13 = random.nextDouble() * (double) 1.5F;
var d19 = random.nextDouble() * Math.PI * (double) 2.0F;
var d25 = Math.cos(d19) * d13;
var d30 = 0.01 + random.nextDouble() * (double) 0.5F;
var d31 = Math.sin(d19) * d13;

var particle = Minecraft.getInstance().particleEngine.createParticle(ParticleTypes.EFFECT, splashOrigin.x + d25 * 0.1, splashOrigin.y + 0.3, splashOrigin.z + d31 * 0.1, d25, d30, d31);
if (particle != null) {
var randomShift = 0.75F + random.nextFloat() * 0.25F;
particle.setColor(red * randomShift, blue * randomShift, green * randomShift);
particle.setPower((float) d13);
}

((PonderWorld) potion.level()).addParticle(particle);
}

potion.discard();
});

scene.effects.emitParticles(Vec3.ZERO, (level, unused1, unused2, unused3) -> {
var pig = pigReference.get();
int i = potionColor.get();
double d0 = (double)(i >> 16 & 255) / (double)255.0F;
double d1 = (double)(i >> 8 & 255) / (double)255.0F;
double d2 = (double)(i & 255) / (double)255.0F;
level.addParticle(ParticleTypes.ENTITY_EFFECT, pig.getRandomX(0.5F), pig.getRandomY(), pig.getRandomZ(0.5F), d0, d1, d2);
}, 1, 80);

scene.idleSeconds(3);

scene.overlay.showText(40).attachKeyFrame().placeNearTarget().pointAt(pigCenter).text("Now, right-click it with an empty Soul Catcher to start catching its soul");

scene.idleSeconds(2);

scene.overlay.showControls((new InputWindowElement(pigCenter.add(0, 0.5f, 0), Pointing.DOWN)).rightClick().withItem(ModItems.EMPTY_SOUL_CATCHER.get().getDefaultInstance()), 40);

scene.idle(7);

scene.world.modifyEntity(pigEntity, pig -> {
var bb = pigReference.get().getBoundingBox();
SoulCatcherItem.addShrinkingEntity(pig);
ParticleUtils.drawParticles(ParticleTypes.WITCH, pig.level(), pigCenter, ParticleUtils.getParticleCountForEntity(pig), bb.getXsize() / 3, bb.getYsize() / 3, bb.getZsize() / 3, Vec3.ZERO);
});

scene.idle(SoulCatcherItem.getCatchingDurationInTicks(AABB.ofSize(Vec3.ZERO, 0.9f, 0.9f, 0.9f)));

scene.world.modifyEntity(pigEntity, pig -> {
var bb = pigReference.get().getBoundingBox();
ParticleUtils.drawParticles(ParticleTypes.REVERSE_PORTAL, pig.level(), pigCenter, ParticleUtils.getParticleCountForEntity(pig), bb.getXsize() / 3, bb.getYsize() / 3, bb.getZsize() / 3, Vec3.ZERO);
pig.discard();
});

scene.idleSeconds(1);

scene.overlay.showText(40).independent(0).placeNearTarget().text("Gotcha! The pig was caught.");
scene.idle(10);
scene.overlay.showText(60).attachKeyFrame().independent(24).placeNearTarget().text("If you want to release it again, just right-click the desired position with the Soul Catcher");

scene.idleSeconds(3);

scene.overlay.showControls((new InputWindowElement(pigPosition, Pointing.DOWN)).rightClick().withItem(ModItems.SOUL_CATCHER.get().getDefaultInstance()), 20);

scene.idle(30);

scene.world.createEntity(w -> {
var pig = EntityType.PIG.create(w);
if (pig == null) return null;

pig.setPosRaw(pig.xo = pigPosition.x, pig.yo = pigPosition.y, pig.zo = pigPosition.z);
pig.setYRot(pig.yRotO = 180);
pig.setYHeadRot(pig.yHeadRotO = 180);

var bb = pig.getBoundingBox();

ParticleUtils.drawParticles(ParticleTypes.WITCH, w, pigCenter, ParticleUtils.getParticleCountForEntity(pig), bb.getXsize() / 3, bb.getYsize() / 3, bb.getZsize() / 3, Vec3.ZERO);

return pig;
});

scene.idleSeconds(2);
scene.markAsFinished();
}
}
Loading

0 comments on commit 50d9828

Please sign in to comment.