Skip to content
This repository has been archived by the owner on Jul 8, 2023. It is now read-only.

Refactor ItemStack and Behavior API #10

Draft
wants to merge 48 commits into
base: bleeding
Choose a base branch
from
Draft
Changes from 1 commit
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
571d41a
Begin implementing DataKey components
SupremeMortal Oct 16, 2021
94496d8
Add more block behaviours
SupremeMortal Oct 17, 2021
d97a36d
Figure out the base implementation for behaviours
SupremeMortal Oct 23, 2021
e6c6e4a
Remove BlockState#getBehavior and references
SupremeMortal Oct 23, 2021
e8bd5ed
Use executor generic parameter for Behavior
SupremeMortal Oct 23, 2021
df6bc9c
Correct values for new MaterialTypes
SupremeMortal Oct 23, 2021
6f62f1d
Add some more block behaviors
SupremeMortal Oct 24, 2021
c4d1a28
Some more block behaviours
SupremeMortal Oct 30, 2021
7165773
Refactor some behaviour and block methods
SupremeMortal Oct 30, 2021
bff6559
More refactoring of blocks and items
SupremeMortal Dec 20, 2021
8a72121
Continue working on item behaviours
SupremeMortal Apr 23, 2022
c82026c
Add Vector3i version of AxisAlignedBB#addCoord
SupremeMortal Apr 23, 2022
4b276c5
Add CAN_DESTROY item behaviour
SupremeMortal Apr 23, 2022
dcb8bae
Create MapDataKey for enchantments
SupremeMortal Apr 23, 2022
e578359
Merge branch 'dev/v1.18.30' into refactor/items-and-behavior
ApocalypsjeNL Apr 25, 2022
74be65b
Add checkerframework exclusions
SupremeMortal Apr 25, 2022
d428e86
Fixed a couple of issues and added the Filtered Light block behaviour
ApocalypsjeNL Apr 25, 2022
30576bc
Added ItemLore key
ApocalypsjeNL Apr 26, 2022
8587777
Fixed the ItemRegistry generic type
ApocalypsjeNL Apr 28, 2022
1c0f148
Adding these back works for me
SupremeMortal Apr 28, 2022
3aeb7e5
Expand available item behaviours
SupremeMortal Apr 28, 2022
883713d
Add damage related behaviours
SupremeMortal Apr 28, 2022
f48c7ff
Implement get_map_color block behavior
SupremeMortal Apr 29, 2022
8880902
Added BOOK_DATA item key and increased the compiler error amount
ApocalypsjeNL May 3, 2022
e6de19e
Added resistance behaviour, map item key and ItemStack comparables
ApocalypsjeNL May 3, 2022
6501845
Added attack damage behaviour
ApocalypsjeNL May 4, 2022
8eac701
Added some more behaviours
ApocalypsjeNL May 5, 2022
2d06fea
Updating lombok dependency
ApocalypsjeNL May 7, 2022
66083c4
Replaced lombok non-null check with Google's one
ApocalypsjeNL May 13, 2022
23c2c07
Added a default blockstate to blocks that don't have one provided
ApocalypsjeNL May 13, 2022
ead2197
Use isInstance for behaviour checks
SupremeMortal May 13, 2022
3d75bc4
Refactor block placing
Creeperface01 Jun 13, 2022
351958c
Merge pull request #16 from Creeperface01/refactor/items/block-placing
Creeperface01 Jun 15, 2022
7cb3a1b
Merge remote-tracking branch 'origin/bleeding' into refactor/items-an…
Creeperface01 Jun 15, 2022
0932dae
Fix compilation
Creeperface01 Jun 15, 2022
b53fd2f
Merge remote-tracking branch 'origin/refactor/items-and-behavior' int…
Creeperface01 Jun 15, 2022
5fa59a9
Fix item serialization
Creeperface01 Jul 9, 2022
ef9192e
Fix item serialization
Creeperface01 Jul 9, 2022
e91d2d9
Merge remote-tracking branch 'origin/refactor/items-and-behavior' int…
Creeperface01 Jul 9, 2022
e2f9e75
Merge branch 'bleeding' into refactor/items-and-behavior
SupremeMortal Aug 12, 2022
1c4f070
Add default values for DataKeys
SupremeMortal Aug 12, 2022
9a99e9f
Separate behaviour registration into contextual and not
SupremeMortal Aug 14, 2022
95e5931
Add more behaviours
SupremeMortal Aug 20, 2022
cdc4112
Modularise block breaking
SupremeMortal Aug 20, 2022
0b4d882
Use math 2.0 library
SupremeMortal Nov 26, 2022
131e8cc
Minor changes for protocol v3
SupremeMortal Dec 17, 2022
6d89066
Rename ItemStack `AIR` to `EMPTY`
SupremeMortal Dec 21, 2022
6b6b724
Inventory API changes
SupremeMortal Apr 15, 2023
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
Prev Previous commit
Next Next commit
More refactoring of blocks and items
SupremeMortal committed Dec 20, 2021

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit bff655963b3353801d424bdf80cc60f088d90a43
28 changes: 27 additions & 1 deletion src/main/java/org/cloudburstmc/api/block/BlockBehaviors.java
Original file line number Diff line number Diff line change
@@ -74,6 +74,10 @@ private BlockBehaviors() {

public static final BehaviorKey<TickBlockBehavior, TickBlockBehavior.Executor> ON_RANDOM_TICK = DataKey.behavior(Identifier.fromString("on_random_tick"), TickBlockBehavior.class, TickBlockBehavior.Executor.class);

public static final BehaviorKey<Boolean, Boolean> CAN_RANDOM_TICK = DataKey.behavior(Identifier.fromString("can_random_tick"), Boolean.class);

public static final BehaviorKey<TickBlockBehavior, TickBlockBehavior.Executor> ON_TICK = DataKey.behavior(Identifier.fromString("on_tick"), TickBlockBehavior.class, TickBlockBehavior.Executor.class);

public static final BehaviorKey<UseBlockBehavior, BooleanBlockBehavior.Executor> USE = DataKey.behavior(Identifier.fromString("use"), UseBlockBehavior.class, BooleanBlockBehavior.Executor.class);

public static final BehaviorKey<EntityBlockBehavior, EntityBlockBehavior.Executor> ON_STAND_ON = DataKey.behavior(Identifier.fromString("on_stand_on"), EntityBlockBehavior.class, EntityBlockBehavior.Executor.class);
@@ -86,7 +90,7 @@ private BlockBehaviors() {

public static final BehaviorKey<ResourceBlockBehavior, ResourceBlockBehavior.Executor> GET_SILK_TOUCH_RESOURCE = DataKey.behavior(Identifier.fromString("get_silk_touch_resource"), ResourceBlockBehavior.class, ResourceBlockBehavior.Executor.class);

public static final BehaviorKey<ResourceBlockBehavior, ResourceBlockBehavior.Executor> GET_RESOURCE = DataKey.behavior(Identifier.fromString("get_resource"), ResourceBlockBehavior.class, ResourceBlockBehavior.Executor.class);
public static final BehaviorKey<ResourceBlockBehavior, ResourceBlockBehavior.Executor> GET_RESOURCE_ITEM = DataKey.behavior(Identifier.fromString("get_resource_item"), ResourceBlockBehavior.class, ResourceBlockBehavior.Executor.class);

public static final BehaviorKey<ResourceCountBlockBehavior, ResourceCountBlockBehavior.Executor> GET_RESOURCE_COUNT = DataKey.behavior(Identifier.fromString("get_resource_count"), ResourceCountBlockBehavior.class, ResourceCountBlockBehavior.Executor.class);

@@ -107,4 +111,26 @@ private BlockBehaviors() {
public static final BehaviorKey<Boolean, Boolean> IS_SUPER_HOT = DataKey.behavior(Identifier.fromString("is_super_hot"), Boolean.class);

public static final BehaviorKey<Boolean, Boolean> IS_FLAMMABLE = DataKey.behavior(Identifier.fromString("is_flammable"), Boolean.class);

public static final BehaviorKey<ColorBlockBehavior, ColorBlockBehavior.Executor> GET_COLOR = DataKey.behavior(Identifier.fromString("get_color"), ColorBlockBehavior.class, ColorBlockBehavior.Executor.class);

public static final BehaviorKey<Integer, Integer> GET_LIGHT = DataKey.behavior(Identifier.fromString("get_light"), Integer.class);

public static final BehaviorKey<Boolean, Boolean> IS_ALWAYS_DESTROYABLE = DataKey.behavior(Identifier.fromString("is_always_destroyable"), Boolean.class);

public static final BehaviorKey<Integer, Integer> GET_TICK_DELAY = DataKey.behavior(Identifier.fromString("get_tick_delay"), Integer.class);

public static final BehaviorKey<SurviveBlockBehavior, SurviveBlockBehavior.Executor> CAN_SURVIVE = DataKey.behavior(Identifier.fromString("can_survive"), SurviveBlockBehavior.class, SurviveBlockBehavior.Executor.class);

public static final BehaviorKey<ComplexBlockBehavior, ComplexBlockBehavior.Executor> CHECK_ALIVE = DataKey.behavior(Identifier.fromString("check_alive"), ComplexBlockBehavior.class, ComplexBlockBehavior.Executor.class);

public static final BehaviorKey<Boolean, Boolean> IS_FLOODABLE = DataKey.behavior(Identifier.fromString("is_floodable"), Boolean.class);

public static final BehaviorKey<Boolean, Boolean> CAN_INSTATICK = DataKey.behavior(Identifier.fromString("is_instaticking"), Boolean.class);

public static final BehaviorKey<BooleanBlockBehavior, BooleanBlockBehavior.Executor> CAN_SLIDE = DataKey.behavior(Identifier.fromString("can_slide"), BooleanBlockBehavior.class, BooleanBlockBehavior.Executor.class);

public static final BehaviorKey<BooleanBlockBehavior, BooleanBlockBehavior.Executor> IS_FREE_TO_FALL = DataKey.behavior(Identifier.fromString("is_free_to_fall"), BooleanBlockBehavior.class, BooleanBlockBehavior.Executor.class);

public static final BehaviorKey<ComplexBlockBehavior, ComplexBlockBehavior.Executor> START_FALLING = DataKey.behavior(Identifier.fromString("start_falling"), ComplexBlockBehavior.class, ComplexBlockBehavior.Executor.class);
}
8 changes: 2 additions & 6 deletions src/main/java/org/cloudburstmc/api/block/BlockType.java
Original file line number Diff line number Diff line change
@@ -3,13 +3,9 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.api.block.trait.BlockTrait;
import org.cloudburstmc.api.item.ItemStack;
import org.cloudburstmc.api.item.ItemKeys;
import org.cloudburstmc.api.item.ItemType;
import org.cloudburstmc.api.item.TierType;
import org.cloudburstmc.api.item.ToolType;
import org.cloudburstmc.api.util.AxisAlignedBB;
import org.cloudburstmc.api.util.Identifier;

import java.util.*;
@@ -26,7 +22,7 @@ public final class BlockType extends ItemType {
private final BlockState defaultState;

private BlockType(Identifier id, BlockTrait<?>[] traits) {
super(id, null);
super(id, Collections.singleton(ItemKeys.BLOCK_STATE));
this.traits = ImmutableSet.copyOf(traits);
this.states = getPermutations(this, traits);

Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package org.cloudburstmc.api.block.behavior;

import org.cloudburstmc.api.block.BlockState;
import org.cloudburstmc.api.block.Block;
import org.cloudburstmc.api.util.behavior.Behavior;

public interface BooleanBlockBehavior {

boolean test(Behavior<Executor> behavior, BlockState state);
boolean test(Behavior<Executor> behavior, Block block);

@FunctionalInterface
interface Executor {
boolean execute(BlockState state);
boolean execute(Block block);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.cloudburstmc.api.block.behavior;

import org.cloudburstmc.api.block.Block;
import org.cloudburstmc.api.util.behavior.Behavior;
import org.cloudburstmc.api.util.data.BlockColor;

public interface ColorBlockBehavior {

BlockColor execute(Behavior<Executor> behavior, Block block);

@FunctionalInterface
interface Executor {
BlockColor execute(Block block);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.cloudburstmc.api.block.behavior;

import org.cloudburstmc.api.block.Block;
import org.cloudburstmc.api.util.behavior.Behavior;

public interface SurviveBlockBehavior {

boolean canSurvive(Behavior<Executor> behavior, Block block);

@FunctionalInterface
interface Executor {
boolean execute(Block block);
}
}
9 changes: 9 additions & 0 deletions src/main/java/org/cloudburstmc/api/item/ItemKeys.java
Original file line number Diff line number Diff line change
@@ -5,13 +5,22 @@
import org.cloudburstmc.api.data.ListDataKey;
import org.cloudburstmc.api.data.SimpleDataKey;
import org.cloudburstmc.api.enchantment.Enchantment;
import org.cloudburstmc.api.item.data.Bucket;
import org.cloudburstmc.api.util.Identifier;
import org.cloudburstmc.api.util.data.DyeColor;
import org.cloudburstmc.api.util.data.FireworkData;

public final class ItemKeys {

public static final SimpleDataKey<BlockState> BLOCK_STATE = DataKey.simple(Identifier.fromString("block_state"), BlockState.class);

public static final SimpleDataKey<Integer> DAMAGE = DataKey.simple(Identifier.fromString("item_damage"), Integer.class);

public static final SimpleDataKey<DyeColor> COLOR = DataKey.simple(Identifier.fromString("dye_color"), DyeColor.class);

public static final ListDataKey<Enchantment> ENCHANTMENTS = DataKey.list(Identifier.fromString("enchantments"), Enchantment.class);

public static final SimpleDataKey<FireworkData> FIREWORK_DATA = DataKey.simple(Identifier.fromString("firework_data"), FireworkData.class);

public static final SimpleDataKey<Bucket> BUCKET_DATA = DataKey.simple(Identifier.fromString("bucket_data"), Bucket.class);
}
43 changes: 40 additions & 3 deletions src/main/java/org/cloudburstmc/api/item/ItemStack.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
package org.cloudburstmc.api.item;

import com.google.common.collect.ImmutableMap;
import com.nukkitx.math.GenericMath;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.checker.index.qual.NonNegative;
import org.cloudburstmc.api.block.BlockState;
import org.cloudburstmc.api.block.BlockTypes;
import org.cloudburstmc.api.data.DataKey;
import org.cloudburstmc.api.data.DataStore;

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

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

public final class ItemStack implements DataStore, Comparable<ItemStack> {

public static final ItemStack AIR = new ItemStack(BlockTypes.AIR, 0, Collections.emptyMap());

private final ItemType type;
private final int amount;
private final ImmutableMap<DataKey<?, ?>, ?> metadata;
@@ -27,6 +31,35 @@ public static ItemStackBuilder builder() {
return new ItemStackBuilder(null, 1, Collections.emptyMap());
}

public static ItemStackBuilder builder(BlockState state) {
return new ItemStackBuilder(state.getType(), 1, Collections.emptyMap())
.data(ItemKeys.BLOCK_STATE, state);
}

public static ItemStackBuilder builder(ItemType type) {
return new ItemStackBuilder(type, 1, Collections.emptyMap());
}

public static ItemStack from(BlockState state) {
return from(state, 1);
}

public static ItemStack from(BlockState state, @NonNegative int amount) {
checkNotNull(state, "state");
checkArgument(amount > 0, "Amount cannot be negative");
return new ItemStack(state.getType(), amount, Map.of(ItemKeys.BLOCK_STATE, state));
}

public static ItemStack from(ItemType type) {
return from(type, 1);
}

public static ItemStack from(ItemType type, @NonNegative int amount) {
checkNotNull(type, "type");
checkArgument(amount > 0, "Amount cannot be negative");
return new ItemStack(type, amount, Collections.emptyMap());
}

public ItemType getType() {
return type;
}
@@ -63,6 +96,10 @@ public <T> T getData(DataKey<T, ?> key) {
return (T) metadata.get(key);
}

public BlockState getBlockState() {
return getData(ItemKeys.BLOCK_STATE);
}

@Override
public int compareTo(ItemStack other) {
if (other.getType().equals(this.getType())) {
25 changes: 10 additions & 15 deletions src/main/java/org/cloudburstmc/api/item/ItemType.java
Original file line number Diff line number Diff line change
@@ -1,34 +1,29 @@
package org.cloudburstmc.api.item;

import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.api.block.BlockType;
import org.cloudburstmc.api.block.trait.BlockTrait;
import org.cloudburstmc.api.data.DataKey;
import org.cloudburstmc.api.util.Identifier;

import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

public sealed class ItemType permits BlockType {

private final Identifier id;
private final Class<?> metadataClass;
private final Set<DataKey<?, ?>> dataKeys;

protected ItemType(Identifier id, Class<?> metadataClass) {
protected ItemType(Identifier id, Set<DataKey<?, ?>> dataKeys) {
this.id = id;
this.metadataClass = metadataClass;
this.dataKeys = dataKeys;
}

public final Identifier getId() {
return id;
}

@Nullable
public final Class<?> getMetadataClass() {
return metadataClass;
public Set<DataKey<?, ?>> getDataKeys() {
return dataKeys;
}

@Override
@@ -37,12 +32,12 @@ public String toString() {
}

public static ItemType of(Identifier id) {
return of(id, null);
return of(id, new DataKey[0]);
}

public static ItemType of(Identifier id, Class<?> metadataClass) {
public static ItemType of(Identifier id, DataKey<?, ?>... dataKeys) {
checkNotNull(id, "id");

return new ItemType(id, metadataClass);
return new ItemType(id, Set.of(dataKeys));
}
}
17 changes: 2 additions & 15 deletions src/main/java/org/cloudburstmc/api/item/ItemTypes.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,7 @@
package org.cloudburstmc.api.item;

import lombok.experimental.UtilityClass;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.api.block.BlockType;
import org.cloudburstmc.api.block.BlockTypes;
import org.cloudburstmc.api.item.data.Bucket;
import org.cloudburstmc.api.item.data.Coal;
import org.cloudburstmc.api.item.data.Damageable;
import org.cloudburstmc.api.util.Identifier;
import org.cloudburstmc.api.util.Identifiers;
import org.cloudburstmc.api.util.data.DyeColor;
import org.cloudburstmc.api.util.data.TreeSpecies;

import java.util.IdentityHashMap;
import java.util.Map;

import static org.cloudburstmc.api.item.TierTypes.*;
import static org.cloudburstmc.api.item.ToolTypes.*;

@UtilityClass
public class ItemTypes {
@@ -256,4 +241,6 @@ public class ItemTypes {
public static final ItemType RAW_IRON = ItemType.of(ItemIds.RAW_IRON); //.build();
public static final ItemType SPYGLASS = ItemType.of(ItemIds.SPYGLASS); //.build();
public static final ItemType COPPER_INGOT = ItemType.of(ItemIds.COPPER_INGOT); //.build();

public static final ItemType LAPIS_LAZULI = ItemType.of(ItemIds.LAPIS_LAZULI);
}
3 changes: 3 additions & 0 deletions src/main/java/org/cloudburstmc/api/level/Level.java
Original file line number Diff line number Diff line change
@@ -210,4 +210,7 @@ default DroppedItem dropItem(Vector3f position, ItemStack item, Vector3f motion,

Set<? extends Entity> getNearbyEntities(AxisAlignedBB bb, Entity entity, boolean loadChunks);

int getMinHeight();

int getMaxHeight();
}
Original file line number Diff line number Diff line change
@@ -3,11 +3,11 @@
import org.cloudburstmc.api.data.BehaviorKey;
import org.cloudburstmc.api.util.behavior.Behavior;

import java.util.function.Function;
import java.util.function.BiFunction;

public interface BehaviorRegistry extends Registry {
public interface BehaviorRegistry {

<T, R> void registerItemBehavior(BehaviorKey<T, R> key, T defaultBehavior, Function<Behavior<R>, R> executorFactory);
<T, R> void registerBehavior(BehaviorKey<T, R> key, T defaultBehavior, BiFunction<Behavior<R>, T, R> executorFactory);

<T, R> void registerBlockBehavior(BehaviorKey<T, R> key, T defaultBehavior, Function<Behavior<R>, R> executorFactory);
<T> T getDefaultBehavior(BehaviorKey<T, ?> key);
}
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@
import org.cloudburstmc.api.util.Identifier;
import org.cloudburstmc.api.util.behavior.BehaviorCollection;

public interface BlockRegistry extends Registry {
public interface BlockRegistry extends BehaviorRegistry {

BehaviorCollection register(BlockType type) throws RegistryException;

Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@
import java.util.List;
import java.util.Set;

public interface GameRuleRegistry extends Registry {
public interface GameRuleRegistry {

<T extends Comparable<T>> void register(GameRule<T> gameRule);

15 changes: 1 addition & 14 deletions src/main/java/org/cloudburstmc/api/registry/ItemRegistry.java
Original file line number Diff line number Diff line change
@@ -1,30 +1,17 @@
package org.cloudburstmc.api.registry;

import com.google.common.collect.ImmutableList;
import org.cloudburstmc.api.block.BlockState;
import org.cloudburstmc.api.item.ItemStack;
import org.cloudburstmc.api.item.ItemType;
import org.cloudburstmc.api.item.behavior.ItemBehavior;
import org.cloudburstmc.api.util.Identifier;

public interface ItemRegistry extends Registry {
public interface ItemRegistry extends BehaviorRegistry {

void register(ItemType type, ItemBehavior behavior, Identifier... identifiers) throws RegistryException;

void registerCreativeItem(ItemStack item);

default ItemStack getItem(BlockState state) throws RegistryException {
return getItem(state, 1);
}

ItemStack getItem(BlockState state, int amount) throws RegistryException;

default ItemStack getItem(ItemType type) throws RegistryException {
return getItem(type, 1);
}

ItemStack getItem(ItemType type, int amount, Object... metadata) throws RegistryException;

Identifier getIdentifier(int runtimeId) throws RegistryException;

ImmutableList<Identifier> getItems();
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@
import java.util.Collection;
import java.util.UUID;

public interface RecipeRegistry extends Registry {
public interface RecipeRegistry {

void register(Recipe recipe) throws RegistryException;

6 changes: 0 additions & 6 deletions src/main/java/org/cloudburstmc/api/registry/Registry.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.cloudburstmc.api.registry;

public interface ResourcePackRegistry extends Registry {
public interface ResourcePackRegistry {
}
22 changes: 22 additions & 0 deletions src/main/java/org/cloudburstmc/api/util/Randoms.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.cloudburstmc.api.util;

import java.util.random.RandomGenerator;

public final class Randoms {

public static int nextInclusiveInt(RandomGenerator random, int min, int max) {
if (min < max + 1) {
min += random.nextInt(max - min + 1);
}
return min;
}

public static boolean chance(RandomGenerator random, int likeliness, int possibilities) {
return possibilities > 0 && (likeliness >= possibilities ||
nextInclusiveInt(random, 1, possibilities) >= likeliness);
}

public static boolean chanceInOne(RandomGenerator random, int possibilities) {
return chance(random, 1, possibilities);
}
}
Original file line number Diff line number Diff line change
@@ -20,5 +20,5 @@ public interface Behavior<T> {
* @param <U> function type
* @return behavior function
*/
<U> U getBehavior(BehaviorKey<?, U> key);
<U> U get(BehaviorKey<?, U> key);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package org.cloudburstmc.api.util.behavior;

import org.cloudburstmc.api.data.BehaviorKey;

import java.util.*;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

public final class BehaviorBuilder {

private final Map<BehaviorKey<?, ?>, List<Object>> behaviors = new IdentityHashMap<>();

private BehaviorBuilder() {
}

public static BehaviorBuilder create() {
return new BehaviorBuilder();
}

public static BehaviorBuilder extend(BehaviorBuilder builder) {
BehaviorBuilder extendedBuilder = new BehaviorBuilder();
extendedBuilder.behaviors.putAll(builder.behaviors);
return extendedBuilder;
}

public <T, R> BehaviorBuilder extend(BehaviorKey<T, R> key, T function) {
checkNotNull(key, "key");
checkNotNull(function, "function");
checkArgument(key.getType() == function.getClass(), "%s does not match expected type of %s for '%s'",
function.getClass(), key.getType(), key.getId());

List<Object> functions = this.behaviors.computeIfAbsent(key, behaviorKey -> {
var list = new ArrayList<>();
list.add(null);
return list;
});

functions.add(function);
return this;
}

public <T, R> BehaviorBuilder overwrite(BehaviorKey<T, R> key, T function) {
checkNotNull(key, "key");
checkNotNull(function, "function");
checkArgument(key.getType() == function.getClass(), "%s does not match expected type of %s for '%s'",
function.getClass(), key.getType(), key.getId());

List<Object> functions = this.behaviors.computeIfAbsent(key, behaviorKey -> new ArrayList<>());

functions.clear();
functions.add(function);
return this;
}

@SuppressWarnings("unchecked")
public void applyTo(BehaviorCollection collection) {
for (Map.Entry<BehaviorKey<?, ?>, List<Object>> entry : this.behaviors.entrySet()) {
ListIterator<Object> iterator = entry.getValue().listIterator();

Object function = iterator.next();
if (function == null) {
collection.extend((BehaviorKey<Object, ?>) entry.getKey(), iterator.next());
} else {
collection.overwrite((BehaviorKey<Object, ?>) entry.getKey(), function);
}
while (iterator.hasNext()) {
collection.extend((BehaviorKey<Object, ?>) entry.getKey(), iterator.next());
}
}
}
}
Original file line number Diff line number Diff line change
@@ -32,4 +32,11 @@ public interface BehaviorCollection {
* @return this behavior collection
*/
<T, R> BehaviorCollection overwrite(BehaviorKey<T, R> key, T function);

/**
* Applies all behaviors in a {@link BehaviorBuilder} to the specified collection.
*
* @param builder builder
*/
void apply(BehaviorBuilder builder);
}