mirror of
https://github.com/IntellectualSites/PlotSquared.git
synced 2024-11-29 08:36:45 +01:00
BlockBuckets r cool 🐮
This commit is contained in:
parent
af9418552a
commit
1d3270d869
@ -831,7 +831,11 @@ public enum C {
|
|||||||
HELP_FOOTER("$3&m---------&r $1Plot\u00B2 Help $3&m---------", "Help"),
|
HELP_FOOTER("$3&m---------&r $1Plot\u00B2 Help $3&m---------", "Help"),
|
||||||
|
|
||||||
HELP_INFO_ITEM("$1/plot help %category% $3- $2%category_desc%", "Help"), HELP_ITEM(
|
HELP_INFO_ITEM("$1/plot help %category% $3- $2%category_desc%", "Help"), HELP_ITEM(
|
||||||
"$1%usage% [%alias%]&- $3- $2%desc%&-", "Help"), /*
|
"$1%usage% [%alias%]&- $3- $2%desc%&-", "Help"),
|
||||||
|
|
||||||
|
BUCKET_ENTRIES_IGNORED("$2Total bucket values add up to 1 or more. Blocks without a spcified chance will be ignored", "Generator_Bucket"),
|
||||||
|
|
||||||
|
/*
|
||||||
* Direction
|
* Direction
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -0,0 +1,154 @@
|
|||||||
|
package com.github.intellectualsites.plotsquared.plot.object;
|
||||||
|
|
||||||
|
import com.github.intellectualsites.plotsquared.plot.config.C;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A block bucket is a container of block types, where each block
|
||||||
|
* has a specified chance of being randomly picked
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"unused", "WeakerAccess"})
|
||||||
|
public final class BlockBucket implements Iterable<PlotBlock> {
|
||||||
|
|
||||||
|
private final Random random = new Random();
|
||||||
|
private final Map<Range, PlotBlock> ranges = new HashMap<>();
|
||||||
|
private final Map<PlotBlock, Integer> blocks;
|
||||||
|
private final BucketIterator bucketIterator = new BucketIterator();
|
||||||
|
private boolean compiled;
|
||||||
|
|
||||||
|
public BlockBucket() {
|
||||||
|
this.blocks = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addBlock(@NonNull final PlotBlock block) {
|
||||||
|
this.addBlock(block, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addBlock(@NonNull final PlotBlock block, final int chance) {
|
||||||
|
this.blocks.put(block, chance);
|
||||||
|
this.compiled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void compile() {
|
||||||
|
if (isCompiled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Map<PlotBlock, Integer> temp = new HashMap<>(blocks.size());
|
||||||
|
final List<PlotBlock> unassigned = new ArrayList<>(blocks.size());
|
||||||
|
|
||||||
|
int sum = 0;
|
||||||
|
for (final Map.Entry<PlotBlock, Integer> entry : blocks.entrySet()) {
|
||||||
|
if (entry.getValue() == -1) {
|
||||||
|
unassigned.add(entry.getKey());
|
||||||
|
} else {
|
||||||
|
sum += entry.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// If this doesn't amount to 100 add it up to exactly 100.
|
||||||
|
//
|
||||||
|
if (sum < 100) {
|
||||||
|
final int remaining = 100 - sum;
|
||||||
|
final int perUnassigned = remaining / unassigned.size();
|
||||||
|
for (final PlotBlock block : unassigned) {
|
||||||
|
temp.put(block, perUnassigned);
|
||||||
|
sum += perUnassigned;
|
||||||
|
}
|
||||||
|
// Make sure there isn't a tiny difference remaining
|
||||||
|
if (sum < 100) {
|
||||||
|
final int difference = 100 - sum;
|
||||||
|
temp.put(unassigned.get(0), perUnassigned + difference);
|
||||||
|
sum = 100;
|
||||||
|
}
|
||||||
|
} else if (!unassigned.isEmpty()) {
|
||||||
|
C.BUCKET_ENTRIES_IGNORED.send(ConsolePlayer.getConsole());
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// If the sum adds up to more than 100, divide all values
|
||||||
|
//
|
||||||
|
if (sum > 100) {
|
||||||
|
final double ratio = 100D / sum;
|
||||||
|
for (final Map.Entry<PlotBlock, Integer> entry : blocks.entrySet()) {
|
||||||
|
if (entry.getValue() == -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
temp.put(entry.getKey(), (int)(entry.getValue() * ratio));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
temp.forEach(temp::put);
|
||||||
|
}
|
||||||
|
int start = 0;
|
||||||
|
for (final Map.Entry<PlotBlock, Integer> entry : temp.entrySet()) {
|
||||||
|
final int rangeStart = start;
|
||||||
|
final int rangeEnd = rangeStart + entry.getValue();
|
||||||
|
start = rangeEnd + 1;
|
||||||
|
final Range range = new Range(rangeStart, rangeEnd);
|
||||||
|
this.ranges.put(range, entry.getKey());
|
||||||
|
}
|
||||||
|
this.blocks.clear();
|
||||||
|
this.compiled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<PlotBlock> iterator() {
|
||||||
|
return this.bucketIterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCompiled() {
|
||||||
|
return this.compiled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a random block out of the bucket
|
||||||
|
*
|
||||||
|
* @return Randomly picked block (cased on specified rates)
|
||||||
|
*/
|
||||||
|
public PlotBlock getBlock() {
|
||||||
|
if (!isCompiled()) {
|
||||||
|
this.compile();
|
||||||
|
}
|
||||||
|
final int number = random.nextInt(101);
|
||||||
|
for (final Map.Entry<Range, PlotBlock> entry : ranges.entrySet()) {
|
||||||
|
if (entry.getKey().isInRange(number)) {
|
||||||
|
return entry.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Didn't find a block? Try again
|
||||||
|
return getBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class BucketIterator implements Iterator<PlotBlock> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PlotBlock next() {
|
||||||
|
return getBlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
private final static class Range {
|
||||||
|
|
||||||
|
private final int min;
|
||||||
|
private final int max;
|
||||||
|
|
||||||
|
public boolean isInRange(final int num) {
|
||||||
|
return num <= max && num >= min;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,40 +0,0 @@
|
|||||||
package com.github.intellectualsites.plotsquared.plot.object;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.ToString;
|
|
||||||
|
|
||||||
@ToString
|
|
||||||
@EqualsAndHashCode
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public final class BlockWrapper {
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final PlotBlock type;
|
|
||||||
private final Map<Class, Object> blockStates;
|
|
||||||
|
|
||||||
public <T> T getState(@NonNull final Class stateType, @NonNull final Class<T> valueType, @NonNull final T defaultValue) {
|
|
||||||
if (!blockStates.containsKey(stateType)) {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
final Object rawValue = blockStates.get(stateType);
|
|
||||||
if (!rawValue.getClass().equals(valueType)) {
|
|
||||||
throw new ClassCastException(String.format("State type %s has a value of type %s but %s was requested",
|
|
||||||
stateType.getSimpleName(), rawValue.getClass().getSimpleName(), valueType.getSimpleName()));
|
|
||||||
}
|
|
||||||
return valueType.cast(rawValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> void setState(@NonNull final Class stateType, @NonNull final T value) {
|
|
||||||
this.blockStates.put(stateType, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<Class, Object> getAllStates() {
|
|
||||||
return Collections.unmodifiableMap(this.blockStates);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,97 +0,0 @@
|
|||||||
package com.github.intellectualsites.plotsquared.plot.object;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import lombok.AccessLevel;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
|
||||||
public final class BlockWrapperFactory<BlockType> {
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public static final class StateEntry<StateType extends Class, ObjectType> {
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final StateType stateType;
|
|
||||||
@Getter
|
|
||||||
private final ObjectType value;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface BlockStateDeserializer<StateType extends Class, ObjectType> {
|
|
||||||
StateEntry<StateType, ObjectType> deserialize(PlotBlock type, String serialized);
|
|
||||||
boolean isOfType(String serializedString);
|
|
||||||
}
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface BlockStateSerializer<StateType extends Class, ObjectType> {
|
|
||||||
String serialize(PlotBlock type, StateEntry<StateType, ObjectType> entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
|
||||||
public static final class StateSerializationMapping<StateType extends Class, ObjectType extends Class> {
|
|
||||||
@Getter
|
|
||||||
private final StateType type;
|
|
||||||
@Getter
|
|
||||||
private final ObjectType objectType;
|
|
||||||
@Getter
|
|
||||||
private final BlockStateSerializer<StateType, ObjectType> serializer;
|
|
||||||
@Getter
|
|
||||||
private final BlockStateDeserializer<StateType, ObjectType> deserializer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Map<Class, StateSerializationMapping> stateSerializationMappings = new HashMap<>();
|
|
||||||
|
|
||||||
public <StateType extends Class, ObjectType extends Class> StateSerializationMapping<StateType, ObjectType>
|
|
||||||
addStateMapping(@NonNull final StateType type, @NonNull final ObjectType objectType, @NonNull final BlockStateSerializer<StateType, ObjectType> serializer, @NonNull final BlockStateDeserializer<StateType, ObjectType> deserializer) {
|
|
||||||
final StateSerializationMapping<StateType, ObjectType> stateSerializationMapping = new StateSerializationMapping<>(type, objectType, serializer, deserializer);
|
|
||||||
this.stateSerializationMappings.put(type, stateSerializationMapping);
|
|
||||||
return stateSerializationMapping;
|
|
||||||
}
|
|
||||||
|
|
||||||
public <StateType extends Class, ObjectType extends Class> StateSerializationMapping<StateType, ObjectType>
|
|
||||||
getStateMapping(@NonNull final StateType type) {
|
|
||||||
return this.stateSerializationMappings.get(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<String> serializeStates(@NonNull final BlockWrapper blockWrapper) {
|
|
||||||
final List<String> serializedStates = new ArrayList<>();
|
|
||||||
blockWrapper.getAllStates().entrySet().stream().map(entry -> new StateEntry(entry.getKey(), entry.getValue()))
|
|
||||||
.forEach(entry -> {
|
|
||||||
final StateSerializationMapping stateSerializationMapping = getStateMapping(entry.getStateType());
|
|
||||||
final BlockStateSerializer blockStateSerializer = stateSerializationMapping.getSerializer();
|
|
||||||
final String serialized = blockStateSerializer.serialize(blockWrapper.getType(), entry);
|
|
||||||
serializedStates.add(serialized);
|
|
||||||
});
|
|
||||||
return serializedStates;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockStateDeserializer getDeserializerRaw(@NonNull final String serializedString) {
|
|
||||||
for (final StateSerializationMapping stateSerializationMapping : this.stateSerializationMappings.values()) {
|
|
||||||
if (stateSerializationMapping.getDeserializer().isOfType(serializedString)) {
|
|
||||||
return stateSerializationMapping.getDeserializer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<StateEntry> deserializeStates(@NonNull final PlotBlock plotBlock, @NonNull final Collection<String> serializedStates) {
|
|
||||||
final Collection<StateEntry> stateEntries = new ArrayList<>(serializedStates.size());
|
|
||||||
for (final String serializedState : serializedStates) {
|
|
||||||
if (serializedState == null || serializedState.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
final BlockStateDeserializer blockStateDeserializer = getDeserializerRaw(serializedState);
|
|
||||||
if (blockStateDeserializer == null) {
|
|
||||||
throw new IllegalStateException(String.format("No deserializer available for %s", serializedState));
|
|
||||||
}
|
|
||||||
stateEntries.add(blockStateDeserializer.deserialize(plotBlock, serializedState));
|
|
||||||
}
|
|
||||||
return stateEntries;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user