惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Project Zero
Project Zero
Security Archives - TechRepublic
Security Archives - TechRepublic
C
Cyber Attacks, Cyber Crime and Cyber Security
Security Latest
Security Latest
Scott Helme
Scott Helme
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
V
Vulnerabilities – Threatpost
C
CERT Recently Published Vulnerability Notes
S
Schneier on Security
G
GRAHAM CLULEY
L
Lohrmann on Cybersecurity
D
Darknet – Hacking Tools, Hacker News & Cyber Security
I
Intezer
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
F
Full Disclosure
T
The Exploit Database - CXSecurity.com
P
Proofpoint News Feed
WordPress大学
WordPress大学
Microsoft Azure Blog
Microsoft Azure Blog
H
Help Net Security
大猫的无限游戏
大猫的无限游戏
MyScale Blog
MyScale Blog
Hacker News: Ask HN
Hacker News: Ask HN
G
Google Developers Blog
H
Heimdal Security Blog
O
OpenAI News
Hugging Face - Blog
Hugging Face - Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
L
LangChain Blog
C
Cisco Blogs
云风的 BLOG
云风的 BLOG
IT之家
IT之家
Cyberwarzone
Cyberwarzone
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Know Your Adversary
Know Your Adversary
博客园 - 聂微东
The Cloudflare Blog
C
Check Point Blog
K
Kaspersky official blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
月光博客
月光博客
T
Tor Project blog
T
Threat Research - Cisco Blogs
T
Tailwind CSS Blog
P
Proofpoint News Feed
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
A
About on SuperTechFans
小众软件
小众软件
Cloudbric
Cloudbric
A
Arctic Wolf

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
I Built a Minecraft Mod Where Every Sword is an AWS Service — Here's How We Coded It with AI
Carlos Corte · 2026-05-05 · via DEV Community

I Built a Minecraft Mod Where Every Sword is an AWS Service — Here's How We Coded It with AI

What happens when a cloud engineer picks up Minecraft modding for the first time? You get swords that invoke Lambda functions, store items in S3 buckets, and auto-scale damage like EC2 instances. Today we're going deep into how I built AWS Swords — a Fabric mod for Minecraft 1.21.1 where every weapon is inspired by a real AWS service, and every ability maps to actual cloud computing concepts.

The concept is straightforward: take the services we use every day in the cloud and turn them into Minecraft weapons with abilities that actually make sense. Lambda is serverless and ephemeral? The sword summons temporary allies that disappear after a few seconds. S3 stores objects? The sword absorbs items from the ground and retrieves them later. EC2 scales? The sword stacks damage the more you hit.

And the best part — I coded this entire mod alongside an AI agent. Every class, every texture animation, every ability was a conversation. Let me show you how.

All four AWS Swords in the inventory — Lambda, Greatsword of Lambda, S3, and EC2, each with unique animated textures

📓 Full source code: The complete mod is available on CurseForge — clone it, build it, swing some cloud-powered swords.

Why AWS Swords?

I've been a modded Minecraft fan for years. Tech mods and RPG packs are my thing — Applied Energistics 2, Tech Reborn, Mekanism, Create, you name it. There's something deeply satisfying about building complex systems inside a game, automating everything, and watching it all come together. If you've ever spent an entire weekend wiring up an ME system or designing a Mekanism ore processing chain, you know exactly what I'm talking about.

So when I started thinking about a side project that combined my two worlds — cloud computing and gaming — the idea hit me: what if there was a tech mod, but for cloud computing? Not pipes and machines, but AWS services as weapons with abilities that mirror what the real services do. And I wanted to go all the way with it — build it for Minecraft 1.21.1, publish it officially on CurseForge, and include it in my current modded Minecraft series.

That's how AWS Swords was born. And what's interesting is how naturally AWS service behaviors map to game mechanics:

  • AWS Lambda → Ephemeral compute → Temporary allies that spawn and despawn
  • Amazon S3 → Object storage → A sword that absorbs and retrieves items
  • Amazon EC2 → Auto Scaling + Spot Instances → Stacking damage + random crits

In practice, this means that every sword teaches you something about the service it represents, just by playing with it.

The Architecture

Here's the mod structure — and yes, it looks a lot like a microservices architecture:

aws-swords-mod/
├── src/main/java/com/awsswords/
│   ├── AwsSwordsMod.java              # Entrypoint (the main() of mods)
│   ├── client/
│   │   └── AwsSwordsClient.java       # Client-side particles
│   ├── entity/
│   │   └── LambdaMinionManager.java   # Lifecycle manager for Lambda invocations
│   └── item/
│       ├── ModItems.java              # Item registry (like a service catalog)
│       ├── ability/
│       │   └── SwordAbility.java      # Interface — the contract every ability follows
│       └── sword/
│           ├── BaseSword.java         # Abstract base — cooldowns, tooltips, particles
│           ├── LambdaSword.java       # ⚡ Invoke: 1-3 temporary allies
│           ├── GreatswordOfLambda.java # ⚔ Mass Invoke: 3-5 holy allies
│           ├── S3Sword.java           # ☁ PutObject / GetObject item storage
│           └── EC2Sword.java          # ⚡ Auto Scaling + Spot Instance crits
├── src/main/resources/
│   ├── fabric.mod.json
│   └── assets/awsswords/
│       ├── lang/                      # en_us.json + es_es.json
│       ├── models/item/               # JSON models per sword
│       └── textures/item/             # Animated PNGs + .mcmeta
└── build.gradle

Enter fullscreen mode Exit fullscreen mode

The design follows a pattern any cloud architect would recognize: an interface defines the contract (SwordAbility), an abstract base class handles shared behavior (BaseSword), and each implementation is independent (one class per sword). Loose coupling, high cohesion. Just like good microservices.

The Tech Stack

Component Version
Minecraft 1.21.1
Fabric Loader 0.19.2
Fabric API 0.109.0+1.21.1
Fabric Loom 1.9
Java 21
Gradle 8.12

Step 1: The Foundation — SwordAbility Interface

Every sword ability in the mod implements this interface. It's the contract — if you want to be an AWS sword, you need to define what happens on use, how long the cooldown is, and what the tooltip says.

public interface SwordAbility {
    void onUse(PlayerEntity player, World world, ItemStack stack);
    default void onAttack(PlayerEntity player, Entity target, ItemStack stack) {}
    int getCooldownTicks();
    Text getDescription();
}

Enter fullscreen mode Exit fullscreen mode

What caught my attention is how clean this keeps things. Adding a new sword means implementing this interface and wiring it up. No giant switch statements, no spaghetti. The onAttack default method is there for swords like EC2 that need hit-based mechanics instead of right-click abilities.

Step 2: BaseSword — The Shared Infrastructure

The BaseSword abstract class handles everything that's common across swords: Netherite-tier stats, cooldown management, tooltip rendering, and the hook for ambient particles.

public abstract class BaseSword extends SwordItem {
    private final SwordAbility ability;
    private final String lore;

    protected BaseSword(SwordAbility ability, String lore, Item.Settings settings) {
        super(ToolMaterials.NETHERITE, settings.attributeModifiers(
                SwordItem.createAttributeModifiers(ToolMaterials.NETHERITE, 3, -2.4f)));
        this.ability = ability;
        this.lore = lore;
    }

    @Override
    public TypedActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) {
        ItemStack stack = player.getStackInHand(hand);
        if (!world.isClient && !player.getItemCooldownManager().isCoolingDown(this)) {
            ability.onUse(player, world, stack);
            player.getItemCooldownManager().set(this, ability.getCooldownTicks());
            return TypedActionResult.success(stack);
        }
        return TypedActionResult.pass(stack);
    }

    @Override
    public void appendTooltip(ItemStack stack, TooltipContext context, List<Text> tooltip, TooltipType type) {
        tooltip.add(ability.getDescription().copy().formatted(Formatting.GOLD));
        tooltip.add(Text.literal("Cooldown: " + ability.getCooldownTicks() / 20 + "s").formatted(Formatting.GRAY));
        tooltip.add(Text.literal(lore).formatted(Formatting.DARK_PURPLE, Formatting.ITALIC));
    }
}

Enter fullscreen mode Exit fullscreen mode

Think of BaseSword as a base AMI — it has everything pre-configured, and each sword just layers its unique behavior on top. The use() method delegates to the ability, handles cooldowns, and makes sure we only run server-side logic (no duplicate execution on the client).

Step 3: Sword of Lambda — Serverless Allies

This is where it gets fun. AWS Lambda runs code on demand, scales automatically, and the compute is ephemeral — it disappears when the function finishes. So the Sword of Lambda invokes 1-3 baby zombie allies that fight for you and despawn after 5 seconds.

Sword of Lambda tooltip — Invoke ability, 15s cooldown, 8 Attack Damage,

public class LambdaSword extends BaseSword {
    public LambdaSword(Item.Settings settings) {
        super(new InvokeAbility(), "Runs on demand. No servers required.", settings);
    }

    @Override
    protected ParticleEffect getAmbientParticle() {
        return ParticleTypes.ENCHANTED_HIT;
    }

    @Override
    public boolean hasGlint(ItemStack stack) { return true; }

    private static class InvokeAbility implements SwordAbility {
        @Override
        public void onUse(PlayerEntity player, World world, ItemStack stack) {
            if (!(world instanceof ServerWorld server)) return;

            int count = 1 + world.random.nextInt(3);
            world.playSound(null, player.getBlockPos(), SoundEvents.ENTITY_EVOKER_CAST_SPELL,
                    SoundCategory.PLAYERS, 1f, 1.5f);

            for (int i = 0; i < count; i++) {
                ZombieEntity minion = new ZombieEntity(EntityType.ZOMBIE, world);
                double angle = (2 * Math.PI * i) / count;
                double x = player.getX() + Math.cos(angle) * 2;
                double z = player.getZ() + Math.sin(angle) * 2;
                minion.refreshPositionAndAngles(x, player.getY(), z,
                        (float)(angle * 180 / Math.PI), 0);
                minion.setBaby(true);
                minion.setCustomName(Text.literal("λ Invocation").formatted(Formatting.GOLD));
                minion.setCustomNameVisible(true);
                server.spawnEntity(minion);
                server.spawnParticles(ParticleTypes.FLAME,
                        x, player.getY() + 0.5, z, 10, 0.3, 0.5, 0.3, 0.02);
                LambdaMinionManager.track(minion, 100); // 5 seconds
            }

            player.sendMessage(Text.literal(
                    "§6⚡ Lambda Invoke: " + count + " function" +
                    (count > 1 ? "s" : "") + " deployed!"), true);
        }

        @Override
        public int getCooldownTicks() { return 300; } // 15 seconds

        @Override
        public Text getDescription() {
            return Text.literal("⚡ Invoke — Summon 1-3 temporary allies");
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

A few things to note:

  • The minions spawn in a circle around the player using trigonometry — just like Lambda functions spinning up across availability zones
  • Each minion gets a custom name tag: λ Invocation in gold text
  • The LambdaMinionManager.track(minion, 100) call registers the entity for automatic cleanup after 100 ticks (5 seconds)
  • The evoker cast spell sound gives it that magical "deploying to the cloud" feel

The LambdaMinionManager — Lifecycle Management

This is the garbage collector for our serverless functions. It uses Fabric's ServerTickEvents to count down each minion's remaining ticks and despawn them with a puff of smoke:

public class LambdaMinionManager {
    private static final List<TrackedMinion> minions = new ArrayList<>();

    public static void register() {
        ServerTickEvents.END_SERVER_TICK.register(server -> {
            Iterator<TrackedMinion> it = minions.iterator();
            while (it.hasNext()) {
                TrackedMinion tracked = it.next();
                tracked.ticksLeft--;
                if (tracked.ticksLeft <= 0 || !tracked.entity.isAlive()) {
                    if (tracked.entity.isAlive()) {
                        if (tracked.entity.getWorld() instanceof ServerWorld sw) {
                            sw.spawnParticles(ParticleTypes.SMOKE,
                                    tracked.entity.getX(), tracked.entity.getY() + 0.5,
                                    tracked.entity.getZ(), 15, 0.3, 0.5, 0.3, 0.05);
                        }
                        tracked.entity.discard();
                    }
                    it.remove();
                }
            }
        });
    }

    public static void track(ZombieEntity entity, int ticks) {
        minions.add(new TrackedMinion(entity, ticks));
    }
}

Enter fullscreen mode Exit fullscreen mode

Think of it as CloudWatch monitoring your Lambda executions — when the timeout hits, the function gets terminated. Clean, predictable lifecycle management.

Step 4: Greatsword of Lambda — Mass Invoke

Same concept, bigger scale. The Greatsword is the two-handed variant — slower attack speed (0.8 vs 1.6), higher damage (+15 vs +11), and it summons 3-5 allies that last 8 seconds instead of 5. It's like going from a single Lambda invocation to a fan-out pattern.

Greatsword of Lambda tooltip — Two-Handed Greatsword, Mass Invoke 3-5 holy allies, 20s cooldown, 13 Attack Damage,

// attackDamage +7 (vs +3 normal), attackSpeed -3.2 (very slow, greatsword feel)
super(ToolMaterials.NETHERITE, settings.attributeModifiers(
        SwordItem.createAttributeModifiers(ToolMaterials.NETHERITE, 7, -3.2f)));

Enter fullscreen mode Exit fullscreen mode

The minions get purple soul fire particles instead of regular flames, and their name tags read λ Holy Invocation — because when you're invoking 5 functions at once, it's practically a religious experience.

Step 5: Sword of S3 — Object Storage in Your Inventory

This one is my favorite. Amazon S3 stores and retrieves objects. So the Sword of S3 does exactly that:

  • Right-clickPutObject: absorbs the nearest item from the ground (4-block radius) into a virtual bucket
  • Shift + Right-clickGetObject: retrieves the last stored item back to your inventory
  • Max capacity: 5 objects (it's a bucket, not a data lake)
  • Persistence: Items are stored in the sword's NBT data — they survive death

Sword of S3 tooltip — PutObject and GetObject abilities, Bucket 4/5 objects stored,

private TypedActionResult<ItemStack> putObject(ServerWorld world, PlayerEntity player, ItemStack sword) {
    NbtList bucket = getBucket(sword);
    if (bucket.size() >= MAX_OBJECTS) {
        player.sendMessage(Text.literal("§c✗ Bucket full! (5/5 objects)"), true);
        return TypedActionResult.fail(sword);
    }

    List<ItemEntity> items = world.getEntitiesByClass(ItemEntity.class,
            new Box(player.getBlockPos()).expand(4), e -> !e.isRemoved());

    if (items.isEmpty()) {
        player.sendMessage(Text.literal("§7No items nearby to upload"), true);
        return TypedActionResult.fail(sword);
    }

    // Find nearest item
    ItemEntity nearest = items.get(0);
    double minDist = player.squaredDistanceTo(nearest);
    for (ItemEntity ie : items) {
        double d = player.squaredDistanceTo(ie);
        if (d < minDist) { minDist = d; nearest = ie; }
    }

    // Store item as NBT
    ItemStack picked = nearest.getStack().copy();
    NbtCompound itemNbt = new NbtCompound();
    itemNbt.put("item", picked.encodeAllowEmpty(world.getRegistryManager()));
    bucket.add(itemNbt);
    setBucket(sword, bucket);

    nearest.discard();
    world.playSound(null, player.getBlockPos(), SoundEvents.ENTITY_ENDERMAN_TELEPORT,
            SoundCategory.PLAYERS, 0.7f, 1.5f);
    world.spawnParticles(ParticleTypes.PORTAL,
            nearest.getX(), nearest.getY() + 0.5, nearest.getZ(), 20, 0.3, 0.3, 0.3, 0.5);

    player.sendMessage(Text.literal("§b☁ PutObject: " + picked.getName().getString() +
            " uploaded (" + bucket.size() + "/" + MAX_OBJECTS + ")"), true);
    return TypedActionResult.success(sword);
}

Enter fullscreen mode Exit fullscreen mode

The cool part here is the NBT storage pattern. In Minecraft 1.21.1, items use the new DataComponentTypes.CUSTOM_DATA system instead of the old direct NBT access. The sword stores a NbtList called s3bucket inside its custom data component — each entry is a serialized ItemStack. It's literally key-value storage, just like S3.

The visual feedback sells it: Portal particles on upload (your item is going to the cloud), Reverse Portal particles on download (it's coming back), and the Enderman teleport sound for both operations. Because if S3 had a sound, it would be a teleport.

The lore text? "11 nines of durability." — because S3 offers 99.999999999% durability, and that joke was too good to pass up.

Step 6: Sword of EC2 — Auto Scaling Damage

EC2 is all about compute that scales. The Sword of EC2 has two mechanics:

Auto Scaling (Active): Consecutive hits within 4 seconds stack damage — +10% per hit, up to +50% at 5 stacks. Stop hitting for 4 seconds and it resets. Just like an Auto Scaling group ramping up instances under load.

Spot Instance (Passive): 20% chance on every hit to land a critical strike with electric spark particles and a lightning sound. Because Spot Instances give you extra compute at a discount, but they can be interrupted at any time — you never know when you'll get one.

Sword of EC2 tooltip — Auto Scaling consecutive hits +10% damage, Spot Instance 20% critical strike chance,

@Override
public boolean postHit(ItemStack stack, LivingEntity target, LivingEntity attacker) {
    if (!(attacker instanceof PlayerEntity player) || attacker.getWorld().isClient) {
        return super.postHit(stack, target, attacker);
    }

    ServerWorld world = (ServerWorld) attacker.getWorld();
    long now = world.getTime();
    UUID id = player.getUuid();

    // Auto Scaling: increment stacks
    StackData data = playerStacks.computeIfAbsent(id, k -> new StackData());
    if (now - data.lastHitTick > STACK_TIMEOUT_TICKS) {
        data.stacks = 0; // reset — scale-in after idle
    }
    data.lastHitTick = now;
    if (data.stacks < MAX_STACKS) data.stacks++;

    float bonus = data.stacks * 0.10f;
    float bonusDamage = target.getMaxHealth() > 0 ? stack.getDamage() * bonus : 0;
    if (bonusDamage > 0) {
        target.damage(world.getDamageSources().playerAttack(player), bonusDamage);
    }

    // Spot Instance: 20% crit chance
    boolean spotCrit = world.random.nextFloat() < 0.20f;
    if (spotCrit) {
        target.damage(world.getDamageSources().playerAttack(player), 4.0f);
        world.spawnParticles(ParticleTypes.ELECTRIC_SPARK,
                target.getX(), target.getY() + 1, target.getZ(), 20, 0.5, 0.8, 0.5, 0.1);
        world.playSound(null, target.getBlockPos(), SoundEvents.ENTITY_LIGHTNING_BOLT_IMPACT,
                SoundCategory.PLAYERS, 0.4f, 1.8f);
    }

    // More particles at higher stacks — visual scaling
    world.spawnParticles(ParticleTypes.SOUL_FIRE_FLAME,
            target.getX(), target.getY() + 1, target.getZ(),
            2 + data.stacks * 3, 0.3, 0.5, 0.3, 0.02);

    int pct = (int)(bonus * 100);
    String msg = "§b⚡ Auto Scaling: " + data.stacks + "/" + MAX_STACKS + " (+" + pct + "%)";
    if (spotCrit) msg += " §e⚡ SPOT CRIT!";
    player.sendMessage(Text.literal(msg), true);

    return super.postHit(stack, target, attacker);
}

Enter fullscreen mode Exit fullscreen mode

Notice how the particle count scales with the stack count (2 + data.stacks * 3). At max stacks you get 17 soul fire particles per hit — the visual feedback tells you exactly how scaled up you are. The EC2 sword uses postHit instead of onUse because its mechanics are attack-based, not right-click-based. Different interaction model, same interface contract.

Step 7: Animated Textures and Visual Polish

Every sword has an 8-frame animated texture with interpolation. In Minecraft, you achieve this with a sprite sheet PNG (16x128 for 8 frames of 16x16) and a .mcmeta file:

{
  "animation": {
    "frametime": 3,
    "interpolate": true
  }
}

Enter fullscreen mode Exit fullscreen mode

The frametime: 3 means each frame lasts 3 ticks (0.15 seconds), and interpolate: true smoothly blends between frames. Combined with hasGlint() → true on every sword, you get that enchanted shimmer on top of the animation.

The color palettes map to the services:

  • Lambda: Orange/purple with fire and gems
  • Greatsword of Lambda: Purple/pink holy warrior energy
  • S3: Green/teal with teal gems and green aura
  • EC2: Blue/orange katana-style with electric sparks

Step 8: Client-Side Particles

The AwsSwordsClient class adds ambient particles when you're holding any AWS sword. It runs client-side only (no server overhead) and spawns subtle enchanted hit particles every 6 ticks:

public class AwsSwordsClient implements ClientModInitializer {
    @Override
    public void onInitializeClient() {
        ClientTickEvents.END_CLIENT_TICK.register(client -> {
            ClientPlayerEntity player = client.player;
            if (player == null || !(player.getMainHandStack().getItem() instanceof BaseSword)) return;

            if (player.getWorld().getTime() % 6 == 0) {
                double x = player.getX() + (player.getRandom().nextDouble() - 0.5) * 0.5;
                double y = player.getY() + 0.8 + player.getRandom().nextDouble() * 0.5;
                double z = player.getZ() + (player.getRandom().nextDouble() - 0.5) * 0.5;
                player.getWorld().addParticle(ParticleTypes.ENCHANTED_HIT, x, y, z, 0, 0.02, 0);
            }
        });
    }
}

Enter fullscreen mode Exit fullscreen mode

It's a small detail, but it makes the swords feel alive. You know you're holding something special.

Step 9: Registration and Localization

The ModItems class registers all swords with Fabric's registry and adds them to the Combat creative tab:

public class ModItems {
    public static final Item SWORD_OF_LAMBDA = register("sword_of_lambda",
            new LambdaSword(new Item.Settings()));
    public static final Item GREATSWORD_OF_LAMBDA = register("greatsword_of_lambda",
            new GreatswordOfLambda(new Item.Settings()));
    public static final Item SWORD_OF_S3 = register("sword_of_s3",
            new S3Sword(new Item.Settings()));
    public static final Item SWORD_OF_EC2 = register("sword_of_ec2",
            new EC2Sword(new Item.Settings()));

    private static Item register(String name, Item item) {
        return Registry.register(Registries.ITEM, Identifier.of(AwsSwordsMod.MOD_ID, name), item);
    }

    public static void register() {
        ItemGroupEvents.modifyEntriesEvent(ItemGroups.COMBAT).register(entries -> {
            entries.add(SWORD_OF_LAMBDA);
            entries.add(GREATSWORD_OF_LAMBDA);
            entries.add(SWORD_OF_S3);
            entries.add(SWORD_OF_EC2);
        });
    }
}

Enter fullscreen mode Exit fullscreen mode

And because this is Breaking the Cloud, we ship with English and Spanish localization:

// en_us.json
{
  "item.awsswords.sword_of_lambda": "Sword of Lambda",
  "item.awsswords.greatsword_of_lambda": "Greatsword of Lambda",
  "item.awsswords.sword_of_s3": "Sword of S3",
  "item.awsswords.sword_of_ec2": "Sword of EC2"
}

// es_es.json
{
  "item.awsswords.sword_of_lambda": "Espada de Lambda",
  "item.awsswords.greatsword_of_lambda": "Gran Espada de Lambda",
  "item.awsswords.sword_of_s3": "Espada de S3",
  "item.awsswords.sword_of_ec2": "Espada de EC2"
}

Enter fullscreen mode Exit fullscreen mode

Building and Running

Two scripts handle everything:

# Build the mod JAR
#!/bin/bash
export JAVA_HOME=/opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home
export PATH="$JAVA_HOME/bin:$PATH"
cd "$(dirname "$0")/aws-swords-mod" && ./gradlew remapJar

# Run Minecraft with the mod loaded
#!/bin/bash
export JAVA_HOME=/opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home
export PATH="$JAVA_HOME/bin:$PATH"
cd "$(dirname "$0")/aws-swords-mod" && ./gradlew runClient

Enter fullscreen mode Exit fullscreen mode

The remapJar task is Fabric-specific — it remaps your compiled classes from development mappings (Yarn) to production mappings (intermediary) so the mod works in a real Minecraft installation. The output lands in build/libs/aws-swords-0.1.0.jar.

Coding with AI — How We Actually Built This

Here's the part that makes this project different. I didn't build this mod alone — I built it in conversation with an AI agent. Every single file in this project was a collaboration.

The workflow looked like this:

  1. I described the vision: "I want a Minecraft mod where swords have AWS service abilities"
  2. We wrote a Statement of Work together: Service-to-ability mappings, damage values, cooldowns, visual effects
  3. We coded iteratively: One sword at a time, testing in-game between each one
  4. The AI handled the boilerplate: Gradle config, Fabric mod JSON, registry patterns, NBT serialization
  5. I made the design decisions: Which services to include, how abilities should feel, what the lore text should say

The thing is, the AI was particularly good at the parts that would have taken me hours to figure out as a first-time Minecraft modder — things like the DataComponentTypes.CUSTOM_DATA pattern for NBT storage in 1.21.1, the ServerTickEvents hook for entity lifecycle management, and the TypedActionResult return types for item interactions.

But the creative decisions — Lambda should summon baby zombies because they're small and ephemeral, S3 should use portal particles because items are going to "the cloud", EC2's lore should be "Choose your instance type wisely" — those were all human.

My advice for anyone trying this: use AI for the mechanics, bring the creativity yourself.

Lessons Learned

Challenge Solution
First time with Fabric modding AI agent handled the boilerplate, I focused on game design
NBT storage in 1.21.1 New DataComponentTypes.CUSTOM_DATA system, not the old direct NBT
Entity lifecycle (Lambda minions) Custom tick-based manager with ServerTickEvents
Client vs Server logic world.isClient checks everywhere — particles client-side, logic server-side
Animated textures 8-frame sprite sheets + .mcmeta with interpolate: true
Greatsword balance Higher damage (+7 vs +3) but much slower speed (-3.2 vs -2.4)
S3 item persistence NBT serialization with encodeAllowEmpty + ItemStack.fromNbt
EC2 stack tracking Per-player HashMap<UUID, StackData> with tick-based timeout

What's Next

The SoW has 3 more swords planned for the MVP:

  • Sword of CloudWatch — "Describe Alarms": reveals all mobs in 30 blocks, showing HP and active effects. Like a scanner. "Observable by default."
  • Sword of IAM — "Deny Policy": applies a debuff that blocks mob special abilities (no teleport for Endermen, no explosion for Creepers). "Explicit deny always wins."
  • Sword of DynamoDB — "Burst Capacity": first 5 hits in 3 seconds deal increasing damage, then you enter "throttle" mode with reduced damage. "Single-digit millisecond latency."

And Phase 2 includes SNS, SQS, Route 53, CloudFront, ECS, EKS, RDS, Kinesis, Step Functions, and Bedrock. Plus a rune and socket system. The roadmap is ambitious, but we're building it one sword at a time.

The Main Takeaway

You don't need to be a Minecraft modding expert to build a mod. You don't need to be a game designer to create fun mechanics. What you need is a clear vision, a good collaborator (AI or human), and the willingness to iterate.

The truth is, this project taught me more about Fabric's internals in a few hours than any tutorial could have. When you're building something you actually want to play, the learning happens naturally.

And if you're a cloud engineer who's ever wondered what your favorite AWS service would look like as a Minecraft weapon — now you know.


Connect with me:

  • LinkedIn - Let's discuss cloud architecture and Minecraft mods
  • X/Twitter - Follow for AWS, GenAI, and now gaming updates
  • GitHub - Check out the full mod source code
  • Dev.to - More technical deep-dives
  • AWS Community - Join the conversation

I'm Carlos Cortez, this is Breaking the Cloud, and today we broke it with diamond swords. See you in the next one!