Try Live
Add Docs
Rankings
Pricing
Enterprise
Docs
Install
Theme
Install
Docs
Pricing
Enterprise
More...
More...
Try Live
Rankings
Create API Key
Add Docs
Timeless and Classics Guns Zero
https://github.com/mcmodderanchor/tacz
Admin
A gun mod for Minecraft Forge 1.20.1 that adds timeless and classic firearms with detailed mechanics
...
Tokens:
12,610
Snippets:
35
Trust Score:
4.8
Update:
5 months ago
Context
Skills
Chat
Benchmark
72.9
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Timeless and Classics Guns Zero (TACZ) Timeless and Classics Guns Zero is a comprehensive firearms modification for Minecraft Forge 1.20.1 that introduces modern kinetic weapon systems into the game. The mod provides a complete firearms framework with realistic ballistics, attachment systems, ammunition management, and extensive customization capabilities through resource packs and scripting. Built on a robust API architecture, TACZ enables both players and developers to create, customize, and integrate sophisticated weapon mechanics into Minecraft. At its core, TACZ implements a modular design separating client-side visual effects from server-side gameplay logic, ensuring synchronized multiplayer experiences. The mod features Lua-scriptable gun behaviors, GLTF-based 3D animations, a comprehensive attachment system with real-time property modifiers, and a resource pack system allowing content creators to add custom weapons without code modifications. With support for over 40 default firearms ranging from pistols to heavy machine guns, integration with popular mods like JEI and KubeJS, and an event-driven architecture for developers, TACZ serves as both a feature-rich gun mod and a flexible platform for firearm-based gameplay. --- ## API Access - TimelessAPI Central API for accessing gun data, attachments, ammunition, and display information across client and server. ```java package com.example.taczintegration; import com.tacz.guns.api.TimelessAPI; import com.tacz.guns.api.item.IGun; import com.tacz.guns.resource.index.CommonGunIndex; import com.tacz.guns.resource.pojo.data.gun.GunData; import com.tacz.guns.client.resource.GunDisplayInstance; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import java.util.Optional; public class GunDataExample { // Server-side: Get gun statistics and properties public void analyzeGunStats(Player player) { ItemStack gunStack = player.getMainHandItem(); if (gunStack.getItem() instanceof IGun iGun) { ResourceLocation gunId = iGun.getGunId(gunStack); // Retrieve common gun data (available on both client and server) Optional<CommonGunIndex> gunIndexOpt = TimelessAPI.getCommonGunIndex(gunId); gunIndexOpt.ifPresent(index -> { GunData data = index.getGunData(); System.out.println("Gun ID: " + gunId); System.out.println("Fire Rate: " + data.getRpm() + " RPM"); System.out.println("Magazine Size: " + data.getAmmoAmount()); System.out.println("Bullet Damage: " + data.getBulletData().getDamage()); System.out.println("Bullet Speed: " + data.getBulletData().getSpeed() + " m/s"); System.out.println("Reload Time (Tactical): " + data.getReloadData().getFeed().getTactical() + " seconds"); System.out.println("Reload Time (Empty): " + data.getReloadData().getFeed().getEmpty() + " seconds"); System.out.println("Weight: " + data.getWeight() + " kg"); // Check fire modes System.out.println("Available Fire Modes: " + data.getFireModeSet()); }); } } // Client-side: Get gun display information for rendering @OnlyIn(Dist.CLIENT) public void getGunDisplayInfo(ItemStack gunStack) { Optional<GunDisplayInstance> displayOpt = TimelessAPI.getGunDisplay(gunStack); displayOpt.ifPresent(display -> { // Access model, animation, and sound data System.out.println("Gun model loaded: " + (display.getGunModel() != null)); System.out.println("Animation controller: " + (display.getAnimationController() != null)); // Get transformation data for first-person view var transform = display.getTransform(); System.out.println("Third-person scale: " + transform.getThirdPerson().getScale()); }); } // List all registered guns public void listAllGuns() { TimelessAPI.getAllCommonGunIndex().forEach(entry -> { ResourceLocation gunId = entry.getKey(); CommonGunIndex gunIndex = entry.getValue(); System.out.println("Gun: " + gunId + " | Type: " + gunIndex.getType() + " | Ammo: " + gunIndex.getGunData().getAmmoId()); }); } } ``` --- ## Gun Item Interface - IGun Core interface providing access to gun properties, ammunition, attachments, and NBT data persistence. ```java package com.example.taczintegration; import com.tacz.guns.api.item.IGun; import com.tacz.guns.api.item.attachment.AttachmentType; import com.tacz.guns.api.item.gun.FireMode; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; public class GunManipulationExample { // Check if entity is holding a gun and get fire mode public void checkPlayerGun(Player player) { if (IGun.mainHandHoldGun(player)) { FireMode mode = IGun.getMainHandFireMode(player); System.out.println("Player holding gun in fire mode: " + mode); } } // Comprehensive gun manipulation public void manipulateGun(Player player, ItemStack gunStack) { if (!(gunStack.getItem() instanceof IGun iGun)) { return; } // Get basic gun info ResourceLocation gunId = iGun.getGunId(gunStack); System.out.println("Manipulating gun: " + gunId); // Ammunition management int currentAmmo = iGun.getCurrentAmmoCount(gunStack); System.out.println("Current ammo in magazine: " + currentAmmo); // Set ammo (for admin tools or game mechanics) iGun.setCurrentAmmoCount(gunStack, 30); // Check if using dummy ammo (virtual ammo system) if (iGun.useDummyAmmo(gunStack)) { int dummyAmmo = iGun.getDummyAmmoAmount(gunStack); int maxDummyAmmo = iGun.getMaxDummyAmmoAmount(gunStack); System.out.println("Dummy ammo: " + dummyAmmo + "/" + maxDummyAmmo); // Add dummy ammo (e.g., from loot or reward) iGun.addDummyAmmoAmount(gunStack, 60); } // Fire mode management FireMode currentMode = iGun.getFireMode(gunStack); System.out.println("Current fire mode: " + currentMode); // Toggle fire mode (semi-auto <-> full-auto) if (currentMode == FireMode.SEMI) { iGun.setFireMode(gunStack, FireMode.AUTO); } else if (currentMode == FireMode.AUTO) { iGun.setFireMode(gunStack, FireMode.SEMI); } // Attachment management checkAndManageAttachments(player, gunStack, iGun); // Level/Experience system int level = iGun.getLevel(gunStack); int exp = iGun.getExp(gunStack); int expToNext = iGun.getExpToNextLevel(gunStack); System.out.println("Gun level " + level + " (" + exp + " XP, " + expToNext + " XP to level " + (level + 1) + ")"); // Heat management (for guns with heat mechanics) if (iGun.hasHeatData(gunStack)) { float heat = iGun.getHeatAmount(gunStack); boolean overheated = iGun.isOverheatLocked(gunStack); System.out.println("Heat: " + heat + " | Overheated: " + overheated); if (overheated) { // Gun is locked due to overheating System.out.println("Gun overheated! Waiting for cooldown..."); } } // Bullet in barrel (for closed-bolt weapons) boolean bulletInBarrel = iGun.hasBulletInBarrel(gunStack); System.out.println("Bullet in barrel: " + bulletInBarrel); // Crawling/Prone mechanics boolean canCrawl = iGun.isCanCrawl(gunStack); System.out.println("Can use while prone: " + canCrawl); // Custom laser color (if gun has laser attachment) if (iGun.hasCustomLaserColor(gunStack)) { int laserColor = iGun.getLaserColor(gunStack); System.out.println("Laser color (RGB): " + Integer.toHexString(laserColor)); } } // Attachment system management private void checkAndManageAttachments(Player player, ItemStack gunStack, IGun iGun) { System.out.println("=== Attachment Management ==="); // Check attachment lock if (iGun.hasAttachmentLock(gunStack)) { System.out.println("Attachments are LOCKED - cannot modify"); return; } // Check each attachment slot for (AttachmentType type : AttachmentType.values()) { if (iGun.allowAttachmentType(gunStack, type)) { ItemStack attachment = iGun.getAttachment(gunStack, type); ResourceLocation attachmentId = iGun.getAttachmentId(gunStack, type); if (!attachment.isEmpty()) { System.out.println(type + " slot: " + attachmentId); } else { System.out.println(type + " slot: EMPTY"); } } } // Example: Install a scope (assuming player has it in inventory) ItemStack scopeItem = findScopeInInventory(player); if (!scopeItem.isEmpty() && iGun.allowAttachment(gunStack, scopeItem)) { // Unload existing scope if any iGun.unloadAttachment(gunStack, AttachmentType.SCOPE); // Install new scope iGun.installAttachment(gunStack, scopeItem); System.out.println("Installed new scope"); // Update zoom level float newZoom = iGun.getAimingZoom(gunStack); System.out.println("New zoom multiplier: " + newZoom + "x"); } } private ItemStack findScopeInInventory(Player player) { // Simplified - search player inventory for scope for (int i = 0; i < player.getInventory().getContainerSize(); i++) { ItemStack stack = player.getInventory().getItem(i); if (stack.getItem() instanceof com.tacz.guns.api.item.IAttachment attachment) { if (attachment.getType(stack) == AttachmentType.SCOPE) { return stack; } } } return ItemStack.EMPTY; } } ``` --- ## Gun Events - Event System Subscribe to gun-related events for custom behavior, statistics tracking, and gameplay modifications. ```java package com.example.taczintegration; import com.tacz.guns.api.event.common.*; import com.tacz.guns.api.item.gun.FireMode; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ItemStack; import net.minecraftforge.event.entity.living.LivingDeathEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @Mod.EventBusSubscriber(modid = "tacz_integration") public class GunEventHandlers { private static int shotsFired = 0; private static int headshotKills = 0; // Fired when a gun shoots (once per trigger pull, even in burst mode) @SubscribeEvent public static void onGunShoot(GunShootEvent event) { LivingEntity shooter = event.getShooter(); ItemStack gun = event.getGunItemStack(); ResourceLocation gunId = event.getGunId(); shotsFired++; System.out.println(shooter.getName().getString() + " fired " + gunId + " (Total shots: " + shotsFired + ")"); // Cancel shooting under certain conditions if (shooter.isInWater()) { event.setCanceled(true); if (shooter instanceof ServerPlayer player) { player.sendSystemMessage( Component.literal("Cannot fire underwater!")); } } } // Fired for each individual shot (may fire multiple times in burst mode) @SubscribeEvent public static void onGunFire(GunFireEvent event) { LivingEntity shooter = event.getShooter(); ItemStack gun = event.getGunItemStack(); // Differentiate client/server side if (event.getLogicalSide().isServer()) { System.out.println("Server: Gun fired by " + shooter.getName().getString()); } else { System.out.println("Client: Playing fire effects"); } // Cancel individual shots in burst if (shooter.getHealth() < 5.0f) { event.setCanceled(true); // Too wounded to maintain burst fire } } // Before entity takes damage from gun @SubscribeEvent public static void onPreGunHurt(EntityHurtByGunEvent.Pre event) { LivingEntity victim = event.getHurtEntity(); LivingEntity attacker = event.getAttacker(); float baseDamage = event.getBaseDamage(); float distance = event.getDistance(); boolean isHeadshot = event.isHeadshot(); ResourceLocation gunId = event.getGunId(); System.out.println("Pre-damage: " + attacker.getName().getString() + " hit " + victim.getName().getString() + " for " + baseDamage + " damage at " + distance + "m" + (isHeadshot ? " [HEADSHOT]" : "")); // Apply custom damage modifiers if (isHeadshot) { event.setBaseHeadshotMultiplier(3.0f); // Triple headshot damage } // Damage reduction for friendly fire if (attacker.getTeam() != null && attacker.getTeam().equals(victim.getTeam())) { event.setBaseArmorIgnore(0.0f); // Armor protects from friendly fire event.setBaseHeadshotMultiplier(1.0f); // No headshot bonus } // Cancel damage in protected zones if (isInSafeZone(victim)) { event.setCanceled(true); } } // After entity takes damage from gun @SubscribeEvent public static void onPostGunHurt(EntityHurtByGunEvent.Post event) { LivingEntity victim = event.getHurtEntity(); LivingEntity attacker = event.getAttacker(); float finalDamage = event.getAmount(); boolean isHeadshot = event.isHeadshot(); System.out.println("Post-damage: " + victim.getName().getString() + " took " + finalDamage + " damage" + (isHeadshot ? " from headshot" : "")); // Track headshot statistics if (isHeadshot && attacker instanceof ServerPlayer) { // Award achievement or update stats System.out.println("Headshot by " + attacker.getName().getString()); } } // When entity is killed by a gun @SubscribeEvent public static void onGunKill(EntityKillByGunEvent event) { LivingEntity killer = event.getKiller(); LivingEntity victim = event.getDeadEntity(); ResourceLocation gunId = event.getGunId(); boolean isHeadshot = event.isHeadShot(); if (isHeadshot) { headshotKills++; if (killer instanceof ServerPlayer player) { player.sendSystemMessage(Component.literal( "HEADSHOT! (" + headshotKills + " total)")); } } System.out.println(killer.getName().getString() + " killed " + victim.getName().getString() + " with " + gunId + (isHeadshot ? " [HEADSHOT]" : "")); } // Fired when reload begins @SubscribeEvent public static void onReload(GunReloadEvent event) { LivingEntity entity = event.getEntity(); ItemStack gun = event.getGunItemStack(); ResourceLocation gunId = event.getGunId(); System.out.println(entity.getName().getString() + " reloading " + gunId); // Cancel reload if out of ammo if (!hasAmmoInInventory(entity, gun)) { event.setCanceled(true); if (entity instanceof ServerPlayer player) { player.sendSystemMessage(Component.literal("Out of ammo!")); } } } // Fired when reload completes @SubscribeEvent public static void onReloadFinish(GunFinishReloadEvent event) { LivingEntity entity = event.getEntity(); ResourceLocation gunId = event.getGunId(); System.out.println(entity.getName().getString() + " finished reloading " + gunId); } // Fire mode selection (semi/auto/burst) @SubscribeEvent public static void onFireModeSwitch(GunFireSelectEvent event) { LivingEntity entity = event.getEntity(); FireMode oldMode = event.getOldFireMode(); FireMode newMode = event.getNewFireMode(); System.out.println(entity.getName().getString() + " switched fire mode: " + oldMode + " -> " + newMode); // Restrict fire modes based on permissions if (entity instanceof ServerPlayer player) { if (newMode == FireMode.AUTO && !player.hasPermissions(2)) { event.setCanceled(true); player.sendSystemMessage(Component.literal( "Full-auto mode requires operator permission")); } } } // Melee/bayonet attack @SubscribeEvent public static void onGunMelee(GunMeleeEvent event) { LivingEntity attacker = event.getAttacker(); LivingEntity victim = event.getHurtEntity(); ItemStack gun = event.getGunItemStack(); System.out.println(attacker.getName().getString() + " melee attacked " + victim.getName().getString() + " with gun"); // Bonus damage if attacking from behind if (isAttackingFromBehind(attacker, victim)) { float currentDamage = event.getAmount(); event.setAmount(currentDamage * 1.5f); } } // Gun drawn (switched to in hotbar) @SubscribeEvent public static void onGunDraw(GunDrawEvent event) { LivingEntity entity = event.getEntity(); ItemStack gun = event.getGunItemStack(); ResourceLocation gunId = event.getGunId(); System.out.println(entity.getName().getString() + " drew " + gunId); } // Bullet hits block @SubscribeEvent public static void onAmmoHitBlock(AmmoHitBlockEvent event) { var blockState = event.getState(); var hitPos = event.getHitResult().getBlockPos(); System.out.println("Bullet hit " + blockState.getBlock().getName() + " at " + hitPos); // Cancel block hit effects in protected areas if (isProtectedBlock(hitPos)) { event.setCanceled(true); } } // Helper methods private static boolean isInSafeZone(LivingEntity entity) { // Check if entity is in a protected zone (spawn, town, etc.) return false; // Implementation depends on your protection system } private static boolean hasAmmoInInventory(LivingEntity entity, ItemStack gun) { // Check if entity has compatible ammo return true; // Simplified } private static boolean isAttackingFromBehind(LivingEntity attacker, LivingEntity victim) { // Calculate if attacking from behind based on look vectors return false; // Simplified } private static boolean isProtectedBlock(net.minecraft.core.BlockPos pos) { // Check if block is protected return false; // Simplified } } ``` --- ## Bullet Entity - EntityKineticBullet The projectile entity representing fired bullets with ballistics simulation and hit detection. ```java package com.example.taczintegration; import com.tacz.guns.entity.EntityKineticBullet; import com.tacz.guns.resource.index.CommonGunIndex; import com.tacz.guns.resource.pojo.data.gun.BulletData; import com.tacz.guns.resource.pojo.data.gun.GunData; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.Vec3; public class CustomBulletExample { // Spawn a custom bullet entity public void fireCustomBullet(ServerLevel level, LivingEntity shooter, ItemStack gunStack, ResourceLocation gunId, ResourceLocation ammoId, GunData gunData) { BulletData bulletData = gunData.getBulletData(); // Create bullet entity // Parameters: level, shooter, gun item, ammo ID, gun ID, // is tracer, gun data, bullet data EntityKineticBullet bullet = new EntityKineticBullet( level, shooter, gunStack, ammoId, gunId, true, // isTracer - visual tracer effect gunData, bulletData ); // Set bullet spawn position (slightly in front of shooter) Vec3 shooterPos = shooter.getEyePosition(); Vec3 lookVec = shooter.getLookAngle(); Vec3 spawnPos = shooterPos.add(lookVec.scale(0.5)); bullet.setPos(spawnPos.x, spawnPos.y, spawnPos.z); // Calculate spread for inaccuracy double horizontalSpread = Math.random() * 0.5 - 0.25; // -0.25 to 0.25 double verticalSpread = Math.random() * 0.5 - 0.25; // Shoot the bullet // Parameters: pitch offset, yaw offset, velocity m/s, spread vector bullet.shoot( verticalSpread, // pitch variance horizontalSpread, // yaw variance bulletData.getSpeed(), // bullet speed new com.mojang.math.Vector2f(0.5f, 0.5f) // additional spread ); // Spawn the bullet in the world level.addFreshEntity(bullet); System.out.println("Fired bullet: velocity=" + bulletData.getSpeed() + "m/s, damage=" + bulletData.getDamage() + ", gravity=" + bulletData.getGravity()); } // Spawn multiple bullets for shotgun-style weapons public void fireScatterShot(ServerLevel level, LivingEntity shooter, ItemStack gunStack, ResourceLocation gunId, ResourceLocation ammoId, GunData gunData) { BulletData bulletData = gunData.getBulletData(); int pelletCount = bulletData.getBulletAmount(); // Number of pellets for (int i = 0; i < pelletCount; i++) { EntityKineticBullet bullet = new EntityKineticBullet( level, shooter, gunStack, ammoId, gunId, false, // No tracer for pellets gunData, bulletData ); // Position bullet Vec3 shooterPos = shooter.getEyePosition(); bullet.setPos(shooterPos.x, shooterPos.y, shooterPos.z); // Random spread for each pellet double horizontalSpread = (Math.random() - 0.5) * 10.0; // Wide spread double verticalSpread = (Math.random() - 0.5) * 10.0; bullet.shoot( verticalSpread, horizontalSpread, bulletData.getSpeed(), new com.mojang.math.Vector2f(5.0f, 5.0f) // Large spread cone ); level.addFreshEntity(bullet); } System.out.println("Fired " + pelletCount + " pellets"); } // Calculate bullet damage at a specific distance public float calculateBulletDamage(EntityKineticBullet bullet, double distanceMeters) { // Access bullet's damage calculation // The bullet uses getDamage(Vec3 hitVec) internally which calculates // distance-based damage falloff // This is simplified - actual calculation uses distance-damage curve float baseDamage = bullet.getDamage(); // Example falloff (actual uses piecewise function from gun data) if (distanceMeters < 30) { return baseDamage; } else if (distanceMeters < 60) { return baseDamage * 0.8f; } else { return baseDamage * 0.6f; } } } ``` --- ## Resource Pack System - Gun Definition Create custom guns through JSON configuration without code modification. ```json { "ammo": "tacz:556x45", "ammo_amount": 30, "extended_mag_ammo_amount": [34, 37, 40], "script": "tacz:xmag_reload_logic", "script_param": { "reload_feed": 1.55, "reload_cooldown": 2.0, "empty_feed": 2.25, "empty_cooldown": 2.6 }, "can_crawl": true, "can_slide": true, "bolt": "closed_bolt", "rpm": 750, "bullet": { "life": 0.8, "bullet_amount": 1, "damage": 8.5, "tracer_count_interval": 0, "extra_damage": { "armor_ignore": 0.30, "head_shot_multiplier": 2.0, "damage_adjust": [ {"distance": 40, "damage": 8.5}, {"distance": 80, "damage": 7.0}, {"distance": "infinite", "damage": 5.5} ] }, "speed": 300, "gravity": 0.12, "knockback": 0, "friction": 0.015, "pierce": 2, "ignite": { "entity": false, "block": false } }, "fire_sound": { "fire_multiplier": 1.0, "silence_multiplier": 0.3 }, "reload": { "type": "magazine", "infinite": false, "feed": { "empty": 2.25, "tactical": 1.55 }, "cooldown": { "empty": 2.6, "tactical": 2.0 } }, "draw_time": 0.35, "put_away_time": 0.50, "aim_time": 0.2, "sprint_time": 0.2, "weight": 3.2, "movement_speed": { "base": 0.0, "aim": -0.25, "reload": -0.15 }, "fire_mode": ["auto", "semi", "burst"], "burst_data": { "continuous_shoot": true, "count": 3, "bpm": 900, "min_interval": 0.3 }, "crawl_recoil_multiplier": 0.5, "recoil": { "pitch": [ {"time": 0, "value": [0.55, 0.55]}, {"time": 0.1, "value": [0.55, 0.55]}, {"time": 0.4, "value": [-0.15, -0.15]}, {"time": 0.6, "value": [0, 0]} ], "yaw": [ {"time": 0, "value": [-0.2, 0.2]}, {"time": 0.35, "value": [0, 0]} ] }, "inaccuracy": { "stand": 3.5, "move": 4.5, "sneak": 2.0, "lie": 1.0, "aim": 0.1 }, "melee": { "distance": 1, "cooldown": 0.7, "default": { "animation_type": "melee_push", "distance": 1, "range_angle": 40, "cooldown": 0, "damage": 2, "knockback": 0.5, "prep": 0.1 } }, "allow_attachment_types": [ "scope", "stock", "muzzle", "grip", "extended_mag" ] } ``` **Attachment Definition Example:** ```json { "weight": 0.8, "zoom": [2.0, 4.0, 6.0], "ads_addend": 0.05, "inaccuracy_addend": -0.5, "recoil_modifier": { "pitch": -0.15, "yaw": -0.10 }, "movement_speed": { "base": -0.02, "aim": -0.05 }, "silence": { "distance_multiplier": 0.2, "hide_muzzle_flash": true } } ``` **Ammo Definition Example:** ```json { "stack_size": 64, "weight": 0.012, "damage_modifier": 1.0, "speed_modifier": 1.0, "tracer_color": "#FF5500" } ``` --- ## KubeJS Integration - Scripting Create custom guns and handle events through KubeJS JavaScript scripting. ```javascript // startup_scripts/custom_guns.js StartupEvents.registry('item', event => { // Create custom modern kinetic gun event.create('my_custom_rifle', 'tacz:modern_kinetic_gun') .gunId('mymod:custom_rifle') .displayName('Custom Tactical Rifle') .maxStackSize(1) .firearmType('rifle') .attachable(true); // Create custom attachment event.create('my_custom_scope', 'tacz:attachment') .attachmentId('mymod:custom_scope') .displayName('Advanced Scope') .attachmentType('scope') .maxStackSize(1); }); // server_scripts/gun_events.js const { TimelessServerEvents } = require('tacz-kubejs'); // Listen to gun shoot events TimelessServerEvents.gunShoot(event => { const { shooter, gunItemStack, gunId, logicalSide } = event; console.log(`${shooter.name.string} fired ${gunId}`); // Cancel shooting if player is on fire if (shooter.isOnFire()) { event.cancel(); shooter.tell('Cannot shoot while on fire!'); } // Custom effect on shoot if (gunId == 'tacz:ak47') { // Spawn particles or apply effects shooter.addEffect('minecraft:speed', 20, 1); } }); // Listen to gun kill events TimelessServerEvents.entityKillByGun(event => { const { killer, deadEntity, gunId, isHeadShot } = event; if (isHeadShot && killer.isPlayer()) { // Award bonus for headshots killer.give('minecraft:diamond'); killer.tell(Text.green('HEADSHOT! +1 Diamond')); // Play sound killer.playSound('minecraft:entity.player.levelup', 1.0, 1.5); } // Track kills per gun type if (!killer.persistentData.gunKills) { killer.persistentData.gunKills = {}; } killer.persistentData.gunKills[gunId] = (killer.persistentData.gunKills[gunId] || 0) + 1; }); // Listen to reload events TimelessServerEvents.gunReload(event => { const { entity, gunItemStack, gunId } = event; console.log(`${entity.name.string} reloading ${gunId}`); // Fast reload mechanic for certain guns if (gunId == 'tacz:glock_17' && entity.isPlayer()) { // Grant temporary speed boost during reload entity.addEffect('minecraft:speed', 40, 2); } }); // Listen to fire mode changes TimelessServerEvents.gunFireSelect(event => { const { entity, oldFireMode, newFireMode } = event; console.log(`Fire mode changed: ${oldFireMode} -> ${newFireMode}`); // Restrict full-auto to certain players if (newFireMode == 'AUTO' && !entity.isOp()) { event.cancel(); entity.tell('Full-auto restricted to operators'); } }); // client_scripts/gun_client.js const { TimelessClientEvents } = require('tacz-kubejs'); // Client-side gun events TimelessClientEvents.gunFire(event => { const { shooter, gunItemStack, logicalSide } = event; // Custom client-side effects (particles, sounds, screen shake) if (logicalSide.isClient()) { // Add custom visual effects here console.log('Gun fired on client'); } }); ``` **Custom Gun Smith Table Recipe (KubeJS):** ```javascript // server_scripts/recipes.js ServerEvents.recipes(event => { // Gun crafting recipe event.recipes.tacz.gun_smith_table({ result: Item.of('tacz:modern_kinetic_gun', { GunId: 'tacz:ak47', CurrentAmmoCount: 30 }), materials: [ { item: 'minecraft:iron_ingot', count: 20 }, { item: 'minecraft:redstone', count: 10 }, { item: 'minecraft:iron_block', count: 2 } ] }); // Attachment crafting event.recipes.tacz.gun_smith_table({ result: Item.of('tacz:attachment', { AttachmentId: 'tacz:scope_standard_4x' }), materials: [ { item: 'minecraft:glass_pane', count: 4 }, { item: 'minecraft:iron_ingot', count: 6 }, { item: 'minecraft:redstone', count: 2 } ] }); }); ``` --- ## Lua Animation Scripts - Gun Logic Implement custom gun behavior using Lua scripting for animations and mechanics. ```lua -- data/mymod/scripts/custom_gun_logic.lua -- Called when gun starts bolt action function start_bolt(api) print("Starting bolt action") api:play_animation("bolt_start") api:set_bolt_time(0.5) -- 0.5 second bolt action end -- Called each tick during bolt action function tick_bolt(api, time_seconds) -- Update bolt position based on time local progress = time_seconds / 0.5 -- 0.0 to 1.0 api:set_bolt_progress(progress) if progress >= 0.3 and not api:get_data("ejected_shell") then -- Eject shell casing at 30% progress api:eject_shell() api:set_data("ejected_shell", true) end if progress >= 1.0 then -- Bolt action complete api:set_data("ejected_shell", false) api:finish_bolt() end end -- Called when gun shoots function shoot(api) print("Gun fired!") -- Custom muzzle flash api:spawn_muzzle_flash() -- Camera shake intensity based on fire mode local fire_mode = api:get_fire_mode() if fire_mode == "AUTO" then api:add_camera_shake(0.3) else api:add_camera_shake(0.5) end -- Play random shoot sound variant local sound_variant = math.random(1, 3) api:play_sound("shoot_" .. sound_variant) return true -- Allow shot to proceed end -- Called when reload starts function start_reload(api) local is_empty = api:get_current_ammo() == 0 if is_empty then print("Empty reload") api:play_animation("reload_empty") api:set_reload_state("empty") else print("Tactical reload") api:play_animation("reload_tactical") api:set_reload_state("tactical") end end -- Called each tick during reload function tick_reload(api, time_seconds) local reload_state = api:get_reload_state() local total_time = reload_state == "empty" and 2.5 or 1.8 local progress = time_seconds / total_time -- Magazine eject at 20% progress if progress >= 0.2 and not api:get_data("mag_ejected") then api:eject_magazine() api:set_data("mag_ejected", true) api:play_sound("mag_out") end -- Magazine insert at 60% progress if progress >= 0.6 and not api:get_data("mag_inserted") then api:insert_magazine() api:set_data("mag_inserted", true) api:play_sound("mag_in") end -- Bolt release at 80% (empty reload only) if reload_state == "empty" and progress >= 0.8 and not api:get_data("bolt_released") then api:release_bolt() api:set_data("bolt_released", true) api:play_sound("bolt_release") end -- Reload complete if progress >= 1.0 then api:finish_reload() -- Reset reload data api:set_data("mag_ejected", false) api:set_data("mag_inserted", false) api:set_data("bolt_released", false) end end -- Called when reload is interrupted function interrupt_reload(api) print("Reload interrupted!") api:stop_animation("reload") api:play_animation("reload_interrupt") end -- Called each tick to update heat function tick_heat(api, delta_time) local current_heat = api:get_heat() local max_heat = 240 -- Heat increases on shot if api:just_fired() then api:add_heat(2) end -- Cooling over time (quadratic cooling curve) if current_heat > 0 then local cooling_rate = 4 * delta_time * delta_time api:add_heat(-cooling_rate) end -- Overheat lockout if current_heat >= max_heat then api:set_overheat_locked(true) api:play_sound("overheat") end -- Unlock after cooldown if api:is_overheat_locked() and current_heat < max_heat * 0.3 then api:set_overheat_locked(false) api:play_sound("cooldown_complete") end end -- Called to calculate bullet spread function calcSpread(api, bullet_num, base_inaccuracy) local heat_progress = api:get_heat() / 240 local heat_multiplier = 1.0 + (heat_progress * 0.3) -- Up to 30% more spread -- Increase spread for subsequent bullets in burst local burst_multiplier = 1.0 + (bullet_num * 0.1) return base_inaccuracy * heat_multiplier * burst_multiplier end -- Custom function - check if can shoot function can_shoot(api) -- Prevent shooting while overheated if api:is_overheat_locked() then return false end -- Prevent shooting underwater if api:is_underwater() then api:show_message("Cannot fire underwater") return false end return true end ``` **Lua Animation State Machine:** ```lua -- animations/custom_animation_controller.lua -- Define animation states states = { idle = { animation = "idle", transitions = { { to = "shoot", condition = "on_shoot" }, { to = "reload", condition = "on_reload" }, { to = "inspect", condition = "on_inspect" } } }, shoot = { animation = "shoot", duration = 0.15, transitions = { { to = "idle", condition = "animation_end" } } }, reload = { animation = "reload_tactical", duration = 1.8, interruptible = true, transitions = { { to = "idle", condition = "animation_end" }, { to = "idle", condition = "on_interrupt" } } }, inspect = { animation = "inspect", duration = 2.0, interruptible = true, transitions = { { to = "idle", condition = "animation_end" } } } } -- Initial state initial_state = "idle" -- State update function function update_state(api, current_state, delta_time) -- Custom per-state logic if current_state == "shoot" then -- Trigger effects during shoot animation if api:get_animation_time() > 0.05 then api:spawn_muzzle_flash() end end end ``` --- ## Gradle Integration - Build Configuration Add TACZ as a dependency to your Forge mod project for API access. ```groovy // build.gradle repositories { maven { name = "Curse Maven" url = "https://www.cursemaven.com" content { includeGroup "curse.maven" } } maven { name = "JitPack" url = "https://jitpack.io" } } dependencies { // TACZ dependency with sources for development // Format: curse.maven:project-slug-projectId:fileId-sources-sourcesFileId implementation fg.deobf("curse.maven:timeless-and-classics-zero-1028108:6632240-sources-6633203") // Alternative: JitPack version // implementation fg.deobf("com.github.MCModderAnchor:TACZ:1.1.6-hotfix") } minecraft { runs { client { property 'mixin.env.remapRefMap', 'true' property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" // Add TACZ to runtime for testing mods { tacz { source sourceSets.main } } } server { property 'mixin.env.remapRefMap', 'true' property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" mods { tacz { source sourceSets.main } } } } } ``` **mods.toml Configuration:** ```toml modLoader="javafml" loaderVersion="[47,)" license="GPL-3.0" [[mods]] modId="my_tacz_integration" version="${file.jarVersion}" displayName="TACZ Integration Example" description="Example mod integrating with TACZ" [[dependencies.my_tacz_integration]] modId="forge" mandatory=true versionRange="[47.1.3,)" ordering="NONE" side="BOTH" [[dependencies.my_tacz_integration]] modId="tacz" mandatory=true versionRange="[1.1.0,)" ordering="AFTER" side="BOTH" ``` --- ## Summary TACZ provides a comprehensive firearms framework for Minecraft that balances realism with gameplay flexibility. The mod's primary use cases include survival gameplay enhancement with realistic weapon mechanics, PvP combat scenarios with balanced gun statistics, adventure maps featuring modern weapons, and roleplay servers requiring authentic firearms. The extensive event system enables kill tracking, statistics collection, damage modification, custom game modes, and permission-based restrictions. Resource pack creators can design complete weapon sets without coding, while mod developers can create weapon-based minigames, integrate guns with custom systems, add procedural weapon generation, or build entire combat-focused mods on the TACZ foundation. Integration patterns emphasize the API-first approach through TimelessAPI for data access, event-driven customization via Forge events, and Lua scripting for complex gun behaviors. The client-server separation ensures proper synchronization, with common indices available on both sides and display data exclusively client-side. Resource pack layering allows multiple gun packs to coexist, enabling players to combine weapons from different creators. KubeJS integration provides script-based customization without Java knowledge, making TACZ accessible to both technical mod developers and content creators focused on gameplay design. The mod's architecture supports everything from simple gun additions to complete combat system overhauls.