Skip to content

Commit b7641b1

Browse files
committed
feat: further expansion of team properties system
- added StringSetProperty and StringMapProperty - StringMapProperty has int, string and boolean implementations - added TEAM_STAGES property and related command & helper API
1 parent 0a50159 commit b7641b1

File tree

11 files changed

+395
-8
lines changed

11 files changed

+395
-8
lines changed

common/src/main/java/dev/ftb/mods/ftbteams/FTBTeams.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import dev.architectury.utils.EnvExecutor;
1111
import dev.ftb.mods.ftblibrary.nbtedit.NBTEditResponseHandlers;
1212
import dev.ftb.mods.ftbteams.api.FTBTeamsAPI;
13-
import dev.ftb.mods.ftbteams.api.Team;
1413
import dev.ftb.mods.ftbteams.api.event.TeamCollectPropertiesEvent;
1514
import dev.ftb.mods.ftbteams.api.event.TeamEvent;
1615
import dev.ftb.mods.ftbteams.api.event.TeamManagerEvent;
@@ -19,12 +18,10 @@
1918
import dev.ftb.mods.ftbteams.data.AbstractTeam;
2019
import dev.ftb.mods.ftbteams.data.FTBTeamsCommands;
2120
import dev.ftb.mods.ftbteams.data.TeamManagerImpl;
22-
import dev.ftb.mods.ftbteams.data.TeamType;
2321
import dev.ftb.mods.ftbteams.net.FTBTeamsNet;
2422
import net.minecraft.commands.CommandBuildContext;
2523
import net.minecraft.commands.CommandSourceStack;
2624
import net.minecraft.commands.Commands;
27-
import net.minecraft.nbt.CompoundTag;
2825
import net.minecraft.network.chat.Component;
2926
import net.minecraft.server.MinecraftServer;
3027
import net.minecraft.server.level.ServerLevel;
@@ -92,6 +89,7 @@ private void teamConfig(TeamCollectPropertiesEvent event) {
9289
event.add(TeamProperties.COLOR);
9390
event.add(TeamProperties.FREE_TO_JOIN);
9491
event.add(TeamProperties.MAX_MSG_HISTORY_SIZE);
92+
event.add(TeamProperties.TEAM_STAGES);
9593
}
9694

9795
private void playerLoggedIn(ServerPlayer player) {

common/src/main/java/dev/ftb/mods/ftbteams/api/Team.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,4 +248,14 @@ default boolean isClientTeam() {
248248
* @param <T> the property type
249249
*/
250250
<T> void syncOnePropertyToAll(MinecraftServer server, TeamProperty<T> property, T value);
251+
252+
/**
253+
* Synchronise the value of one team property for this team to all online players on this team. This method does nothing
254+
* if called on the client.
255+
*
256+
* @param property the property to sync
257+
* @param value the value to sync
258+
* @param <T> the property type
259+
*/
260+
<T> void syncOnePropertyToTeam(TeamProperty<T> property, T value);
251261
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package dev.ftb.mods.ftbteams.api;
2+
3+
import dev.ftb.mods.ftbteams.api.event.TeamEvent;
4+
import dev.ftb.mods.ftbteams.api.event.TeamPropertiesChangedEvent;
5+
import dev.ftb.mods.ftbteams.api.property.TeamProperties;
6+
import dev.ftb.mods.ftbteams.api.property.TeamPropertyCollection;
7+
8+
import java.util.Collection;
9+
import java.util.Collections;
10+
import java.util.List;
11+
import java.util.Set;
12+
13+
/**
14+
* Utility class providing some convenience methods for querying and adjust the team stages for a team. These methods
15+
* all handle client sync and team data serialization internally.
16+
* <p>
17+
* Modifying a team's stages also causes a {@link TeamPropertiesChangedEvent} event to be fired.
18+
*/
19+
public class TeamStagesHelper {
20+
/**
21+
* Add one team stage to a team.
22+
*
23+
* @param team the team
24+
* @param stage the stage to add
25+
* @return true if the stage was added, false if the team already had the stage
26+
*/
27+
public static boolean addTeamStage(Team team, String stage) {
28+
return addTeamStages(team, List.of(stage)) == 1;
29+
}
30+
31+
/**
32+
* Add multiple team stages to a team. It is much more efficient to use this method rather than repeated calls to
33+
* {@link #addTeamStage(Team, String)} when adding multiple stages.
34+
*
35+
* @param team the team
36+
* @param stages the stages to add
37+
* @return the number of stages actually added
38+
*/
39+
public static int addTeamStages(Team team, Collection<String> stages) {
40+
return updateStages(team, stages, true);
41+
}
42+
43+
/**
44+
* Remove one team stage from a team.
45+
*
46+
* @param team the team
47+
* @param stage the stage to add
48+
* @return true if the stage was remove, false if the team did not have the stage
49+
*/
50+
public static boolean removeTeamStage(Team team, String stage) {
51+
return removeTeamStages(team, List.of(stage)) == 1;
52+
}
53+
54+
/**
55+
* Removing multiple team stages from a team. It is much more efficient to use this method rather than repeated calls to
56+
* {@link #removeTeamStage(Team, String)} when removing multiple stages.
57+
*
58+
* @param team the team
59+
* @param stages the stages to add
60+
* @return the number of stages actually removed
61+
*/
62+
public static int removeTeamStages(Team team, Collection<String> stages) {
63+
return updateStages(team, stages, false);
64+
}
65+
66+
/**
67+
* Check if a team has a particular stage.
68+
*
69+
* @param team the team
70+
* @param stage the stage to check
71+
* @return true if the team has the stage, false otherwise
72+
*/
73+
public static boolean hasTeamStage(Team team, String stage) {
74+
return team.getProperty(TeamProperties.TEAM_STAGES).contains(stage);
75+
}
76+
77+
/**
78+
* Get all the stages for a team.
79+
*
80+
* @param team the team
81+
* @return an unmodifiable collection of the team's stages
82+
*/
83+
public static Collection<String> getStages(Team team) {
84+
return Collections.unmodifiableSet(team.getProperty(TeamProperties.TEAM_STAGES));
85+
}
86+
87+
private static int updateStages(Team team, Collection<String> stages, boolean adding) {
88+
Set<String> stageSet = team.getProperty(TeamProperties.TEAM_STAGES);
89+
int changed = (int) stages.stream().filter(stage -> adding && stageSet.add(stage) || !adding && stageSet.remove(stage)).count();
90+
if (changed > 0) {
91+
team.setProperty(TeamProperties.TEAM_STAGES, stageSet);
92+
93+
TeamPropertyCollection old = team.getProperties().copy();
94+
TeamEvent.PROPERTIES_CHANGED.invoker().accept(new TeamPropertiesChangedEvent(team, old));
95+
team.syncOnePropertyToTeam(TeamProperties.TEAM_STAGES, stageSet);
96+
}
97+
98+
return changed;
99+
}
100+
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package dev.ftb.mods.ftbteams.api.property;
2+
3+
import com.google.common.base.Joiner;
4+
import com.google.common.base.Splitter;
5+
import net.minecraft.nbt.CompoundTag;
6+
import net.minecraft.nbt.Tag;
7+
import net.minecraft.network.FriendlyByteBuf;
8+
import net.minecraft.network.RegistryFriendlyByteBuf;
9+
import net.minecraft.resources.ResourceLocation;
10+
11+
import java.util.HashMap;
12+
import java.util.Map;
13+
import java.util.Optional;
14+
import java.util.function.BiConsumer;
15+
import java.util.function.Function;
16+
import java.util.function.Supplier;
17+
18+
public class StringMapProperty<T> extends TeamProperty<Map<String,T>> {
19+
private final TeamPropertyType<Map<String, T>> propType;
20+
private final Function<String,T> fromString;
21+
private final BiConsumer<FriendlyByteBuf, T> toNet;
22+
private final Function<FriendlyByteBuf, T> fromNet;
23+
24+
protected StringMapProperty(ResourceLocation id, Supplier<Map<String, T>> defaultValue, TeamPropertyType<Map<String, T>> propType,
25+
Function<String,T> fromString, BiConsumer<FriendlyByteBuf,T> toNet, Function<FriendlyByteBuf,T> fromNet)
26+
{
27+
super(id, defaultValue);
28+
this.propType = propType;
29+
this.fromString = fromString;
30+
this.toNet = toNet;
31+
this.fromNet = fromNet;
32+
}
33+
34+
@Override
35+
public TeamPropertyType<Map<String, T>> getType() {
36+
return propType;
37+
}
38+
39+
@Override
40+
public Optional<Map<String, T>> fromString(String string) {
41+
try {
42+
Map<String,T> res = new HashMap<>();
43+
Splitter.on(",").withKeyValueSeparator("=").split(string)
44+
.forEach((k, v) -> res.put(k, fromString.apply(v)));
45+
return Optional.of(res);
46+
} catch (IllegalArgumentException e) {
47+
return Optional.empty();
48+
}
49+
}
50+
51+
@Override
52+
public String toString(Map<String, T> value) {
53+
return Joiner.on(",").withKeyValueSeparator("=").join(value);
54+
}
55+
56+
@Override
57+
public void write(RegistryFriendlyByteBuf buf) {
58+
buf.writeMap(getDefaultValue(), FriendlyByteBuf::writeUtf, toNet::accept);
59+
}
60+
61+
@Override
62+
public Tag toNBT(Map<String, T> value) {
63+
CompoundTag res = new CompoundTag();
64+
value.forEach((k, v) -> res.putString(k, v.toString()));
65+
return res;
66+
}
67+
68+
@Override
69+
public Optional<Map<String, T>> fromNBT(Tag tag) {
70+
if (tag instanceof CompoundTag c) {
71+
Map<String,T> res = new HashMap<>();
72+
c.getAllKeys().forEach(k -> {
73+
res.put(k, fromString.apply(c.getString(k)));
74+
});
75+
return Optional.of(res);
76+
} else {
77+
return Optional.empty();
78+
}
79+
}
80+
81+
@Override
82+
public Map<String, T> readValue(RegistryFriendlyByteBuf buf) {
83+
return buf.readMap(FriendlyByteBuf::readUtf, fromNet::apply);
84+
}
85+
86+
@Override
87+
public void writeValue(RegistryFriendlyByteBuf buf, Map<String, T> value) {
88+
buf.writeMap(value, FriendlyByteBuf::writeUtf, toNet::accept);
89+
}
90+
91+
protected static <T> Map<String,T> mapFromNetwork(FriendlyByteBuf buf, Function<FriendlyByteBuf,T> fromNet) {
92+
return buf.readMap(FriendlyByteBuf::readUtf, fromNet::apply);
93+
}
94+
95+
public static class ToInteger extends StringMapProperty<Integer> {
96+
public ToInteger(ResourceLocation id, Map<String, Integer> defaultValue) {
97+
super(id, () -> defaultValue, TeamPropertyType.INT_MAP, Integer::parseInt, FriendlyByteBuf::writeVarInt, FriendlyByteBuf::readVarInt);
98+
}
99+
100+
static ToInteger fromNetwork(ResourceLocation id, FriendlyByteBuf buf) {
101+
return new ToInteger(id, mapFromNetwork(buf, FriendlyByteBuf::readVarInt));
102+
}
103+
}
104+
105+
public static class ToBoolean extends StringMapProperty<Boolean> {
106+
public ToBoolean(ResourceLocation id, Map<String, Boolean> defaultValue) {
107+
super(id, () -> defaultValue, TeamPropertyType.BOOL_MAP, Boolean::parseBoolean, FriendlyByteBuf::writeBoolean, FriendlyByteBuf::readBoolean);
108+
}
109+
110+
static ToBoolean fromNetwork(ResourceLocation id, FriendlyByteBuf buf) {
111+
return new ToBoolean(id, mapFromNetwork(buf, FriendlyByteBuf::readBoolean));
112+
}
113+
}
114+
115+
public static class ToString extends StringMapProperty<String> {
116+
public ToString(ResourceLocation id, Map<String, String> defaultValue) {
117+
super(id, () -> defaultValue, TeamPropertyType.STRING_MAP, Function.identity(), FriendlyByteBuf::writeUtf, FriendlyByteBuf::readUtf);
118+
}
119+
120+
static ToString fromNetwork(ResourceLocation id, FriendlyByteBuf buf) {
121+
return new ToString(id, mapFromNetwork(buf, FriendlyByteBuf::readUtf));
122+
}
123+
}
124+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package dev.ftb.mods.ftbteams.api.property;
2+
3+
import dev.ftb.mods.ftblibrary.config.ConfigGroup;
4+
import dev.ftb.mods.ftblibrary.config.ConfigValue;
5+
import dev.ftb.mods.ftblibrary.config.StringConfig;
6+
import net.minecraft.nbt.ListTag;
7+
import net.minecraft.nbt.StringTag;
8+
import net.minecraft.nbt.Tag;
9+
import net.minecraft.network.FriendlyByteBuf;
10+
import net.minecraft.network.RegistryFriendlyByteBuf;
11+
import net.minecraft.resources.ResourceLocation;
12+
13+
import java.util.*;
14+
import java.util.function.Supplier;
15+
import java.util.stream.Collectors;
16+
17+
public class StringSetProperty extends TeamProperty<Set<String>> {
18+
public StringSetProperty(ResourceLocation id, Supplier<Set<String>> def) {
19+
super(id, def);
20+
}
21+
22+
public StringSetProperty(ResourceLocation id, Set<String> def) {
23+
this(id, () -> def);
24+
}
25+
26+
static StringSetProperty fromNetwork(ResourceLocation id, FriendlyByteBuf buf) {
27+
return new StringSetProperty(id, new HashSet<>(buf.readList(b -> b.readUtf(Short.MAX_VALUE))));
28+
}
29+
30+
@Override
31+
public TeamPropertyType<Set<String>> getType() {
32+
return TeamPropertyType.STRING_SET;
33+
}
34+
35+
@Override
36+
public Optional<Set<String>> fromString(String string) {
37+
return string.length() > 2 && string.startsWith("[") && string.endsWith("]") ?
38+
Optional.of(new HashSet<>(Arrays.asList(string.substring(1, string.length() - 1).split("\t")))) :
39+
Optional.empty();
40+
}
41+
42+
@Override
43+
public void write(RegistryFriendlyByteBuf buf) {
44+
buf.writeCollection(getDefaultValue(), FriendlyByteBuf::writeUtf);
45+
}
46+
47+
@Override
48+
public String toString(Set<String> value) {
49+
return "[" + String.join("\t", value) + "]";
50+
}
51+
52+
@Override
53+
public ConfigValue<?> config(ConfigGroup config, TeamPropertyValue<Set<String>> value) {
54+
return config.addList(id.getPath(), new ArrayList<>(value.getValue()), new StringConfig(), "");
55+
}
56+
57+
@Override
58+
public Tag toNBT(Set<String> value) {
59+
ListTag res = new ListTag();
60+
value.forEach(s -> res.add(StringTag.valueOf(s)));
61+
return res;
62+
}
63+
64+
@Override
65+
public Optional<Set<String>> fromNBT(Tag tag) {
66+
return tag instanceof ListTag l ?
67+
Optional.of(l.stream().map(Tag::getAsString).collect(Collectors.toSet())) :
68+
Optional.empty();
69+
}
70+
71+
@Override
72+
public void writeValue(RegistryFriendlyByteBuf buf, Set<String> value) {
73+
buf.writeCollection(value, FriendlyByteBuf::writeUtf);
74+
}
75+
76+
@Override
77+
public Set<String> readValue(RegistryFriendlyByteBuf buf) {
78+
return buf.readCollection(HashSet::new, FriendlyByteBuf::readUtf);
79+
}
80+
}

common/src/main/java/dev/ftb/mods/ftbteams/api/property/TeamProperties.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import dev.ftb.mods.ftblibrary.icon.Color4I;
44
import dev.ftb.mods.ftbteams.api.FTBTeamsAPI;
55

6-
import java.math.BigInteger;
6+
import java.util.HashSet;
77
import java.util.regex.Pattern;
88

99
/**
@@ -23,4 +23,7 @@ public class TeamProperties {
2323
= new BooleanProperty(FTBTeamsAPI.rl("free_to_join"), false);
2424
public static final IntProperty MAX_MSG_HISTORY_SIZE
2525
= new IntProperty(FTBTeamsAPI.rl("max_msg_history_size"), 1000);
26+
public static final StringSetProperty TEAM_STAGES
27+
= (StringSetProperty) new StringSetProperty(FTBTeamsAPI.rl("team_stages"), new HashSet<>())
28+
.notPlayerEditable();
2629
}

common/src/main/java/dev/ftb/mods/ftbteams/api/property/TeamPropertyType.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import java.math.BigInteger;
99
import java.util.List;
1010
import java.util.Map;
11+
import java.util.Set;
1112
import java.util.concurrent.ConcurrentHashMap;
1213

1314
/**
@@ -23,12 +24,16 @@ public class TeamPropertyType<T> {
2324
public static final TeamPropertyType<Boolean> BOOLEAN = register("boolean", BooleanProperty::fromNetwork);
2425
public static final TeamPropertyType<String> STRING = register("string", StringProperty::fromNetwork);
2526
public static final TeamPropertyType<List<String>> STRING_LIST = register("string_list", StringListProperty::fromNetwork);
27+
public static final TeamPropertyType<Set<String>> STRING_SET = register("string_list", StringSetProperty::fromNetwork);
2628
public static final TeamPropertyType<Integer> INT = register("int", IntProperty::fromNetwork);
2729
public static final TeamPropertyType<Double> DOUBLE = register("double", DoubleProperty::fromNetwork);
2830
public static final TeamPropertyType<Color4I> COLOR = register("color", ColorProperty::fromNetwork);
2931
public static final TeamPropertyType<String> ENUM = register("enum", EnumProperty::fromNetwork);
3032
public static final TeamPropertyType<PrivacyMode> PRIVACY_MODE = register("privacy_mode", PrivacyProperty::fromNetwork);
3133
public static final TeamPropertyType<BigInteger> BIG_INTEGER = register("big_integer", BigIntegerProperty::fromNetwork);
34+
public static final TeamPropertyType<Map<String,Integer>> INT_MAP = register("int_map", StringMapProperty.ToInteger::fromNetwork);
35+
public static final TeamPropertyType<Map<String,Boolean>> BOOL_MAP = register("bool_map", StringMapProperty.ToBoolean::fromNetwork);
36+
public static final TeamPropertyType<Map<String,String>> STRING_MAP = register("string_map", StringMapProperty.ToString::fromNetwork);
3237

3338
private final ResourceLocation id;
3439
private final FromNet<T> deserializer;

0 commit comments

Comments
 (0)