This commit is contained in:
zly2006 committed 2024-07-13 16:24:08 +08:00
1 parent 6df7dac28e
commit 42eefdbef2
16 files changed
+165 -482

No files matched your search

@@ -12,10 +12,6 @@ public class SLSCarpetSettings {
@Rule(categories = {SLSA, RuleCategory.SURVIVAL})
public static boolean obtainableReinforcedDeepSlate = false;
/** Carpet SLS Addition original **/
@Rule(categories = {SLSA, RuleCategory.OPTIMIZATION})
public static int skipTicksForJoblessVillager = 0;
/** Carpet SLS Addition original **/
@Rule(categories = {SLSA, RuleCategory.CREATIVE})
public static boolean creativeNoInfinitePickup = false;
@@ -48,10 +44,6 @@ public class SLSCarpetSettings {
@Rule(categories = {SLSA, RuleCategory.FEATURE})
public static boolean fakePlayersNotOccupiedSleepQuota = false;
/** Carpet SLS Addition original **/
@Rule(categories = {SLSA, RuleCategory.CREATIVE})
public static int maxUpdateQueueSize = -1;
/** From Plusls Carpet Addition **/
@Rule(categories = {SLSA, RuleCategory.FEATURE, NEED_CLIENT})
public static boolean emptyShulkerBoxStack = false;
@@ -72,10 +64,6 @@ public class SLSCarpetSettings {
@Rule(categories = {SLSA, FROM_AMS, RuleCategory.OPTIMIZATION})
public static boolean optimizedOnDragonRespawn = false;
/** Carpet SLS Addition original **/
@Rule(categories = {SLSA, RuleCategory.FEATURE})
public static boolean printStackTraceOnVillagerSpawn = false;
/** Carpet SLS Addition original **/
@Rule(categories = {SLSA, RuleCategory.FEATURE})
public static boolean elytraCraftable = false;
@@ -5,11 +5,9 @@ import carpet.CarpetServer;
import com.github.zly2006.carpetslsaddition.command.BotCommand;
import com.github.zly2006.carpetslsaddition.command.HatCommand;
import com.github.zly2006.carpetslsaddition.command.SitCommand;
import com.github.zly2006.carpetslsaddition.util.access.SettingsManagerAccessor;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.mojang.brigadier.CommandDispatcher;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.loader.api.FabricLoader;
@@ -22,7 +20,7 @@ import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.io.InputStreamReader;
import java.util.Map;
public class ServerMain implements ModInitializer, CarpetExtension {
@@ -44,40 +42,35 @@ public class ServerMain implements ModInitializer, CarpetExtension {
CarpetServer.manageExtension(this);
}
@Override
public void onGameStarted() {
CarpetServer.settingsManager.parseSettingsClass(SLSCarpetSettings.class);
}
@Override
public void onServerLoaded(MinecraftServer server) {
ServerMain.server = server;
CarpetServer.settingsManager.parseSettingsClass(SLSCarpetSettings.class);
((SettingsManagerAccessor) CarpetServer.settingsManager).carpet_SLS_Addition$loadSettings();
}
@Override
public Map<String, String> canHasTranslations(String lang) {
Map<String, String> translation = Maps.newHashMap();
String jsonFile;
try {
try (InputStream stream = ServerMain.class.getResourceAsStream("/assets/slsaddition/lang/%s.json".formatted(lang))) {
assert stream != null;
jsonFile = new String(stream.readAllBytes(), StandardCharsets.UTF_8);
return GSON.fromJson(new InputStreamReader(stream), Map.class);
}
} catch (IOException | NullPointerException ignored) {
try {
try (InputStream stream = ServerMain.class.getResourceAsStream("/assets/slsaddition/lang/%s.json".formatted("en_us"))) {
try (InputStream stream = ServerMain.class.getResourceAsStream("/assets/slsaddition/lang/en_us.json")) {
assert stream != null;
jsonFile = new String(stream.readAllBytes(), StandardCharsets.UTF_8);
return GSON.fromJson(new InputStreamReader(stream), Map.class);
}
} catch (IOException | NullPointerException e) {
return translation;
}
}
GSON.fromJson(jsonFile, JsonObject.class).entrySet().stream()
.filter(entry -> entry.getValue().isJsonPrimitive())
.map(entry -> Map.entry(entry.getKey(), entry.getValue().getAsString()))
.forEach(entry -> {
translation.put(entry.getKey(), entry.getValue());
});
return translation;
}
@Override
@@ -1,183 +0,0 @@
package com.github.zly2006.carpetslsaddition.block;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import net.minecraft.world.block.NeighborUpdater;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
public class RewriteChainRestrictedNeighborUpdater implements NeighborUpdater {
private static final Logger LOGGER = LoggerFactory.getLogger("Minecraft");
private final World world;
private final int maxChainDepth;
private final ArrayDeque<Entry> queue = new ArrayDeque<>();
private final List<Entry> pending = new ArrayList<>();
private int depth = 0;
// rewrite part
private boolean needUpdate = true;
public RewriteChainRestrictedNeighborUpdater(World world, int maxChainDepth) {
this.world = world;
this.maxChainDepth = maxChainDepth;
}
public void replaceWithStateForNeighborUpdate(Direction direction, BlockState neighborState, BlockPos pos, BlockPos neighborPos, int flags, int maxUpdateDepth) {
this.enqueue(pos, new StateReplacementEntry(direction, neighborState, pos.toImmutable(), neighborPos.toImmutable(), flags, maxUpdateDepth));
}
public void updateNeighbor(BlockPos pos, Block sourceBlock, BlockPos sourcePos) {
this.enqueue(pos, new SimpleEntry(pos, sourceBlock, sourcePos.toImmutable()));
}
public void updateNeighbor(BlockState state, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) {
this.enqueue(pos, new StatefulEntry(state, pos.toImmutable(), sourceBlock, sourcePos.toImmutable(), notify));
}
public void updateNeighbors(BlockPos pos, Block sourceBlock, @Nullable Direction except) {
this.enqueue(pos, new SixWayEntry(pos.toImmutable(), sourceBlock, except));
}
private void enqueue(BlockPos pos, Entry entry) {
if (!needUpdate) {
return;
}
int maxSize = SLSCarpetSettings.maxUpdateQueueSize;
if (maxSize > 0) {
needUpdate = this.pending.size() + this.queue.size() + 1 <= maxSize;
}
boolean notEmpty = this.depth > 0;
boolean isFull = this.maxChainDepth >= 0 && this.depth >= this.maxChainDepth;
++this.depth;
if (!isFull) {
if (notEmpty) {
this.pending.add(entry);
} else {
this.queue.push(entry);
}
}
else if (this.depth - 1 == this.maxChainDepth) {
LOGGER.error("Too many chained neighbor updates. Skipping the rest. First skipped position: " + pos.toShortString());
}
if (!notEmpty) {
this.runQueuedUpdates();
}
}
private void runQueuedUpdates() {
try {
while(!this.queue.isEmpty() || !this.pending.isEmpty()) {
if (SLSCarpetSettings.maxUpdateQueueSize == 0) {
break;
}
for(int i = this.pending.size() - 1; i >= 0; --i) {
this.queue.push(this.pending.get(i));
}
this.pending.clear();
Entry entry = this.queue.peek();
assert entry != null;
while(this.pending.isEmpty()) {
if (needUpdate) {
if (!entry.update(this.world)) {
this.queue.pop();
break;
}
}
else {
entry.update(this.world);
throw new OutOfMemoryError("Create by Carpet-SLS-Addition");
}
}
}
}
catch (OutOfMemoryError e) {
if (e.getMessage().endsWith("Carpet-SLS-Addition")) {
LOGGER.error("The update queue exceeded the maximum allowed allocation of heap space set by SLS Addition!", e);
}
else {
throw e;
}
}
finally {
this.queue.clear();
this.pending.clear();
this.depth = 0;
needUpdate = true;
}
}
private interface Entry {
boolean update(World world);
}
private record StateReplacementEntry(Direction direction, BlockState neighborState, BlockPos pos, BlockPos neighborPos, int updateFlags, int updateLimit) implements Entry {
public boolean update(World world) {
NeighborUpdater.replaceWithStateForNeighborUpdate(world, this.direction, this.neighborState, this.pos, this.neighborPos, this.updateFlags, this.updateLimit);
return false;
}
}
record SimpleEntry(BlockPos pos, Block sourceBlock, BlockPos sourcePos) implements Entry {
public boolean update(World world) {
BlockState blockState = world.getBlockState(this.pos);
NeighborUpdater.tryNeighborUpdate(world, blockState, this.pos, this.sourceBlock, this.sourcePos, false);
return false;
}
}
record StatefulEntry(BlockState state, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean movedByPiston) implements Entry {
public boolean update(World world) {
NeighborUpdater.tryNeighborUpdate(world, this.state, this.pos, this.sourceBlock, this.sourcePos, this.movedByPiston);
return false;
}
}
static final class SixWayEntry implements Entry {
private final BlockPos pos;
private final Block sourceBlock;
@Nullable
private final Direction except;
private int currentDirectionIndex = 0;
SixWayEntry(BlockPos pos, Block sourceBlock, @Nullable Direction except) {
this.pos = pos;
this.sourceBlock = sourceBlock;
this.except = except;
if (NeighborUpdater.UPDATE_ORDER[this.currentDirectionIndex] == except) {
++this.currentDirectionIndex;
}
}
public boolean update(World world) {
BlockPos blockPos = this.pos.offset(NeighborUpdater.UPDATE_ORDER[this.currentDirectionIndex++]);
BlockState blockState = world.getBlockState(blockPos);
blockState.neighborUpdate(world, blockPos, this.sourceBlock, this.pos, false);
if (this.currentDirectionIndex < NeighborUpdater.UPDATE_ORDER.length && NeighborUpdater.UPDATE_ORDER[this.currentDirectionIndex] == this.except) {
++this.currentDirectionIndex;
}
return this.currentDirectionIndex < NeighborUpdater.UPDATE_ORDER.length;
}
}
}
@@ -1,43 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.carpet;
import carpet.api.settings.CarpetRule;
import carpet.api.settings.SettingsManager;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import com.github.zly2006.carpetslsaddition.ServerMain;
import com.github.zly2006.carpetslsaddition.util.NeighborUpdaterChanger;
import com.github.zly2006.carpetslsaddition.util.access.SettingsManagerAccessor;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.world.ServerWorld;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(value = SettingsManager.class, remap = false)
public abstract class MixinSettingsManager implements SettingsManagerAccessor {
@Shadow protected abstract void loadConfigurationFromConf();
@Override
public void carpet_SLS_Addition$loadSettings() {
this.loadConfigurationFromConf();
}
@Inject(method = "setRule", at = @At(value = "INVOKE", target = "Lcarpet/utils/Messenger;m(Lnet/minecraft/server/command/ServerCommandSource;[Ljava/lang/Object;)V", shift = At.Shift.BEFORE), remap = true)
private void injectSetRule(ServerCommandSource source, CarpetRule<?> rule, String newValue, CallbackInfoReturnable<Integer> cir) {
if ("maxUpdateQueueSize".equals(rule.name())) {
MinecraftServer server = ServerMain.server;
if (server != null)
{
server.execute(() -> {
for (ServerWorld world : server.getWorlds())
{
((NeighborUpdaterChanger)world).useRewriteChainNeighborUpdater(SLSCarpetSettings.maxUpdateQueueSize > -1);
}
});
}
}
}
}
@@ -1,9 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.elytra;
import net.minecraft.recipe.Recipe;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(Recipe.class)
public interface MixinRecipe {
}
@@ -1,89 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.entity;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import com.github.zly2006.carpetslsaddition.ServerMain;
import net.minecraft.entity.EntityData;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.SpawnReason;
import net.minecraft.entity.passive.MerchantEntity;
import net.minecraft.entity.passive.VillagerEntity;
import net.minecraft.village.VillagerData;
import net.minecraft.village.VillagerProfession;
import net.minecraft.world.LocalDifficulty;
import net.minecraft.world.ServerWorldAccess;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(VillagerEntity.class)
public abstract class MixinVillagerEntity extends MerchantEntity {
@Shadow public abstract VillagerData getVillagerData();
@Shadow protected abstract void decayGossip();
@Unique
int tickCount = 0;
public MixinVillagerEntity(EntityType<? extends MerchantEntity> entityType, World world) {
super(entityType, world);
}
@Inject(at = @At("HEAD"), method = "initialize")
private void injectInitialize(ServerWorldAccess world, LocalDifficulty difficulty, SpawnReason spawnReason, EntityData entityData, CallbackInfoReturnable<EntityData> cir) {
if (SLSCarpetSettings.printStackTraceOnVillagerSpawn) {
var logBuilder = new StringBuilder("\n=== Villager Spawn Report ===\n");
logBuilder.append("// Generated by Carpet SLS Addition\n");
try {
logBuilder.append("- Spawn Reason: ").append(spawnReason.toString()).append("\n");
logBuilder.append("- World: ").append(this.getWorld().getRegistryKey().getValue().toString()).append("\n");
logBuilder.append("- Position: ").append("(x=%.2f, y=%.2f, z=%.2f)".formatted(this.getX(), this.getY(), this.getZ())).append("\n");
logBuilder.append("- Stack Trance: ");
var exception = new Exception();
for (var element : exception.getStackTrace()) {
logBuilder.append("\n ").append(element.toString());
}
}
catch (Exception e) {
logBuilder.append("// Sorry but we fail to generate the villager spawn report.\n");
logBuilder.append("- Error Stack Trance: ");
for (var element : e.getStackTrace()) {
logBuilder.append("\n ").append(element.toString());
}
}
logBuilder.append("\n ================================");
ServerMain.LOGGER.warn(logBuilder.toString());
}
}
@Inject(at = @At("HEAD"), method = "tick", cancellable = true)
private void onTick(CallbackInfo ci) {
if (SLSCarpetSettings.skipTicksForJoblessVillager != 0) {
VillagerProfession profession = this.getVillagerData().getProfession();
if (profession != VillagerProfession.NONE && profession != VillagerProfession.NITWIT) {
tickCount = 0;
return;
}
if (tickCount > 0) {
tickCount--;
}
else {
tickCount = SLSCarpetSettings.skipTicksForJoblessVillager;
ci.cancel();
if (this.getHeadRollingTimeLeft() > 0) {
this.setHeadRollingTimeLeft(this.getHeadRollingTimeLeft() - 1);
}
this.decayGossip();
}
}
}
}
@@ -1,24 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.server;
import com.github.zly2006.carpetslsaddition.util.access.ServerAccessor;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.server.dedicated.MinecraftDedicatedServer;
import net.minecraft.server.dedicated.ServerPropertiesLoader;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Environment(EnvType.SERVER)
@Mixin(MinecraftDedicatedServer.class)
public class MixinMinecraftDedicatedServer implements ServerAccessor {
@Shadow
@Final
private ServerPropertiesLoader propertiesLoader;
@Override
public ServerPropertiesLoader getPropertiesLoader() {
return propertiesLoader;
}
}
@@ -1,34 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.server;
import com.github.zly2006.carpetslsaddition.SLSCarpetSettings;
import net.minecraft.server.MinecraftServer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import java.util.function.BooleanSupplier;
@Mixin(MinecraftServer.class)
public abstract class MixinMinecraftServer {
@Redirect(method = "runServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;tick(Ljava/util/function/BooleanSupplier;)V"))
private void redirectTicking(MinecraftServer instance, BooleanSupplier shouldKeepTicking) {
if (SLSCarpetSettings.maxUpdateQueueSize != -1) {
try {
instance.tick(shouldKeepTicking);
}
catch (Throwable throwable) {
if (throwable instanceof OutOfMemoryError oom) {
if (!oom.getMessage().startsWith("Create by Carpet-SLS-Addition")) {
throw throwable;
}
}
else {
throw throwable;
}
}
}
else {
instance.tick(shouldKeepTicking);
}
}
}
@@ -1,43 +0,0 @@
package com.github.zly2006.carpetslsaddition.mixin.world;
import com.github.zly2006.carpetslsaddition.ServerMain;
import com.github.zly2006.carpetslsaddition.block.RewriteChainRestrictedNeighborUpdater;
import com.github.zly2006.carpetslsaddition.util.NeighborUpdaterChanger;
import com.github.zly2006.carpetslsaddition.util.access.ServerAccessor;
import net.fabricmc.api.EnvType;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.world.World;
import net.minecraft.world.block.NeighborUpdater;
import org.spongepowered.asm.mixin.*;
@Mixin(World.class)
public abstract class MixinWorld implements NeighborUpdaterChanger {
@Mutable
@Shadow
@Final
protected NeighborUpdater neighborUpdater;
@Unique
private NeighborUpdater previousUpdater = null;
@Override
public void useRewriteChainNeighborUpdater(boolean use) {
if (use) {
this.previousUpdater = this.neighborUpdater;
int maxDepth;
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER) {
maxDepth = ((ServerAccessor) ServerMain.server).getPropertiesLoader().getPropertiesHandler().maxChainedNeighborUpdates;
}
else {
maxDepth = 1000000;
}
this.neighborUpdater = new RewriteChainRestrictedNeighborUpdater((World)(Object)this, maxDepth);
}
else {
this.neighborUpdater = previousUpdater;
}
}
}
@@ -1,5 +0,0 @@
package com.github.zly2006.carpetslsaddition.util;
public interface NeighborUpdaterChanger {
void useRewriteChainNeighborUpdater(boolean use);
}
@@ -1,7 +0,0 @@
package com.github.zly2006.carpetslsaddition.util.access;
import net.minecraft.server.dedicated.ServerPropertiesLoader;
public interface ServerAccessor {
ServerPropertiesLoader getPropertiesLoader();
}
@@ -1,5 +0,0 @@
package com.github.zly2006.carpetslsaddition.util.access;
public interface SettingsManagerAccessor {
void carpet_SLS_Addition$loadSettings();
}