Skip to content

Commit a3275c5

Browse files
authored
Add new positions fetcher to handle trees growing downwards + add new config detectionModeBiomeOverride that is accessible only through the config file (#912)
1 parent 3b85f08 commit a3275c5

17 files changed

Lines changed: 278 additions & 27 deletions

File tree

common/src/main/java/fr/rakambda/fallingtree/common/config/ITreeConfiguration.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import fr.rakambda.fallingtree.common.wrapper.IBlock;
1010
import org.jetbrains.annotations.NotNull;
1111
import java.util.Collection;
12+
import java.util.Map;
1213

1314
public interface ITreeConfiguration{
1415
@NotNull
@@ -41,6 +42,9 @@ public interface ITreeConfiguration{
4142
@NotNull
4243
DetectionMode getDetectionMode();
4344

45+
@NotNull
46+
Map<String, DetectionMode> getDetectionModeBiomeOverride();
47+
4448
int getMaxScanSize();
4549

4650
int getMinSize();
Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
package fr.rakambda.fallingtree.common.config.enums;
22

3+
import fr.rakambda.fallingtree.common.tree.Tree;
4+
import fr.rakambda.fallingtree.common.wrapper.IBlockPos;
5+
import lombok.Getter;
6+
import lombok.RequiredArgsConstructor;
7+
import java.util.function.Function;
8+
import java.util.stream.Stream;
9+
10+
@Getter
11+
@RequiredArgsConstructor
312
public enum DetectionMode{
4-
WHOLE_TREE, ABOVE_CUT, ABOVE_Y
13+
ABOVE_CUT(tree -> tree.getTopMostLog().stream()),
14+
ABOVE_Y(tree -> tree.getTopMostLog().stream()),
15+
BELOW_CUT(tree -> tree.getBottomMostLog().stream()),
16+
BELOW_Y(tree -> tree.getBottomMostLog().stream()),
17+
WHOLE_TREE_DOWNWARDS(tree -> tree.getBottomMostLog().stream()),
18+
WHOLE_TREE(tree -> tree.getTopMostLog().stream());
19+
20+
private final Function<Tree, Stream<IBlockPos>> leafAroundPosProvider;
521
}

common/src/main/java/fr/rakambda/fallingtree/common/config/proxy/TreeProxyConfiguration.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
package fr.rakambda.fallingtree.common.config.proxy;
22

33
import fr.rakambda.fallingtree.common.FallingTreeCommon;
4-
import fr.rakambda.fallingtree.common.wrapper.IBlock;
54
import fr.rakambda.fallingtree.common.config.IResettable;
65
import fr.rakambda.fallingtree.common.config.ITreeConfiguration;
76
import fr.rakambda.fallingtree.common.config.enums.AdjacentStopMode;
87
import fr.rakambda.fallingtree.common.config.enums.BreakMode;
98
import fr.rakambda.fallingtree.common.config.enums.BreakOrder;
109
import fr.rakambda.fallingtree.common.config.enums.DetectionMode;
1110
import fr.rakambda.fallingtree.common.config.enums.MaxSizeAction;
11+
import fr.rakambda.fallingtree.common.wrapper.IBlock;
1212
import lombok.RequiredArgsConstructor;
1313
import lombok.Setter;
1414
import org.jetbrains.annotations.NotNull;
1515
import java.util.Collection;
16+
import java.util.Map;
1617
import java.util.Optional;
1718

1819
@RequiredArgsConstructor
@@ -87,6 +88,12 @@ public DetectionMode getDetectionMode(){
8788
return delegate.getDetectionMode();
8889
}
8990

91+
@Override
92+
@NotNull
93+
public Map<String, DetectionMode> getDetectionModeBiomeOverride(){
94+
return delegate.getDetectionModeBiomeOverride();
95+
}
96+
9097
@Override
9198
public int getMaxScanSize(){
9299
return delegate.getMaxScanSize();

common/src/main/java/fr/rakambda/fallingtree/common/config/real/TreeConfiguration.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,22 @@
22

33
import com.google.gson.annotations.Expose;
44
import fr.rakambda.fallingtree.common.FallingTreeCommon;
5-
import fr.rakambda.fallingtree.common.wrapper.IBlock;
65
import fr.rakambda.fallingtree.common.config.IResettable;
76
import fr.rakambda.fallingtree.common.config.ITreeConfiguration;
87
import fr.rakambda.fallingtree.common.config.enums.AdjacentStopMode;
98
import fr.rakambda.fallingtree.common.config.enums.BreakMode;
109
import fr.rakambda.fallingtree.common.config.enums.BreakOrder;
1110
import fr.rakambda.fallingtree.common.config.enums.DetectionMode;
1211
import fr.rakambda.fallingtree.common.config.enums.MaxSizeAction;
12+
import fr.rakambda.fallingtree.common.wrapper.IBlock;
1313
import lombok.Data;
1414
import org.jetbrains.annotations.NotNull;
1515
import java.util.ArrayList;
1616
import java.util.Collection;
17+
import java.util.HashMap;
1718
import java.util.HashSet;
1819
import java.util.List;
20+
import java.util.Map;
1921
import java.util.Set;
2022
import static java.util.Objects.isNull;
2123

@@ -43,6 +45,9 @@ public class TreeConfiguration implements ITreeConfiguration, IResettable{
4345
@NotNull
4446
private DetectionMode detectionMode = DetectionMode.WHOLE_TREE;
4547
@Expose
48+
@NotNull
49+
private Map<String, DetectionMode> detectionModeBiomeOverride = new HashMap<>();
50+
@Expose
4651
private int maxScanSize = 500;
4752
@Expose
4853
private int minSize = 0;

common/src/main/java/fr/rakambda/fallingtree/common/tree/Tree.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,13 @@ public Optional<IBlockPos> getTopMostLog(){
106106
.max(comparingInt(IBlockPos::getY));
107107
}
108108

109+
@NotNull
110+
public Optional<IBlockPos> getBottomMostLog(){
111+
return getBreakableLogs().stream()
112+
.map(TreePart::blockPos)
113+
.min(comparingInt(IBlockPos::getY));
114+
}
115+
109116
@NotNull
110117
private Optional<IBlockPos> getTopMostPart(){
111118
return getParts().stream()

common/src/main/java/fr/rakambda/fallingtree/common/tree/builder/TreeBuilder.java

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package fr.rakambda.fallingtree.common.tree.builder;
22

3+
import fr.rakambda.fallingtree.common.FallingTreeCommon;
4+
import fr.rakambda.fallingtree.common.config.enums.DetectionMode;
35
import fr.rakambda.fallingtree.common.tree.Tree;
46
import fr.rakambda.fallingtree.common.tree.TreePartType;
57
import fr.rakambda.fallingtree.common.tree.builder.position.AbovePositionFetcher;
68
import fr.rakambda.fallingtree.common.tree.builder.position.AboveYFetcher;
79
import fr.rakambda.fallingtree.common.tree.builder.position.BasicPositionFetcher;
10+
import fr.rakambda.fallingtree.common.tree.builder.position.BelowPositionFetcher;
11+
import fr.rakambda.fallingtree.common.tree.builder.position.BelowYFetcher;
812
import fr.rakambda.fallingtree.common.tree.builder.position.IPositionFetcher;
9-
import fr.rakambda.fallingtree.common.FallingTreeCommon;
1013
import fr.rakambda.fallingtree.common.wrapper.DirectionCompat;
1114
import fr.rakambda.fallingtree.common.wrapper.IBlock;
1215
import fr.rakambda.fallingtree.common.wrapper.IBlockEntity;
@@ -21,6 +24,7 @@
2124
import java.util.Collection;
2225
import java.util.EnumSet;
2326
import java.util.HashSet;
27+
import java.util.Objects;
2428
import java.util.Optional;
2529
import java.util.PriorityQueue;
2630
import java.util.function.Predicate;
@@ -45,7 +49,9 @@ public Optional<Tree> getTree(@NotNull IPlayer player, @NotNull ILevel level, @N
4549
var toAnalyzePos = new PriorityQueue<ToAnalyzePos>();
4650
var analyzedPos = new HashSet<ToAnalyzePos>();
4751
var tree = new Tree(level, originPos);
48-
toAnalyzePos.add(new ToAnalyzePos(getFirstPositionFetcher(), originPos, originBlock, originPos, originBlock, originState, originEntity, TreePartType.LOG_START, 0, 0));
52+
var detectionMode = getDetectionMode(level, originPos);
53+
var firstPositionFetcher = getFirstPositionFetcher(detectionMode);
54+
toAnalyzePos.add(new ToAnalyzePos(firstPositionFetcher, originPos, originBlock, originPos, originBlock, originState, originEntity, TreePartType.LOG_START, 0, 0));
4955

5056
var boundingBoxSearch = getBoundingBoxSearch(originPos);
5157
var adjacentPredicate = getAdjacentPredicate();
@@ -86,9 +92,11 @@ public Optional<Tree> getTree(@NotNull IPlayer player, @NotNull ILevel level, @N
8692

8793
if(mod.getConfiguration().getTrees().getBreakMode().isCheckLeavesAround()){
8894
var aroundRequired = mod.getConfiguration().getTrees().getMinimumLeavesAroundRequired();
89-
if(tree.getTopMostLog()
90-
.map(topLog -> getLeavesAround(level, topLog) < aroundRequired)
91-
.orElse(true)){
95+
if(detectionMode.getLeafAroundPosProvider()
96+
.apply(tree)
97+
.mapToLong(topLog -> getLeavesAround(level, topLog))
98+
.sum() < aroundRequired
99+
){
92100
// TODO Set it back as info, see #845
93101
log.debug("Tree at {} doesn't have enough leaves around top most log", originPos);
94102
return empty();
@@ -148,15 +156,29 @@ private Predicate<IBlockPos> getBoundingBoxSearch(@NotNull IBlockPos originPos){
148156
}
149157

150158
@NotNull
151-
private IPositionFetcher getFirstPositionFetcher(){
152-
var detectionMode = mod.getConfiguration().getTrees().getDetectionMode();
159+
private IPositionFetcher getFirstPositionFetcher(@NotNull DetectionMode detectionMode){
153160
return switch(detectionMode){
154161
case ABOVE_CUT -> AbovePositionFetcher.getInstance(mod);
155162
case ABOVE_Y -> AboveYFetcher.getInstance(mod);
156-
case WHOLE_TREE -> BasicPositionFetcher.getInstance(mod);
163+
case BELOW_CUT -> BelowPositionFetcher.getInstance(mod);
164+
case BELOW_Y -> BelowYFetcher.getInstance(mod);
165+
case WHOLE_TREE, WHOLE_TREE_DOWNWARDS -> BasicPositionFetcher.getInstance(mod);
157166
};
158167
}
159168

169+
@NotNull
170+
private DetectionMode getDetectionMode(@NotNull ILevel level, @NotNull IBlockPos originPos){
171+
var biomeOverrides = mod.getConfiguration().getTrees().getDetectionModeBiomeOverride();
172+
if(!biomeOverrides.isEmpty()){
173+
var biome = level.getBiome(originPos);
174+
var override = biomeOverrides.get(biome.getId());
175+
if(Objects.nonNull(override)){
176+
return override;
177+
}
178+
}
179+
return mod.getConfiguration().getTrees().getDetectionMode();
180+
}
181+
160182
@NotNull
161183
private Collection<ToAnalyzePos> filterPotentialPos(@NotNull Predicate<IBlockPos> boundingBoxSearch,
162184
@NotNull Predicate<IBlock> adjacentPredicate,
Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,25 @@
11
package fr.rakambda.fallingtree.common.tree.builder.position;
22

3-
import java.util.Collection;
4-
import java.util.function.Function;
5-
import java.util.function.Supplier;
6-
import static java.util.Objects.isNull;
7-
import static java.util.stream.Collectors.toList;
83
import fr.rakambda.fallingtree.common.FallingTreeCommon;
94
import fr.rakambda.fallingtree.common.tree.builder.ToAnalyzePos;
105
import fr.rakambda.fallingtree.common.wrapper.IBlockPos;
116
import fr.rakambda.fallingtree.common.wrapper.ILevel;
127
import lombok.AccessLevel;
138
import lombok.RequiredArgsConstructor;
149
import org.jetbrains.annotations.NotNull;
10+
import java.util.Collection;
11+
import java.util.function.Function;
12+
import static java.util.Objects.isNull;
13+
import static java.util.stream.Collectors.toList;
1514

1615
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
1716
public class AbovePositionFetcher implements IPositionFetcher{
1817
private static AbovePositionFetcher INSTANCE;
19-
private static AbovePositionFetcher SECOND_STEP_INSTANCE;
2018

2119
@NotNull
2220
private final FallingTreeCommon<?> mod;
2321
@NotNull
2422
private final Function<IBlockPos, IBlockPos> lowerPosProvider;
25-
@NotNull
26-
private final Supplier<IPositionFetcher> positionFetcherSupplier;
2723

2824
@Override
2925
@NotNull
@@ -44,15 +40,8 @@ public Collection<ToAnalyzePos> getPositions(@NotNull ILevel level, @NotNull IBl
4440

4541
public static AbovePositionFetcher getInstance(@NotNull FallingTreeCommon<?> common){
4642
if(isNull(INSTANCE)){
47-
INSTANCE = new AbovePositionFetcher(common, IBlockPos::above, () -> getSecondStepInstance(common));
43+
INSTANCE = new AbovePositionFetcher(common, IBlockPos::above);
4844
}
4945
return INSTANCE;
5046
}
51-
52-
private static AbovePositionFetcher getSecondStepInstance(@NotNull FallingTreeCommon<?> common){
53-
if(isNull(SECOND_STEP_INSTANCE)){
54-
SECOND_STEP_INSTANCE = new AbovePositionFetcher(common, Function.identity(), () -> BasicPositionFetcher.getInstance(common));
55-
}
56-
return SECOND_STEP_INSTANCE;
57-
}
5847
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package fr.rakambda.fallingtree.common.tree.builder.position;
2+
3+
import fr.rakambda.fallingtree.common.FallingTreeCommon;
4+
import fr.rakambda.fallingtree.common.tree.builder.ToAnalyzePos;
5+
import fr.rakambda.fallingtree.common.wrapper.IBlockPos;
6+
import fr.rakambda.fallingtree.common.wrapper.ILevel;
7+
import lombok.AccessLevel;
8+
import lombok.RequiredArgsConstructor;
9+
import org.jetbrains.annotations.NotNull;
10+
import java.util.Collection;
11+
import java.util.function.Function;
12+
import static java.util.Objects.isNull;
13+
import static java.util.stream.Collectors.toList;
14+
15+
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
16+
public class BelowPositionFetcher implements IPositionFetcher{
17+
private static BelowPositionFetcher INSTANCE;
18+
19+
@NotNull
20+
private final FallingTreeCommon<?> mod;
21+
@NotNull
22+
private final Function<IBlockPos, IBlockPos> higherPosProvider;
23+
24+
@Override
25+
@NotNull
26+
public Collection<ToAnalyzePos> getPositions(@NotNull ILevel level, @NotNull IBlockPos originPos, @NotNull ToAnalyzePos parent){
27+
var parentPos = parent.checkPos();
28+
var parentBlock = level.getBlockState(parentPos).getBlock();
29+
return parentPos.betweenClosedStream(parentPos.below().south().west(), higherPosProvider.apply(parentPos).north().east())
30+
.map(checkPos -> {
31+
var checkedState = level.getBlockState(checkPos);
32+
var checkedEntity = level.getBlockEntity(checkPos);
33+
var checkBlock = checkedState.getBlock();
34+
var treePart = mod.getTreePart(checkBlock);
35+
var logSequence = treePart.isLog() ? 0 : (parent.sequenceSinceLastLog() + 1);
36+
return new ToAnalyzePos(this, parentPos, parentBlock, checkPos.immutable(), checkBlock, checkedState, checkedEntity, treePart, parent.sequence() + 1, logSequence);
37+
})
38+
.collect(toList());
39+
}
40+
41+
public static BelowPositionFetcher getInstance(@NotNull FallingTreeCommon<?> common){
42+
if(isNull(INSTANCE)){
43+
INSTANCE = new BelowPositionFetcher(common, IBlockPos::below);
44+
}
45+
return INSTANCE;
46+
}
47+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package fr.rakambda.fallingtree.common.tree.builder.position;
2+
3+
import fr.rakambda.fallingtree.common.FallingTreeCommon;
4+
import fr.rakambda.fallingtree.common.tree.builder.ToAnalyzePos;
5+
import fr.rakambda.fallingtree.common.wrapper.IBlockPos;
6+
import fr.rakambda.fallingtree.common.wrapper.ILevel;
7+
import lombok.AccessLevel;
8+
import lombok.RequiredArgsConstructor;
9+
import org.jetbrains.annotations.NotNull;
10+
11+
import java.util.Collection;
12+
13+
import static java.util.Objects.isNull;
14+
import static java.util.stream.Collectors.toList;
15+
16+
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
17+
public class BelowYFetcher implements IPositionFetcher{
18+
private static BelowYFetcher INSTANCE;
19+
20+
@NotNull
21+
private final FallingTreeCommon<?> mod;
22+
23+
@Override
24+
@NotNull
25+
public Collection<ToAnalyzePos> getPositions(@NotNull ILevel level, @NotNull IBlockPos originPos, @NotNull ToAnalyzePos parent){
26+
var parentPos = parent.checkPos();
27+
var parentBlock = level.getBlockState(parentPos).getBlock();
28+
return parentPos.betweenClosedStream(parentPos.below().south().west(), parentPos.above().north().east())
29+
.filter(pos -> pos.getY() < originPos.getY())
30+
.map(checkPos -> {
31+
var checkState = level.getBlockState(checkPos);
32+
var checkedEntity = level.getBlockEntity(checkPos);
33+
var checkBlock = checkState.getBlock();
34+
var treePart = mod.getTreePart(checkBlock);
35+
var logSequence = treePart.isLog() ? 0 : (parent.sequenceSinceLastLog() + 1);
36+
return new ToAnalyzePos(this, parentPos, parentBlock, checkPos.immutable(), checkBlock, checkState, checkedEntity, treePart, parent.sequence() + 1, logSequence);
37+
})
38+
.collect(toList());
39+
}
40+
41+
public static BelowYFetcher getInstance(@NotNull FallingTreeCommon<?> common){
42+
if(isNull(INSTANCE)){
43+
INSTANCE = new BelowYFetcher(common);
44+
}
45+
return INSTANCE;
46+
}
47+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package fr.rakambda.fallingtree.common.wrapper;
2+
3+
import org.jetbrains.annotations.NotNull;
4+
5+
public interface IBiome extends IWrapper{
6+
@NotNull
7+
String getId();
8+
}

0 commit comments

Comments
 (0)