Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include gamerule settings in metadata #425

Merged
merged 1 commit into from
Jul 21, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import me.lucko.spark.common.platform.world.CountMap;
import me.lucko.spark.common.platform.world.WorldInfoProvider;
import org.bukkit.Chunk;
import org.bukkit.GameRule;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.block.BlockState;
Expand All @@ -32,6 +33,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class BukkitWorldInfoProvider implements WorldInfoProvider {
private static final boolean SUPPORTS_PAPER_COUNT_METHODS;
Expand Down Expand Up @@ -110,6 +112,33 @@ public ChunksResult<BukkitChunkInfo> pollChunks() {
return data;
}

@Override
public GameRulesResult pollGameRules() {
GameRulesResult data = new GameRulesResult();

boolean addDefaults = true; // add defaults in the first iteration
for (World world : this.server.getWorlds()) {
for (String gameRule : world.getGameRules()) {
GameRule<?> ruleObj = GameRule.getByName(gameRule);
if (ruleObj == null) {
continue;
}

if (addDefaults) {
Object defaultValue = world.getGameRuleDefault(ruleObj);
data.putDefault(gameRule, Objects.toString(defaultValue));
}

Object value = world.getGameRuleValue(ruleObj);
data.put(gameRule, world.getName(), Objects.toString(value));
}

addDefaults = false;
}

return data;
}

static final class BukkitChunkInfo extends AbstractChunkInfo<EntityType> {
private final CountMap<EntityType> entityCounts;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,19 @@ public CompletableFuture<WorldInfoProvider.ChunksResult<? extends ChunkInfo<?>>>
return async(WorldInfoProvider::pollChunks);
}

public CompletableFuture<WorldInfoProvider.GameRulesResult> pollGameRules() {
return async(WorldInfoProvider::pollGameRules);
}

public WorldInfoProvider.CountsResult getCounts() {
return get(pollCounts());
}

public WorldInfoProvider.ChunksResult<? extends ChunkInfo<?>> getChunks() {
return get(pollChunks());
}

public WorldInfoProvider.GameRulesResult getGameRules() {
return get(pollGameRules());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ public CountsResult pollCounts() {
public ChunksResult<? extends ChunkInfo<?>> pollChunks() {
return null;
}

@Override
public GameRulesResult pollGameRules() {
return null;
}
};

/**
Expand All @@ -55,6 +60,13 @@ public ChunksResult<? extends ChunkInfo<?>> pollChunks() {
*/
ChunksResult<? extends ChunkInfo<?>> pollChunks();

/**
* Polls for game rules.
*
* @return the game rules
*/
GameRulesResult pollGameRules();

default boolean mustCallSync() {
return true;
}
Expand Down Expand Up @@ -101,4 +113,37 @@ public int chunks() {
}
}

final class GameRulesResult {
private final Map<String, GameRule> rules = new HashMap<>();

private GameRule rule(String name) {
return this.rules.computeIfAbsent(name, k -> new GameRule());
}

public void put(String gameRuleName, String worldName, String value) {
rule(gameRuleName).worldValues.put(worldName, value);
}

public void putDefault(String gameRuleName, String value) {
rule(gameRuleName).defaultValue = value;
}

public Map<String, GameRule> getRules() {
return this.rules;
}

public static final class GameRule {
Map<String, String> worldValues = new HashMap<>();
String defaultValue = null;

public String getDefaultValue() {
return this.defaultValue;
}

public Map<String, String> getWorldValues() {
return this.worldValues;
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public WorldStatisticsProvider(AsyncWorldInfoProvider provider) {
}

public WorldStatistics getWorldStatistics() {
WorldInfoProvider.ChunksResult<? extends ChunkInfo<?>> result = provider.getChunks();
WorldInfoProvider.ChunksResult<? extends ChunkInfo<?>> result = this.provider.getChunks();
if (result == null) {
return null;
}
Expand Down Expand Up @@ -70,6 +70,16 @@ public WorldStatistics getWorldStatistics() {
stats.setTotalEntities(combinedTotal.get());
combined.asMap().forEach((key, value) -> stats.putEntityCounts(key, value.get()));

WorldInfoProvider.GameRulesResult gameRules = this.provider.getGameRules();
if (gameRules != null) {
gameRules.getRules().forEach((ruleName, rule) -> stats.addGameRules(WorldStatistics.GameRule.newBuilder()
.setName(ruleName)
.setDefaultValue(rule.getDefaultValue())
.putAllWorldValues(rule.getWorldValues())
.build()
));
}

return stats.build();
}

Expand Down
7 changes: 7 additions & 0 deletions spark-common/src/main/proto/spark/spark.proto
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ message WorldStatistics {
int32 total_entities = 1;
map<string, int32> entity_counts = 2;
repeated World worlds = 3;
repeated GameRule game_rules = 4;

message World {
string name = 1;
Expand All @@ -158,6 +159,12 @@ message WorldStatistics {
int32 total_entities = 3;
map<string, int32> entity_counts = 4;
}

message GameRule {
string name = 1;
string default_value = 2;
map<string, string> world_values = 3;
}
}

message WindowStatistics {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import net.minecraft.server.world.ServerEntityManager;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.GameRules;
import net.minecraft.world.entity.ClientEntityManager;
import net.minecraft.world.entity.EntityIndex;
import net.minecraft.world.entity.EntityTrackingSection;
Expand Down Expand Up @@ -101,6 +102,28 @@ public ChunksResult<FabricChunkInfo> pollChunks() {

return data;
}

@Override
public GameRulesResult pollGameRules() {
GameRulesResult data = new GameRulesResult();
Iterable<ServerWorld> worlds = this.server.getWorlds();

GameRules.accept(new GameRules.Visitor() {
@Override
public <T extends GameRules.Rule<T>> void visit(GameRules.Key<T> key, GameRules.Type<T> type) {
String defaultValue = type.createRule().serialize();
data.putDefault(key.getName(), defaultValue);

for (ServerWorld world : worlds) {
String worldName = world.getRegistryKey().getValue().getPath();

String value = world.getGameRules().get(key).serialize();
data.put(key.getName(), worldName, value);
}
}
});
return data;
}
}

public static final class Client extends FabricWorldInfoProvider {
Expand Down Expand Up @@ -128,13 +151,13 @@ public CountsResult pollCounts() {

@Override
public ChunksResult<FabricChunkInfo> pollChunks() {
ChunksResult<FabricChunkInfo> data = new ChunksResult<>();

ClientWorld world = this.client.world;
if (world == null) {
return null;
}

ChunksResult<FabricChunkInfo> data = new ChunksResult<>();

ClientEntityManager<Entity> entityManager = ((ClientWorldAccessor) world).getEntityManager();
SectionedEntityCache<Entity> cache = ((ClientEntityManagerAccessor) entityManager).getCache();

Expand All @@ -143,6 +166,32 @@ public ChunksResult<FabricChunkInfo> pollChunks() {

return data;
}

@Override
public GameRulesResult pollGameRules() {
ClientWorld world = this.client.world;
if (world == null) {
return null;
}

GameRulesResult data = new GameRulesResult();

String worldName = world.getRegistryKey().getValue().getPath();
GameRules worldRules = world.getGameRules();

GameRules.accept(new GameRules.Visitor() {
@Override
public <T extends GameRules.Rule<T>> void visit(GameRules.Key<T> key, GameRules.Type<T> type) {
String defaultValue = type.createRule().serialize();
data.putDefault(key.getName(), defaultValue);

String value = worldRules.get(key).serialize();
data.put(key.getName(), worldName, value);
}
});

return data;
}
}

static final class FabricChunkInfo extends AbstractChunkInfo<EntityType<?>> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.entity.EntityLookup;
import net.minecraft.world.level.entity.EntitySection;
import net.minecraft.world.level.entity.EntitySectionStorage;
Expand Down Expand Up @@ -97,6 +98,29 @@ public ChunksResult<ForgeChunkInfo> pollChunks() {

return data;
}

@Override
public GameRulesResult pollGameRules() {
GameRulesResult data = new GameRulesResult();
Iterable<ServerLevel> levels = this.server.getAllLevels();

GameRules.visitGameRuleTypes(new GameRules.GameRuleTypeVisitor() {
@Override
public <T extends GameRules.Value<T>> void visit(GameRules.Key<T> key, GameRules.Type<T> type) {
String defaultValue = type.createRule().serialize();
data.putDefault(key.getId(), defaultValue);

for (ServerLevel level : levels) {
String levelName = level.dimension().location().getPath();

String value = level.getGameRules().getRule(key).serialize();
data.put(key.getId(), levelName, value);
}
}
});

return data;
}
}

public static final class Client extends ForgeWorldInfoProvider {
Expand Down Expand Up @@ -124,13 +148,13 @@ public CountsResult pollCounts() {

@Override
public ChunksResult<ForgeChunkInfo> pollChunks() {
ChunksResult<ForgeChunkInfo> data = new ChunksResult<>();

ClientLevel level = this.client.level;
if (level == null) {
return null;
}

ChunksResult<ForgeChunkInfo> data = new ChunksResult<>();

TransientEntitySectionManager<Entity> entityManager = level.entityStorage;
EntitySectionStorage<Entity> cache = entityManager.sectionStorage;

Expand All @@ -139,6 +163,32 @@ public ChunksResult<ForgeChunkInfo> pollChunks() {

return data;
}

@Override
public GameRulesResult pollGameRules() {
ClientLevel level = this.client.level;
if (level == null) {
return null;
}

GameRulesResult data = new GameRulesResult();

String levelName = level.dimension().location().getPath();
GameRules levelRules = level.getGameRules();

GameRules.visitGameRuleTypes(new GameRules.GameRuleTypeVisitor() {
@Override
public <T extends GameRules.Value<T>> void visit(GameRules.Key<T> key, GameRules.Type<T> type) {
String defaultValue = type.createRule().serialize();
data.putDefault(key.getId(), defaultValue);

String value = levelRules.getRule(key).serialize();
data.put(key.getId(), levelName, value);
}
});

return data;
}
}

static final class ForgeChunkInfo extends AbstractChunkInfo<EntityType<?>> {
Expand Down
Loading
Loading