Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/main/java/xyz/nucleoid/spleef/Spleef.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import xyz.nucleoid.plasmid.game.GameType;
import xyz.nucleoid.spleef.game.SpleefConfig;
import xyz.nucleoid.spleef.game.SpleefWaiting;
import xyz.nucleoid.spleef.game.action.*;
import xyz.nucleoid.spleef.game.map.shape.renderer.*;

public final class Spleef implements ModInitializer {
Expand All @@ -31,5 +32,11 @@ public void onInitialize() {
MapShapeRenderer.REGISTRY.register(new Identifier(Spleef.ID, "square"), SquareShapeRenderer.CODEC);
MapShapeRenderer.REGISTRY.register(new Identifier(Spleef.ID, "sierpinski_carpet"), SierpinskiCarpetShapeRenderer.CODEC);
MapShapeRenderer.REGISTRY.register(new Identifier(Spleef.ID, "pattern"), PatternShapeRenderer.CODEC);

BlockAction.REGISTRY.register(new Identifier(Spleef.ID, "add_status_effect"), AddStatusEffectBlockAction.CODEC);
BlockAction.REGISTRY.register(new Identifier(Spleef.ID, "give_item_stack"), GiveItemStackBlockAction.CODEC);
BlockAction.REGISTRY.register(new Identifier(Spleef.ID, "restock_projectile"), RestockProjectileBlockAction.CODEC);
BlockAction.REGISTRY.register(new Identifier(Spleef.ID, "send_message"), SendMessageBlockAction.CODEC);
BlockAction.REGISTRY.register(new Identifier(Spleef.ID, "sequence"), SequenceBlockAction.CODEC);
}
}
36 changes: 28 additions & 8 deletions src/main/java/xyz/nucleoid/spleef/game/SpleefActive.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
import xyz.nucleoid.plasmid.game.player.PlayerOfferResult;
import xyz.nucleoid.plasmid.game.rule.GameRuleType;
import xyz.nucleoid.spleef.Spleef;
import xyz.nucleoid.spleef.game.action.BlockAction;
import xyz.nucleoid.spleef.game.map.SpleefMap;
import xyz.nucleoid.stimuli.event.block.BlockBreakEvent;
import xyz.nucleoid.stimuli.event.player.PlayerDamageEvent;
import xyz.nucleoid.stimuli.event.player.PlayerDeathEvent;
import xyz.nucleoid.stimuli.event.projectile.ProjectileHitEvent;
Expand Down Expand Up @@ -84,6 +86,7 @@ public static void open(GameSpace gameSpace, ServerWorld world, SpleefMap map, S

activity.listen(GamePlayerEvents.OFFER, active::offerPlayer);

activity.listen(BlockBreakEvent.EVENT, active::onBlockBreak);
activity.listen(ProjectileHitEvent.BLOCK, active::onBlockHit);

activity.listen(PlayerDamageEvent.EVENT, active::onPlayerDamage);
Expand Down Expand Up @@ -156,7 +159,7 @@ private void tick() {
var projectiles = this.config.projectile();
if (time > this.restockTime && projectiles != null) {
if (this.restockTime != -1) {
this.restockProjectiles(projectiles);
this.restockProjectiles();
}

this.restockTime = time + projectiles.restockInterval();
Expand All @@ -175,16 +178,22 @@ private void tickClosing(GameSpace gameSpace, long time) {
}
}

private void restockProjectiles(ProjectileConfig projectileConfig) {
private void restockProjectiles() {
for (var player : this.gameSpace.getPlayers()) {
this.restockProjectileFor(player);
}
}

public void restockProjectileFor(ServerPlayerEntity player) {
if (player.isSpectator()) return;

var projectileConfig = this.config.projectile();
var projectileStack = projectileConfig.stack();

for (var player : this.gameSpace.getPlayers()) {
if (player.isSpectator()) continue;
if (player.getInventory().count(projectileStack.getItem()) >= projectileConfig.maximum()) continue;
if (player.getInventory().count(projectileStack.getItem()) >= projectileConfig.maximum()) return;

player.getInventory().insertStack(projectileStack.copy());
player.playSound(SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.PLAYERS, 1, 1);
}
player.getInventory().insertStack(projectileStack.copy());
player.playSound(SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.PLAYERS, 1, 1);
}

private void breakFloorBlock(BlockPos pos) {
Expand All @@ -193,6 +202,17 @@ private void breakFloorBlock(BlockPos pos) {
}
}

private ActionResult onBlockBreak(ServerPlayerEntity player, ServerWorld world, BlockPos pos) {
var block = world.getBlockState(pos).getBlock();
var action = this.config.blockBreakActions().get(block);

if (action != null) {
BlockAction.apply(action, player, this.gameSpace.getPlayers(), this);
}

return ActionResult.PASS;
}

private ActionResult onBlockHit(ProjectileEntity entity, BlockHitResult hitResult) {
var projectiles = this.config.projectile();
if (projectiles == null) return ActionResult.FAIL;
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/xyz/nucleoid/spleef/game/SpleefConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.block.Block;
import net.minecraft.registry.Registries;
import net.minecraft.util.dynamic.Codecs;
import org.jetbrains.annotations.Nullable;
import xyz.nucleoid.plasmid.game.common.config.PlayerConfig;
import xyz.nucleoid.spleef.game.action.BlockAction;
import xyz.nucleoid.spleef.game.map.SpleefGeneratedMapConfig;
import xyz.nucleoid.spleef.game.map.SpleefTemplateMapConfig;

import java.util.Collections;
import java.util.Map;
import java.util.Optional;

public record SpleefConfig(
Expand All @@ -17,6 +22,7 @@ public record SpleefConfig(
ToolConfig tool,
@Nullable ProjectileConfig projectile,
@Nullable LavaRiseConfig lavaRise,
Map<Block, BlockAction> blockBreakActions,
long levelBreakInterval,
int decay,
int timeOfDay,
Expand All @@ -28,6 +34,7 @@ public record SpleefConfig(
ToolConfig.CODEC.optionalFieldOf("tool", ToolConfig.DEFAULT).forGetter(SpleefConfig::tool),
ProjectileConfig.CODEC.optionalFieldOf("projectile").forGetter(config -> Optional.ofNullable(config.projectile())),
LavaRiseConfig.CODEC.optionalFieldOf("lava_rise").forGetter(config -> Optional.ofNullable(config.lavaRise())),
Codec.unboundedMap(Registries.BLOCK.getCodec(), BlockAction.REGISTRY_CODEC).optionalFieldOf("block_break_actions", Collections.emptyMap()).forGetter(SpleefConfig::blockBreakActions),
Codec.LONG.optionalFieldOf("level_break_interval", 20L * 60).forGetter(SpleefConfig::levelBreakInterval),
Codec.INT.optionalFieldOf("decay", -1).forGetter(SpleefConfig::decay),
Codec.INT.optionalFieldOf("time_of_day", 6000).forGetter(SpleefConfig::timeOfDay),
Expand All @@ -40,6 +47,7 @@ private SpleefConfig(
ToolConfig tool,
Optional<ProjectileConfig> projectile,
Optional<LavaRiseConfig> lavaRise,
Map<Block, BlockAction> blockBreakActions,
long levelBreakInterval,
int decay,
int timeOfDay,
Expand All @@ -49,6 +57,7 @@ private SpleefConfig(
map, players, tool,
projectile.orElse(null),
lavaRise.orElse(null),
blockBreakActions,
levelBreakInterval, decay,
timeOfDay,
unstableTnt
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package xyz.nucleoid.spleef.game.action;

import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.server.network.ServerPlayerEntity;
import xyz.nucleoid.codecs.MoreCodecs;

public record AddStatusEffectBlockAction(StatusEffectInstance effect, BlockActionTarget target) implements BlockAction {
private static final Codec<StatusEffectInstance> STATUS_EFFECT_CODEC = MoreCodecs.withNbt(effect -> effect.writeNbt(new NbtCompound()), nbt -> {
if (nbt instanceof NbtCompound compound) {
var effect = StatusEffectInstance.fromNbt(compound);

if (effect == null) {
return DataResult.error(() -> "Unknown status effect ID");
} else {
return DataResult.success(effect);
}
}

return DataResult.error(() -> "Expected compound tag");
});

public static final Codec<AddStatusEffectBlockAction> CODEC = RecordCodecBuilder.create(instance -> {
return instance.group(
STATUS_EFFECT_CODEC.fieldOf("effect").forGetter(AddStatusEffectBlockAction::effect),
BlockActionTarget.CODEC.fieldOf("target").forGetter(AddStatusEffectBlockAction::target)
).apply(instance, AddStatusEffectBlockAction::new);
});

@Override
public void apply(ServerPlayerEntity player, BlockActionContext context) {
player.addStatusEffect(new StatusEffectInstance(this.effect), player);
}

@Override
public Codec<AddStatusEffectBlockAction> getCodec() {
return CODEC;
}
}
28 changes: 28 additions & 0 deletions src/main/java/xyz/nucleoid/spleef/game/action/BlockAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package xyz.nucleoid.spleef.game.action;

import com.mojang.serialization.Codec;
import net.minecraft.server.network.ServerPlayerEntity;
import xyz.nucleoid.plasmid.game.player.PlayerSet;
import xyz.nucleoid.plasmid.registry.TinyRegistry;
import xyz.nucleoid.spleef.game.SpleefActive;

import java.util.function.Function;

public interface BlockAction {
TinyRegistry<Codec<? extends BlockAction>> REGISTRY = TinyRegistry.create();
Codec<BlockAction> REGISTRY_CODEC = REGISTRY.dispatchMap(BlockAction::getCodec, Function.identity()).codec();

public void apply(ServerPlayerEntity player, BlockActionContext context);

public BlockActionTarget target();

Codec<? extends BlockAction> getCodec();

public static void apply(BlockAction action, ServerPlayerEntity self, PlayerSet players, SpleefActive game) {
var context = new BlockActionContext(self, players, game);

action.target().forEachTarget(context, player -> {
action.apply(player, context);
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package xyz.nucleoid.spleef.game.action;

import net.minecraft.server.network.ServerPlayerEntity;
import xyz.nucleoid.plasmid.game.player.PlayerSet;
import xyz.nucleoid.spleef.game.SpleefActive;

public record BlockActionContext(ServerPlayerEntity self, PlayerSet players, SpleefActive game) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package xyz.nucleoid.spleef.game.action;

import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.StringIdentifiable;

import java.util.function.Consumer;

public enum BlockActionTarget implements StringIdentifiable {
SELF("self"),
OTHERS("others"),
ALL("all")
;

public static final com.mojang.serialization.Codec<BlockActionTarget> CODEC = StringIdentifiable.createCodec(BlockActionTarget::values);

public final String name;

BlockActionTarget(String name) {
this.name = name;
}

public void forEachTarget(BlockActionContext context, Consumer<ServerPlayerEntity> consumer) {
if (this == SELF) {
consumer.accept(context.self());
return;
}

context.players().stream()
.filter(player -> {
if (this == OTHERS && player == context.self()) {
return false;
}

return !player.isSpectator();
})
.forEach(consumer);
}

public String asString() {
return this.name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package xyz.nucleoid.spleef.game.action;

import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.item.ItemStack;
import net.minecraft.server.network.ServerPlayerEntity;

public record GiveItemStackBlockAction(ItemStack stack, BlockActionTarget target) implements BlockAction {
public static final Codec<GiveItemStackBlockAction> CODEC = RecordCodecBuilder.create(instance -> {
return instance.group(
ItemStack.CODEC.fieldOf("stack").forGetter(GiveItemStackBlockAction::stack),
BlockActionTarget.CODEC.fieldOf("target").forGetter(GiveItemStackBlockAction::target)
).apply(instance, GiveItemStackBlockAction::new);
});

@Override
public void apply(ServerPlayerEntity player, BlockActionContext context) {
player.giveItemStack(this.stack.copy());
}

@Override
public Codec<GiveItemStackBlockAction> getCodec() {
return CODEC;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package xyz.nucleoid.spleef.game.action;

import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.server.network.ServerPlayerEntity;

public record RestockProjectileBlockAction(BlockActionTarget target) implements BlockAction {
public static final Codec<RestockProjectileBlockAction> CODEC = RecordCodecBuilder.create(instance -> {
return instance.group(
BlockActionTarget.CODEC.fieldOf("target").forGetter(RestockProjectileBlockAction::target)
).apply(instance, RestockProjectileBlockAction::new);
});

@Override
public void apply(ServerPlayerEntity player, BlockActionContext context) {
context.game().restockProjectileFor(player);
}

@Override
public Codec<RestockProjectileBlockAction> getCodec() {
return CODEC;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package xyz.nucleoid.spleef.game.action;

import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import xyz.nucleoid.plasmid.util.PlasmidCodecs;

public record SendMessageBlockAction(Text message, boolean overlay, BlockActionTarget target) implements BlockAction {
public static final Codec<SendMessageBlockAction> CODEC = RecordCodecBuilder.create(instance -> {
return instance.group(
PlasmidCodecs.TEXT.fieldOf("message").forGetter(SendMessageBlockAction::message),
Codec.BOOL.optionalFieldOf("overlay", false).forGetter(SendMessageBlockAction::overlay),
BlockActionTarget.CODEC.fieldOf("target").forGetter(SendMessageBlockAction::target)
).apply(instance, SendMessageBlockAction::new);
});

@Override
public void apply(ServerPlayerEntity player, BlockActionContext context) {
player.sendMessage(this.message, this.overlay);
}

@Override
public Codec<SendMessageBlockAction> getCodec() {
return CODEC;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package xyz.nucleoid.spleef.game.action;

import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.server.network.ServerPlayerEntity;

import java.util.List;

public record SequenceBlockAction(List<BlockAction> actions) implements BlockAction {
public static final Codec<SequenceBlockAction> CODEC = RecordCodecBuilder.create(instance -> {
return instance.group(
BlockAction.REGISTRY_CODEC.listOf().fieldOf("actions").forGetter(SequenceBlockAction::actions)
).apply(instance, SequenceBlockAction::new);
});

@Override
public void apply(ServerPlayerEntity player, BlockActionContext context) {
for (var action : this.actions) {
action.target().forEachTarget(context, playerx -> {
action.apply(player, context);
});
}
}

public BlockActionTarget target() {
return BlockActionTarget.SELF;
}

@Override
public Codec<SequenceBlockAction> getCodec() {
return CODEC;
}
}