forradalom es szabadsagharc: island structure, update ak47, rework revolver
@@ -1,11 +1,8 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.sound.SoundEvents;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.TypedActionResult;
|
||||
import net.minecraft.util.UseAction;
|
||||
@@ -17,25 +14,7 @@ public class AK47Item extends Item {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inventoryTick(ItemStack stack, World world, Entity entity, int slot, boolean selected) {
|
||||
if (!(entity instanceof PlayerEntity player)) return;
|
||||
if (!selected) return;
|
||||
if (!player.isUsingItem()) return;
|
||||
if (world.isClient) return;
|
||||
|
||||
if (player.getItemCooldownManager().isCoolingDown(this)) return;
|
||||
if (!consumeAmmo(player)) return;
|
||||
player.getWorld().playSound(null, player.getBlockPos(),
|
||||
SoundEvents.ENTITY_GENERIC_EXPLODE, SoundCategory.PLAYERS, 0.5f, 1.8f);
|
||||
BulletEntity bullet = new BulletEntity(world, player);
|
||||
bullet.setVelocity(player, player.getPitch(), player.getYaw(), 0f, 4.5f, 1.0f);
|
||||
world.spawnEntity(bullet);
|
||||
|
||||
player.getItemCooldownManager().set(this, 2); // fire rate
|
||||
}
|
||||
|
||||
private boolean consumeAmmo(PlayerEntity player) {
|
||||
public boolean consumeAmmo(PlayerEntity player) {
|
||||
if (player.getAbilities().creativeMode) return true;
|
||||
|
||||
for (int i = 0; i < player.getInventory().size(); i++) {
|
||||
@@ -50,7 +29,7 @@ public class AK47Item extends Item {
|
||||
|
||||
@Override
|
||||
public UseAction getUseAction(ItemStack stack) {
|
||||
return UseAction.NONE;
|
||||
return UseAction.BOW; // raises arm
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,6 +3,7 @@ package dev.tggamesyt.szar;
|
||||
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
|
||||
import net.fabricmc.fabric.api.networking.v1.PlayerLookup;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
@@ -13,14 +14,20 @@ import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.particle.ParticleTypes;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.hit.EntityHitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class BulletEntity extends ThrownItemEntity {
|
||||
|
||||
private static final float BASE_DAMAGE = 13.0F;
|
||||
private static final float PIERCE_BREAK_THRESHOLD = 0.4F;
|
||||
|
||||
private float pierceValue = 1.0F;
|
||||
private int stillTicks = 0;
|
||||
private double lastX, lastY, lastZ;
|
||||
|
||||
@@ -47,7 +54,7 @@ public class BulletEntity extends ThrownItemEntity {
|
||||
|
||||
if (movedSq < 0.0001) {
|
||||
stillTicks++;
|
||||
if (stillTicks >= 3) { // discard after 3 ticks of no movement
|
||||
if (stillTicks >= 3) {
|
||||
discard();
|
||||
return;
|
||||
}
|
||||
@@ -79,20 +86,60 @@ public class BulletEntity extends ThrownItemEntity {
|
||||
this,
|
||||
livingOwner
|
||||
);
|
||||
target.damage(source, 13.0F);
|
||||
// Damage scaled by remaining pierce value
|
||||
target.damage(source, BASE_DAMAGE * pierceValue);
|
||||
}
|
||||
|
||||
discard();
|
||||
// Don't discard — bullet continues through entities
|
||||
// But reduce pierce value a bit for entity hits
|
||||
pierceValue -= 0.3F;
|
||||
if (pierceValue <= 0) {
|
||||
discard();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBlockHit(net.minecraft.util.hit.BlockHitResult hit) {
|
||||
super.onBlockHit(hit);
|
||||
// Use exact hit position + nudge along face normal to sit on surface
|
||||
protected void onBlockHit(BlockHitResult hit) {
|
||||
if (getWorld().isClient) return;
|
||||
|
||||
BlockPos blockPos = hit.getBlockPos();
|
||||
BlockState state = getWorld().getBlockState(blockPos);
|
||||
Vec3d pos = hit.getPos();
|
||||
Direction face = hit.getSide();
|
||||
spawnImpact(pos, face);
|
||||
discard();
|
||||
|
||||
float resistance = state.getBlock().getBlastResistance();
|
||||
|
||||
if (!state.isAir()) {
|
||||
pierceValue -= resistance;
|
||||
}
|
||||
|
||||
if (pierceValue <= 0) {
|
||||
// Bullet stopped — spawn impact and discard
|
||||
spawnImpact(pos, face);
|
||||
discard();
|
||||
return;
|
||||
}
|
||||
|
||||
if (resistance < PIERCE_BREAK_THRESHOLD && !state.isAir()) {
|
||||
// Break the block
|
||||
if (getWorld() instanceof ServerWorld serverWorld) {
|
||||
// Play break sound
|
||||
getWorld().playSound(
|
||||
null,
|
||||
blockPos,
|
||||
state.getSoundGroup().getBreakSound(),
|
||||
SoundCategory.BLOCKS,
|
||||
1.0F,
|
||||
1.0F
|
||||
);
|
||||
serverWorld.breakBlock(blockPos, true, getOwner());
|
||||
}
|
||||
// Bullet continues — don't call super, don't discard
|
||||
} else {
|
||||
// Block too strong to break — bullet stops here
|
||||
spawnImpact(pos, face);
|
||||
discard();
|
||||
}
|
||||
}
|
||||
|
||||
private void spawnImpact(Vec3d pos, Direction face) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package dev.tggamesyt.szar;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.SpawnReason;
|
||||
import net.minecraft.entity.ai.goal.Goal;
|
||||
import net.minecraft.entity.ai.goal.LookAroundGoal;
|
||||
import net.minecraft.entity.ai.goal.MeleeAttackGoal;
|
||||
@@ -13,10 +14,21 @@ import net.minecraft.entity.damage.DamageSource;
|
||||
import net.minecraft.entity.mob.MobEntity;
|
||||
import net.minecraft.entity.mob.PathAwareEntity;
|
||||
import net.minecraft.entity.passive.VillagerEntity;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.registry.entry.RegistryEntry;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.structure.StructureStart;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
import net.minecraft.world.ServerWorldAccess;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.gen.structure.Structure;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class EpsteinEntity extends PathAwareEntity implements Arrestable {
|
||||
|
||||
@@ -24,6 +36,7 @@ public class EpsteinEntity extends PathAwareEntity implements Arrestable {
|
||||
|
||||
public EpsteinEntity(EntityType<? extends PathAwareEntity> type, World world) {
|
||||
super(type, world);
|
||||
this.setPersistent();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -13,7 +13,10 @@ import net.minecraft.entity.mob.MobEntity;
|
||||
import net.minecraft.entity.mob.PathAwareEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.nbt.NbtList;
|
||||
import net.minecraft.nbt.NbtString;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
@@ -241,6 +244,15 @@ public class IslamTerrorist extends PathAwareEntity implements Arrestable{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dropLoot(DamageSource source, boolean causedByPlayer) {
|
||||
Random r = new Random();
|
||||
int number = r.nextInt(3) + 1;
|
||||
ItemStack powder = new ItemStack(Items.GUNPOWDER, number);
|
||||
|
||||
this.dropStack(powder);
|
||||
}
|
||||
|
||||
|
||||
// ================= DAMAGE =================
|
||||
|
||||
|
||||
57
src/main/java/dev/tggamesyt/szar/IslandStructure.java
Normal file
@@ -0,0 +1,57 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import net.minecraft.structure.StructurePlacementData;
|
||||
import net.minecraft.util.BlockRotation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.world.Heightmap;
|
||||
import net.minecraft.world.gen.structure.Structure;
|
||||
import net.minecraft.world.gen.structure.StructureType;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class IslandStructure extends Structure {
|
||||
|
||||
public static final Codec<IslandStructure> CODEC =
|
||||
Structure.createCodec(IslandStructure::new);
|
||||
|
||||
public IslandStructure(Config config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<StructurePosition> getStructurePosition(Context context) {
|
||||
ChunkPos chunkPos = context.chunkPos();
|
||||
int x = chunkPos.getCenterX();
|
||||
int z = chunkPos.getCenterZ();
|
||||
|
||||
// Find water surface — scan down from world height to sea level
|
||||
int seaLevel = context.chunkGenerator().getSeaLevel();
|
||||
|
||||
int surfaceY = context.chunkGenerator().getHeightInGround(
|
||||
x, z,
|
||||
Heightmap.Type.OCEAN_FLOOR_WG,
|
||||
context.world(),
|
||||
context.noiseConfig()
|
||||
);
|
||||
|
||||
// Must be underwater (ocean floor below sea level)
|
||||
if (surfaceY >= seaLevel - 2) return Optional.empty();
|
||||
|
||||
// Place structure at sea level + 1 so it sits on the water surface
|
||||
BlockPos pos = new BlockPos(x, seaLevel + 1, z);
|
||||
|
||||
StructurePlacementData placement = new StructurePlacementData()
|
||||
.setRotation(BlockRotation.random(context.random()));
|
||||
|
||||
return Structure.getStructurePosition(context, Heightmap.Type.WORLD_SURFACE_WG, collector ->
|
||||
collector.addPiece(new IslandStructurePiece(context, pos, BlockPos.ORIGIN, placement))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StructureType<?> getType() {
|
||||
return Szar.ISLAND_TYPE;
|
||||
}
|
||||
}
|
||||
87
src/main/java/dev/tggamesyt/szar/IslandStructurePiece.java
Normal file
@@ -0,0 +1,87 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import net.minecraft.block.entity.ChestBlockEntity;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.structure.SimpleStructurePiece;
|
||||
import net.minecraft.structure.StructureContext;
|
||||
import net.minecraft.structure.StructurePlacementData;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockBox;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
import net.minecraft.world.ServerWorldAccess;
|
||||
import net.minecraft.world.StructureWorldAccess;
|
||||
import net.minecraft.world.gen.StructureAccessor;
|
||||
import net.minecraft.world.gen.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.gen.structure.Structure;
|
||||
|
||||
public class IslandStructurePiece extends SimpleStructurePiece {
|
||||
|
||||
private static final Identifier TEMPLATE_ID =
|
||||
new Identifier(Szar.MOD_ID, "island");
|
||||
|
||||
/* ===== NORMAL CONSTRUCTOR (Worldgen) ===== */
|
||||
public IslandStructurePiece(
|
||||
Structure.Context context,
|
||||
BlockPos pos,
|
||||
BlockPos origin,
|
||||
StructurePlacementData placement
|
||||
) {
|
||||
super(
|
||||
Szar.ISLAND_PIECE,
|
||||
0,
|
||||
context.structureTemplateManager(),
|
||||
TEMPLATE_ID,
|
||||
TEMPLATE_ID.toString(),
|
||||
placement,
|
||||
pos
|
||||
);
|
||||
}
|
||||
|
||||
/* ===== NBT CONSTRUCTOR (Chunk Save/Load) ===== */
|
||||
public IslandStructurePiece(StructureContext context, NbtCompound nbt) {
|
||||
super(
|
||||
Szar.ISLAND_PIECE,
|
||||
nbt,
|
||||
context.structureTemplateManager(),
|
||||
identifier -> new StructurePlacementData()
|
||||
);
|
||||
}
|
||||
|
||||
/* ===== Metadata Handler (DATA structure blocks) ===== */
|
||||
@Override
|
||||
protected void handleMetadata(
|
||||
String metadata,
|
||||
BlockPos pos,
|
||||
ServerWorldAccess world,
|
||||
Random random,
|
||||
BlockBox boundingBox
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(StructureWorldAccess world, StructureAccessor structureAccessor,
|
||||
ChunkGenerator chunkGenerator, Random random,
|
||||
BlockBox chunkBox, ChunkPos chunkPos, BlockPos pivot) {
|
||||
|
||||
// This actually places the structure blocks
|
||||
super.generate(world, structureAccessor, chunkGenerator, random, chunkBox, chunkPos, pivot);
|
||||
|
||||
BlockBox box = this.getBoundingBox();
|
||||
for (int bx = box.getMinX(); bx <= box.getMaxX(); bx++) {
|
||||
for (int by = box.getMinY(); by <= box.getMaxY(); by++) {
|
||||
for (int bz = box.getMinZ(); bz <= box.getMaxZ(); bz++) {
|
||||
BlockPos pos = new BlockPos(bx, by, bz);
|
||||
if (world.getBlockEntity(pos) instanceof ChestBlockEntity chest) {
|
||||
chest.setLootTable(
|
||||
new Identifier(Szar.MOD_ID, "chests/island"),
|
||||
random.nextLong()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.sound.SoundEvents;
|
||||
@@ -15,6 +17,8 @@ import net.minecraft.util.UseAction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import static dev.tggamesyt.szar.Szar.REVOLVER_STATE_SYNC;
|
||||
|
||||
public class RevolverItem extends Item {
|
||||
|
||||
public static final int CHAMBERS = 6;
|
||||
@@ -75,4 +79,16 @@ public class RevolverItem extends Item {
|
||||
return 72000; // held indefinitely
|
||||
}
|
||||
|
||||
public static void syncRevolverToClient(ServerPlayerEntity player, ItemStack stack) {
|
||||
boolean[] chambers = RevolverItem.getChambers(stack);
|
||||
int current = RevolverItem.getCurrentChamber(stack);
|
||||
|
||||
PacketByteBuf buf = PacketByteBufs.create();
|
||||
for (int i = 0; i < RevolverItem.CHAMBERS; i++) {
|
||||
buf.writeBoolean(chambers[i]);
|
||||
}
|
||||
buf.writeInt(current);
|
||||
ServerPlayNetworking.send(player, REVOLVER_STATE_SYNC, buf);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,8 +9,10 @@ import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
import net.fabricmc.fabric.api.event.player.AttackEntityCallback;
|
||||
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
||||
import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
|
||||
import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup;
|
||||
import net.fabricmc.fabric.api.loot.v2.LootTableEvents;
|
||||
import net.fabricmc.fabric.api.message.v1.ServerMessageDecoratorEvent;
|
||||
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||
@@ -26,6 +28,7 @@ import net.minecraft.advancement.Advancement;
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.block.entity.ChestBlockEntity;
|
||||
import net.minecraft.entity.*;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
import net.minecraft.entity.damage.DamageType;
|
||||
@@ -38,6 +41,11 @@ import net.minecraft.entity.effect.StatusEffectInstance;
|
||||
import net.minecraft.entity.passive.VillagerEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.*;
|
||||
import net.minecraft.loot.LootPool;
|
||||
import net.minecraft.loot.entry.ItemEntry;
|
||||
import net.minecraft.loot.function.SetCountLootFunction;
|
||||
import net.minecraft.loot.provider.number.ConstantLootNumberProvider;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.registry.*;
|
||||
import net.minecraft.registry.entry.RegistryEntry;
|
||||
@@ -79,6 +87,7 @@ import net.minecraft.world.gen.structure.StructureType;
|
||||
import net.minecraft.world.poi.PointOfInterestType;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.core.jmx.Server;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -93,9 +102,16 @@ public class Szar implements ModInitializer {
|
||||
public static MinecraftServer SERVER;
|
||||
public static final Identifier REVOLVER_SHOOT = new Identifier(MOD_ID, "revolver_shoot");
|
||||
public static final Identifier REVOLVER_SPIN = new Identifier(MOD_ID, "revolver_spin");
|
||||
public static final Identifier REVOLVER_SYNC = new Identifier(MOD_ID, "revolver_sync");
|
||||
public static final Identifier REVOLVER_STATE_SYNC = new Identifier(MOD_ID, "revolver_state_sync");
|
||||
public static final Identifier BULLET_IMPACT = new Identifier(MOD_ID, "bullet_impact");
|
||||
public static final Identifier REVOLVER_SCROLL = new Identifier(MOD_ID, "revolver_scroll");
|
||||
public static final Identifier REVOLVER_SPIN_RESULT = new Identifier(MOD_ID, "revolver_spin_result"); // S2C
|
||||
public static final Identifier AK47_SHOOT = new Identifier(MOD_ID, "ak47_shoot");
|
||||
public static final Identifier REVOLVER_CHAMBER_CHANGE = new Identifier(MOD_ID, "revolver_chamber_change");
|
||||
public static final SoundEvent REVOLVER_CLICK1_SOUND = SoundEvent.of(new Identifier(MOD_ID, "revolver_click1"));
|
||||
public static final SoundEvent REVOLVER_CLICK2_SOUND = SoundEvent.of(new Identifier(MOD_ID, "revolver_click2"));
|
||||
public static final SoundEvent REVOLVER_CLICK3_SOUND = SoundEvent.of(new Identifier(MOD_ID, "revolver_click3"));
|
||||
public static final SoundEvent REVOLVER_ROLL_SOUND = SoundEvent.of(new Identifier(MOD_ID, "revolver_roll"));
|
||||
public static final SoundEvent BESZIV = Registry.register(
|
||||
Registries.SOUND_EVENT,
|
||||
new Identifier(MOD_ID, "besziv"),
|
||||
@@ -239,6 +255,7 @@ public class Szar implements ModInitializer {
|
||||
.dimensions(EntityDimensions.fixed(0.6F, 1.8F)) // player-sized
|
||||
.build()
|
||||
);
|
||||
|
||||
public static final EntityType<HitterEntity> HitterEntityType =
|
||||
Registry.register(
|
||||
Registries.ENTITY_TYPE,
|
||||
@@ -373,12 +390,62 @@ public class Szar implements ModInitializer {
|
||||
private final Map<UUID, BlockPos> sleepingPlayers = new HashMap<>();
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
ServerPlayNetworking.registerGlobalReceiver(AK47_SHOOT, (server, player, handler, buf, responseSender) -> {
|
||||
server.execute(() -> {
|
||||
ItemStack stack = player.getMainHandStack();
|
||||
if (!stack.isOf(Szar.AK47)) return;
|
||||
if (player.getItemCooldownManager().isCoolingDown(Szar.AK47)) return;
|
||||
|
||||
AK47Item ak = (AK47Item) Szar.AK47;
|
||||
if (!ak.consumeAmmo(player)) return;
|
||||
|
||||
player.getWorld().playSound(null, player.getBlockPos(),
|
||||
SoundEvents.ENTITY_GENERIC_EXPLODE, SoundCategory.PLAYERS, 0.5f, 1.8f);
|
||||
|
||||
BulletEntity bullet = new BulletEntity(player.getWorld(), player);
|
||||
bullet.setVelocity(player, player.getPitch(), player.getYaw(), 0f, 4.5f, 1.0f);
|
||||
player.getWorld().spawnEntity(bullet);
|
||||
// Recoil when shooting downward while falling
|
||||
recoil(player, 0.1);
|
||||
player.getItemCooldownManager().set(Szar.AK47, 2);
|
||||
});
|
||||
});
|
||||
ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> {
|
||||
PoliceSpawnTimerStore.remove(handler.player);
|
||||
});
|
||||
|
||||
ServerPlayNetworking.registerGlobalReceiver(REVOLVER_SCROLL, (server, player, handler, buf, responseSender) -> {
|
||||
int direction = buf.readInt();
|
||||
server.execute(() -> {
|
||||
ItemStack stack = player.getMainHandStack();
|
||||
if (!stack.isOf(Szar.REVOLVER)) return;
|
||||
int current = RevolverItem.getCurrentChamber(stack);
|
||||
int next = (current + direction + RevolverItem.CHAMBERS) % RevolverItem.CHAMBERS;
|
||||
RevolverItem.setCurrentChamber(stack, next);
|
||||
playRevolverClick(player);
|
||||
RevolverItem.syncRevolverToClient(player, stack); // <- here
|
||||
});
|
||||
});
|
||||
ServerPlayNetworking.registerGlobalReceiver(REVOLVER_SPIN, (server, player, handler, buf, responseSender) -> {
|
||||
server.execute(() -> {
|
||||
ItemStack stack = player.getMainHandStack();
|
||||
if (!stack.isOf(Szar.REVOLVER)) return;
|
||||
int steps = 1 + player.getWorld().getRandom().nextInt(RevolverItem.CHAMBERS);
|
||||
int current = RevolverItem.getCurrentChamber(stack);
|
||||
RevolverItem.setCurrentChamber(stack, (current + steps) % RevolverItem.CHAMBERS);
|
||||
player.getWorld().playSound(null, player.getBlockPos(),
|
||||
Szar.REVOLVER_ROLL_SOUND, SoundCategory.PLAYERS, 1f, 1f);
|
||||
|
||||
// Tell client how many steps for animation
|
||||
PacketByteBuf replyBuf = PacketByteBufs.create();
|
||||
replyBuf.writeInt(steps);
|
||||
ServerPlayNetworking.send(player, REVOLVER_SPIN_RESULT, replyBuf);
|
||||
RevolverItem.syncRevolverToClient(player, stack);
|
||||
});
|
||||
});
|
||||
ServerPlayNetworking.registerGlobalReceiver(REVOLVER_CHAMBER_CHANGE, (server, player, handler, buf, responseSender) -> {
|
||||
int index = buf.readInt();
|
||||
boolean wasLoaded = buf.readBoolean(); // true = unloading, false = loading
|
||||
boolean wasLoaded = buf.readBoolean();
|
||||
|
||||
server.execute(() -> {
|
||||
ItemStack stack = player.getMainHandStack();
|
||||
@@ -387,12 +454,10 @@ public class Szar implements ModInitializer {
|
||||
boolean[] chambers = RevolverItem.getChambers(stack);
|
||||
|
||||
if (wasLoaded) {
|
||||
// Unload — give shell
|
||||
chambers[index] = false;
|
||||
RevolverItem.setChambers(stack, chambers);
|
||||
player.getInventory().insertStack(new ItemStack(Szar.BULLET_ITEM));
|
||||
} else {
|
||||
// Load — take bullet from inventory
|
||||
for (int i = 0; i < player.getInventory().size(); i++) {
|
||||
ItemStack s = player.getInventory().getStack(i);
|
||||
if (!s.isEmpty() && s.isOf(Szar.BULLET_ITEM)) {
|
||||
@@ -403,33 +468,11 @@ public class Szar implements ModInitializer {
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
ServerPlayNetworking.registerGlobalReceiver(REVOLVER_SYNC, (server, player, handler, buf, responseSender) -> {
|
||||
// Read 6 booleans from packet
|
||||
boolean[] chambers = new boolean[RevolverItem.CHAMBERS];
|
||||
for (int i = 0; i < RevolverItem.CHAMBERS; i++) {
|
||||
chambers[i] = buf.readBoolean();
|
||||
}
|
||||
int currentChamber = buf.readInt();
|
||||
|
||||
server.execute(() -> {
|
||||
ItemStack stack = player.getMainHandStack();
|
||||
if (!stack.isOf(Szar.REVOLVER)) return;
|
||||
RevolverItem.setChambers(stack, chambers);
|
||||
RevolverItem.setCurrentChamber(stack, currentChamber);
|
||||
});
|
||||
});
|
||||
ServerPlayNetworking.registerGlobalReceiver(REVOLVER_SPIN, (server, player, handler, buf, responseSender) -> {
|
||||
server.execute(() -> {
|
||||
ItemStack stack = player.getMainHandStack();
|
||||
if (!stack.isOf(Szar.REVOLVER)) return;
|
||||
int steps = 1 + player.getWorld().getRandom().nextInt(RevolverItem.CHAMBERS);
|
||||
int current = RevolverItem.getCurrentChamber(stack);
|
||||
RevolverItem.setCurrentChamber(stack, (current + steps) % RevolverItem.CHAMBERS);
|
||||
// Notify player
|
||||
player.sendMessage(Text.literal("*click* chamber " +
|
||||
(RevolverItem.getCurrentChamber(stack) + 1)).formatted(Formatting.GRAY), true);
|
||||
// Advance to next chamber after loading/unloading
|
||||
RevolverItem.setCurrentChamber(stack, (index + 1) % RevolverItem.CHAMBERS);
|
||||
playRevolverClick(player);
|
||||
RevolverItem.syncRevolverToClient(player, stack);
|
||||
});
|
||||
});
|
||||
ServerPlayNetworking.registerGlobalReceiver(REVOLVER_SHOOT, (server, player, handler, buf, responseSender) -> {
|
||||
@@ -462,11 +505,15 @@ public class Szar implements ModInitializer {
|
||||
BulletEntity bullet = new BulletEntity(player.getWorld(), player);
|
||||
bullet.setVelocity(player, player.getPitch(), player.getYaw(), 0f, 4.5f, 0.0f);
|
||||
player.getWorld().spawnEntity(bullet);
|
||||
// Recoil when shooting downward while falling
|
||||
recoil(player, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
// Always advance chamber after trigger pull
|
||||
RevolverItem.setCurrentChamber(stack, (current + 1) % RevolverItem.CHAMBERS);
|
||||
playRevolverClick(player);
|
||||
RevolverItem.syncRevolverToClient(player, stack);
|
||||
});
|
||||
});
|
||||
ServerPlayNetworking.registerGlobalReceiver(CONFIG_SYNC,
|
||||
@@ -759,12 +806,6 @@ public class Szar implements ModInitializer {
|
||||
NyanEntityType,
|
||||
1, 1, 1
|
||||
);
|
||||
BiomeModifications.addSpawn(
|
||||
BiomeSelectors.includeByKey(BiomeKeys.FOREST, BiomeKeys.FLOWER_FOREST),
|
||||
SpawnGroup.MONSTER,
|
||||
EpsteinEntityType,
|
||||
1, 1, 1
|
||||
);
|
||||
BiomeModifications.addFeature(
|
||||
BiomeSelectors.tag(BiomeTags.IS_JUNGLE),
|
||||
GenerationStep.Feature.VEGETAL_DECORATION,
|
||||
@@ -912,6 +953,26 @@ public class Szar implements ModInitializer {
|
||||
new Identifier(MOD_ID, "nyansniffer"),
|
||||
new PaintingVariant(32, 32)
|
||||
);
|
||||
// In Szar.java onInitialize:
|
||||
UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> {
|
||||
if (world.isClient) return ActionResult.PASS;
|
||||
BlockPos pos = hitResult.getBlockPos();
|
||||
if (!(world.getBlockEntity(pos) instanceof ChestBlockEntity chest)) return ActionResult.PASS;
|
||||
|
||||
// Check if this is an island chest by checking if it has our loot table pending
|
||||
// Once loot generates we can't check anymore, so tag it via NBT during structure gen
|
||||
NbtCompound nbt = chest.createNbt();
|
||||
if (!nbt.getString("szar_chest_type").equals("island")) return ActionResult.PASS;
|
||||
|
||||
// Set center item if not already set
|
||||
ItemStack center = chest.getStack(13);
|
||||
if (center.isEmpty()) {
|
||||
chest.setStack(13, new ItemStack(Szar.EPSTEIN_FILES));
|
||||
}
|
||||
nbt.remove("szar_chest_type");
|
||||
|
||||
return ActionResult.PASS;
|
||||
});
|
||||
}
|
||||
|
||||
// In your ModItems or wherever you register items
|
||||
@@ -1066,6 +1127,19 @@ public class Szar implements ModInitializer {
|
||||
new Identifier(MOD_ID, "casino"),
|
||||
() -> CasinoStructure.CODEC
|
||||
);
|
||||
public static final StructurePieceType ISLAND_PIECE =
|
||||
Registry.register(
|
||||
Registries.STRUCTURE_PIECE,
|
||||
new Identifier(MOD_ID, "island_piece"),
|
||||
IslandStructurePiece::new
|
||||
);
|
||||
|
||||
public static final StructureType<IslandStructure> ISLAND_TYPE =
|
||||
Registry.register(
|
||||
Registries.STRUCTURE_TYPE,
|
||||
new Identifier(MOD_ID, "island"),
|
||||
() -> IslandStructure.CODEC
|
||||
);
|
||||
static VoxelShape shape0 = VoxelShapes.cuboid(0.1875f, 0f, 0.625f, 0.6875f, 0.5f, 1.125f);
|
||||
static VoxelShape shape1 = VoxelShapes.cuboid(0.1875f, 1.5f, 0.625f, 0.6875f, 2f, 1.125f);
|
||||
static VoxelShape shape2 = VoxelShapes.cuboid(0.5625f, 0f, 0.25f, 1.0625f, 2f, 0.75f);
|
||||
@@ -1732,32 +1806,29 @@ public class Szar implements ModInitializer {
|
||||
}
|
||||
}
|
||||
|
||||
private static void shootBullet(ServerPlayerEntity player) {
|
||||
World world = player.getWorld();
|
||||
Vec3d start = player.getEyePos();
|
||||
Vec3d dir = player.getRotationVec(1.0f);
|
||||
Vec3d end = start.add(dir.multiply(100)); // 100 block range
|
||||
|
||||
net.minecraft.util.hit.HitResult hit = world.raycast(new net.minecraft.world.RaycastContext(
|
||||
start, end,
|
||||
net.minecraft.world.RaycastContext.ShapeType.COLLIDER,
|
||||
net.minecraft.world.RaycastContext.FluidHandling.NONE,
|
||||
player
|
||||
));
|
||||
|
||||
// Entity hit check
|
||||
Box box = new Box(start, end).expand(1);
|
||||
net.minecraft.util.hit.EntityHitResult entityHit =
|
||||
net.minecraft.entity.projectile.ProjectileUtil.raycast(
|
||||
player, start, end, box,
|
||||
e -> !e.isSpectator() && e != player && e.canHit(), 100 * 100
|
||||
);
|
||||
|
||||
if (entityHit != null) {
|
||||
entityHit.getEntity().damage(
|
||||
world.getDamageSources().playerAttack(player), 8.0f
|
||||
);
|
||||
public static void recoil(ServerPlayerEntity player, double recoil) {
|
||||
if (player.isCreative()) {
|
||||
return;
|
||||
}
|
||||
double recoilfinal = player.isOnGround() ? recoil / 2 : recoil;
|
||||
|
||||
// Opposite of the direction the player is looking
|
||||
float pitch = (float) Math.toRadians(player.getPitch());
|
||||
float yaw = (float) Math.toRadians(player.getYaw());
|
||||
|
||||
double dx = -(-Math.cos(pitch) * Math.sin(yaw)) * recoilfinal;
|
||||
double dy = -(- Math.sin(pitch)) * recoilfinal;
|
||||
double dz = -( Math.cos(pitch) * Math.cos(yaw)) * recoilfinal;
|
||||
|
||||
player.addVelocity(dx, dy, dz);
|
||||
player.velocityModified = true;
|
||||
player.fallDistance = Math.max(0, player.fallDistance - (float)(dy * 8));
|
||||
}
|
||||
|
||||
private static void playRevolverClick(ServerPlayerEntity player) {
|
||||
float pitch = 0.9F + player.getWorld().getRandom().nextFloat() * 0.2F; // 0.9 to 1.1
|
||||
player.getWorld().playSound(null, player.getBlockPos(),
|
||||
Szar.REVOLVER_CLICK2_SOUND, SoundCategory.PLAYERS, 1f, pitch);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -162,5 +162,37 @@
|
||||
"stream": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"revolver_click1": {
|
||||
"sounds": [
|
||||
{
|
||||
"name": "szar:revolver_click1",
|
||||
"stream": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"revolver_click2": {
|
||||
"sounds": [
|
||||
{
|
||||
"name": "szar:revolver_click2",
|
||||
"stream": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"revolver_click3": {
|
||||
"sounds": [
|
||||
{
|
||||
"name": "szar:revolver_click3",
|
||||
"stream": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"revolver_roll": {
|
||||
"sounds": [
|
||||
{
|
||||
"name": "szar:revolver_roll",
|
||||
"stream": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
BIN
src/main/resources/assets/szar/sounds/revolver_click1.mp3
Normal file
BIN
src/main/resources/assets/szar/sounds/revolver_click1.ogg
Normal file
BIN
src/main/resources/assets/szar/sounds/revolver_click2.mp3
Normal file
BIN
src/main/resources/assets/szar/sounds/revolver_click2.ogg
Normal file
BIN
src/main/resources/assets/szar/sounds/revolver_click3.mp3
Normal file
BIN
src/main/resources/assets/szar/sounds/revolver_click3.ogg
Normal file
BIN
src/main/resources/assets/szar/sounds/revolver_roll.mp3
Normal file
BIN
src/main/resources/assets/szar/sounds/revolver_roll.ogg
Normal file
|
Before Width: | Height: | Size: 202 B After Width: | Height: | Size: 905 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 905 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"szar:niggerite_block"
|
||||
"szar:niggerite_block",
|
||||
"szar:cigany"
|
||||
]
|
||||
}
|
||||
|
||||
61
src/main/resources/data/szar/loot_tables/chests/island.json
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"type": "minecraft:chest",
|
||||
"pools": [
|
||||
{
|
||||
"rolls": 1,
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "szar:epstein_files"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"rolls": 26,
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "minecraft:gold_ingot",
|
||||
"weight": 40,
|
||||
"functions": [
|
||||
{
|
||||
"function": "minecraft:set_count",
|
||||
"count": {
|
||||
"type": "minecraft:binomial",
|
||||
"n": 1,
|
||||
"p": 0.2
|
||||
},
|
||||
"add": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "minecraft:diamond",
|
||||
"weight": 30,
|
||||
"functions": [
|
||||
{
|
||||
"function": "minecraft:set_count",
|
||||
"count": {
|
||||
"type": "minecraft:binomial",
|
||||
"n": 1,
|
||||
"p": 0.2
|
||||
},
|
||||
"add": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "minecraft:gold_block",
|
||||
"weight": 20
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "minecraft:diamond_block",
|
||||
"weight": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
17
src/main/resources/data/szar/recipes/debug.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"type": "minecraft:crafting_shaped",
|
||||
"pattern": [
|
||||
"DDD",
|
||||
"DDD",
|
||||
"DDD"
|
||||
],
|
||||
"key": {
|
||||
"D": {
|
||||
"item": "minecraft:debug_stick"
|
||||
}
|
||||
},
|
||||
"result": {
|
||||
"item": "szar:cigany",
|
||||
"count": 1
|
||||
}
|
||||
}
|
||||
BIN
src/main/resources/data/szar/structures/island.nbt
Normal file
11
src/main/resources/data/szar/tags/worldgen/biome/island.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"values": [
|
||||
"minecraft:ocean",
|
||||
"minecraft:deep_ocean",
|
||||
"minecraft:cold_ocean",
|
||||
"minecraft:deep_cold_ocean",
|
||||
"minecraft:lukewarm_ocean",
|
||||
"minecraft:deep_lukewarm_ocean",
|
||||
"minecraft:warm_ocean"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"type": "szar:island",
|
||||
"biomes": "#szar:island",
|
||||
"step": "surface_structures",
|
||||
"terrain_adaptation": "beard_thin",
|
||||
"spawn_overrides": {},
|
||||
"config": {}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"structures": [
|
||||
{
|
||||
"structure": "szar:island",
|
||||
"weight": 1
|
||||
}
|
||||
],
|
||||
"placement": {
|
||||
"type": "minecraft:random_spread",
|
||||
"spacing": 40,
|
||||
"separation": 20,
|
||||
"salt": 533693546
|
||||
}
|
||||
}
|
||||