Merge branch 'master' into light
This commit is contained in:
commit
ac9fcd9ece
122 files changed
+7753
-1373
No files matched your search
@@ -6,6 +6,8 @@ import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface CarpetExtension
|
||||
{
|
||||
/**
|
||||
@@ -51,4 +53,6 @@ public interface CarpetExtension
|
||||
default String version() {return null;}
|
||||
|
||||
default void registerLoggers() {}
|
||||
|
||||
default Map<String, String> canHasTranslations(String lang) { return null;}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import carpet.commands.*;
|
||||
import carpet.network.ServerNetworkHandler;
|
||||
import carpet.helpers.TickSpeed;
|
||||
import carpet.logging.LoggerRegistry;
|
||||
import carpet.script.CarpetScriptServer;
|
||||
@@ -56,10 +57,11 @@ public class CarpetServer // static for now - easier to handle all around the co
|
||||
if (sm != null) sm.attachServer(server);
|
||||
e.onServerLoaded(server);
|
||||
});
|
||||
scriptServer = new CarpetScriptServer();
|
||||
scriptServer = new CarpetScriptServer(server);
|
||||
scriptServer.loadAllWorldScripts();
|
||||
MobAI.resetTrackers();
|
||||
LoggerRegistry.initLoggers();
|
||||
//TickSpeed.reset();
|
||||
}
|
||||
|
||||
public static void tick(MinecraftServer server)
|
||||
@@ -102,29 +104,41 @@ public class CarpetServer // static for now - easier to handle all around the co
|
||||
|
||||
public static void onPlayerLoggedIn(ServerPlayerEntity player)
|
||||
{
|
||||
ServerNetworkHandler.onPlayerJoin(player);
|
||||
LoggerRegistry.playerConnected(player);
|
||||
extensions.forEach(e -> e.onPlayerLoggedIn(player));
|
||||
|
||||
}
|
||||
|
||||
public static void onPlayerLoggedOut(ServerPlayerEntity player)
|
||||
{
|
||||
ServerNetworkHandler.onPlayerLoggedOut(player);
|
||||
LoggerRegistry.playerDisconnected(player);
|
||||
extensions.forEach(e -> e.onPlayerLoggedOut(player));
|
||||
}
|
||||
|
||||
public static void onServerClosed(MinecraftServer server)
|
||||
{
|
||||
ServerNetworkHandler.close();
|
||||
currentCommandDispatcher = null;
|
||||
if (scriptServer != null) scriptServer.onClose();
|
||||
settingsManager.detachServer();
|
||||
|
||||
LoggerRegistry.stopLoggers();
|
||||
extensions.forEach(e -> e.onServerClosed(server));
|
||||
minecraft_server = null;
|
||||
disconnect();
|
||||
}
|
||||
|
||||
public static void registerExtensionLoggers()
|
||||
{
|
||||
extensions.forEach(CarpetExtension::registerLoggers);
|
||||
}
|
||||
|
||||
public static void disconnect()
|
||||
{
|
||||
// this for whatever reason gets called multiple times even when joining;
|
||||
TickSpeed.reset();
|
||||
settingsManager.detachServer();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,13 @@ import carpet.settings.ParsedRule;
|
||||
import carpet.settings.Rule;
|
||||
import carpet.settings.SettingsManager;
|
||||
import carpet.settings.Validator;
|
||||
import carpet.utils.Translations;
|
||||
import carpet.utils.Messenger;
|
||||
import carpet.utils.SpawnChunks;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.dedicated.DedicatedServer;
|
||||
import net.minecraft.server.world.ChunkTicketType;
|
||||
import net.minecraft.server.world.ServerChunkManager;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.Unit;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Box;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
@@ -35,7 +34,7 @@ import static carpet.settings.RuleCategory.CLIENT;
|
||||
@SuppressWarnings("CanBeFinal")
|
||||
public class CarpetSettings
|
||||
{
|
||||
public static final String carpetVersion = "1.3.17+v200401";
|
||||
public static final String carpetVersion = "1.3.29+v200611";
|
||||
public static final Logger LOG = LogManager.getLogger();
|
||||
public static boolean skipGenerationChecks = false;
|
||||
public static boolean impendingFillSkipUpdates = false;
|
||||
@@ -43,6 +42,31 @@ public class CarpetSettings
|
||||
public static Vec3d fixedPosition = null;
|
||||
public static int runPermissionLevel = 2;
|
||||
|
||||
private static class LanguageValidator extends Validator<String> {
|
||||
@Override public String validate(ServerCommandSource source, ParsedRule<String> currentRule, String newValue, String string) {
|
||||
if (currentRule.get().equals(newValue) || source == null)
|
||||
{
|
||||
return newValue;
|
||||
}
|
||||
if (!Translations.isValidLanguage(newValue))
|
||||
{
|
||||
Messenger.m(source, "r "+newValue+" is not a valid language");
|
||||
return null;
|
||||
}
|
||||
CarpetSettings.language = newValue;
|
||||
Translations.updateLanguage(source);
|
||||
return newValue;
|
||||
}
|
||||
}
|
||||
@Rule(
|
||||
desc = "sets the language for carpet",
|
||||
category = FEATURE,
|
||||
options = {"none", "zh_cn", "zh_tw"},
|
||||
strict = false,
|
||||
validate = LanguageValidator.class
|
||||
)
|
||||
public static String language = "none";
|
||||
|
||||
@Rule(
|
||||
desc = "Nether portals correctly place entities going through",
|
||||
extra = "Entities shouldn't suffocate in obsidian",
|
||||
@@ -71,6 +95,7 @@ public class CarpetSettings
|
||||
)
|
||||
public static int portalSurvivalDelay = 80;
|
||||
|
||||
|
||||
private static class OneHourMaxDelayLimit extends Validator<Integer> {
|
||||
@Override public Integer validate(ServerCommandSource source, ParsedRule<Integer> currentRule, Integer newValue, String string) {
|
||||
return (newValue > 0 && newValue <= 72000) ? newValue : null;
|
||||
@@ -236,13 +261,6 @@ public class CarpetSettings
|
||||
@Rule( desc = "Pistons can push block entities, like hoppers, chests etc.", category = {EXPERIMENTAL, FEATURE} )
|
||||
public static boolean movableBlockEntities = false;
|
||||
|
||||
/*@Rule(
|
||||
desc = "Orange stained glass behaves like slime, but doesn't stick to it",
|
||||
extra = "Only available for 1.14. in 1.15 use honey instead",
|
||||
category = {EXPERIMENTAL, FEATURE}
|
||||
)
|
||||
public static boolean honeySlime = false;*/
|
||||
|
||||
@Rule( desc = "Saplings turn into dead shrubs in hot climates and no water access", category = FEATURE )
|
||||
public static boolean desertShrubs = false;
|
||||
|
||||
@@ -308,7 +326,7 @@ public class CarpetSettings
|
||||
)
|
||||
public static String commandPerimeterInfo = "true";
|
||||
|
||||
@Rule(desc = "Enables /draw commands", extra = "... allows for drawing simple shapes", category = COMMAND)
|
||||
@Rule(desc = "Enables /draw commands", extra = {"... allows for drawing simple shapes or","other shapes which are sorta difficult to do normally"}, category = COMMAND)
|
||||
public static String commandDraw = "true";
|
||||
|
||||
@Rule(
|
||||
@@ -356,9 +374,6 @@ public class CarpetSettings
|
||||
@Rule(desc = "Pistons, Glass and Sponge can be broken faster with their appropriate tools", category = SURVIVAL)
|
||||
public static boolean missingTools = false;
|
||||
|
||||
//@Rule(desc = "Alternative, persistent caching strategy for nether portals", category = {SURVIVAL, CREATIVE})
|
||||
//public static boolean portalCaching = false; // ineffective in 1.15
|
||||
|
||||
@Rule(desc = "fill/clone/setblock and structure blocks cause block updates", category = CREATIVE)
|
||||
public static boolean fillUpdates = true;
|
||||
|
||||
@@ -472,7 +487,7 @@ public class CarpetSettings
|
||||
{
|
||||
@Override public Integer validate(ServerCommandSource source, ParsedRule<Integer> currentRule, Integer newValue, String string)
|
||||
{
|
||||
if (currentRule.get().equals(newValue))
|
||||
if (currentRule.get().equals(newValue) || source == null)
|
||||
{
|
||||
return newValue;
|
||||
}
|
||||
@@ -486,8 +501,8 @@ public class CarpetSettings
|
||||
if (server.isDedicated())
|
||||
{
|
||||
int vd = (newValue >= 2)?newValue:((DedicatedServer) server).getProperties().viewDistance;
|
||||
if (vd != CarpetServer.minecraft_server.getPlayerManager().getViewDistance())
|
||||
CarpetServer.minecraft_server.getPlayerManager().setViewDistance(vd);
|
||||
if (vd != server.getPlayerManager().getViewDistance())
|
||||
server.getPlayerManager().setViewDistance(vd);
|
||||
return newValue;
|
||||
}
|
||||
else
|
||||
@@ -509,13 +524,9 @@ public class CarpetSettings
|
||||
)
|
||||
public static int viewDistance = 0;
|
||||
|
||||
private static class DisableSpawnChunksValidator extends Validator<Boolean> {
|
||||
@Override public Boolean validate(ServerCommandSource source, ParsedRule<Boolean> currentRule, Boolean newValue, String string) {
|
||||
if (currentRule.get().booleanValue() == newValue.booleanValue())
|
||||
{
|
||||
//must been some startup thing
|
||||
return newValue;
|
||||
}
|
||||
public static class ChangeSpawnChunksValidator extends Validator<Integer> {
|
||||
public static void changeSpawnSize(int size)
|
||||
{
|
||||
ServerWorld overworld = CarpetServer.minecraft_server.getWorld(DimensionType.OVERWORLD);
|
||||
if (overworld != null) {
|
||||
ChunkPos centerChunk = new ChunkPos(new BlockPos(
|
||||
@@ -523,40 +534,39 @@ public class CarpetSettings
|
||||
overworld.getLevelProperties().getSpawnY(),
|
||||
overworld.getLevelProperties().getSpawnZ()
|
||||
));
|
||||
ServerChunkManager chunkManager = (ServerChunkManager) overworld.getChunkManager();
|
||||
|
||||
chunkManager.removeTicket(ChunkTicketType.START, centerChunk, 11, Unit.INSTANCE);
|
||||
if (!newValue)
|
||||
{
|
||||
chunkManager.addTicket(ChunkTicketType.START, centerChunk, 11, Unit.INSTANCE);
|
||||
}
|
||||
SpawnChunks.changeSpawnChunks(overworld.getChunkManager(), centerChunk, size);
|
||||
}
|
||||
}
|
||||
@Override public Integer validate(ServerCommandSource source, ParsedRule<Integer> currentRule, Integer newValue, String string) {
|
||||
if (source == null) return newValue;
|
||||
if (newValue < 0 || newValue > 32)
|
||||
{
|
||||
Messenger.m(source, "r spawn chunk size has to be between 0 and 32");
|
||||
return null;
|
||||
}
|
||||
if (currentRule.get().intValue() == newValue.intValue())
|
||||
{
|
||||
//must been some startup thing
|
||||
return newValue;
|
||||
}
|
||||
if (CarpetServer.minecraft_server == null) return newValue;
|
||||
ServerWorld currentOverworld = CarpetServer.minecraft_server.getWorld(DimensionType.OVERWORLD);
|
||||
if (currentOverworld != null)
|
||||
{
|
||||
changeSpawnSize(newValue);
|
||||
}
|
||||
return newValue;
|
||||
}
|
||||
}
|
||||
@Rule(
|
||||
desc = "Allows spawn chunks to unload",
|
||||
desc = "Changes size of spawn chunks",
|
||||
extra = {"Defines new radius", "setting it to 0 - disables spawn chunks"},
|
||||
category = CREATIVE,
|
||||
validate = DisableSpawnChunksValidator.class
|
||||
)
|
||||
public static boolean disableSpawnChunks = false;
|
||||
|
||||
/*private static class KelpLimit extends Validator<Integer>
|
||||
{
|
||||
@Override public Integer validate(ServerCommandSource source, ParsedRule<Integer> currentRule, Integer newValue, String string) {
|
||||
return (newValue>=0 && newValue <=25)?newValue:null;
|
||||
}
|
||||
@Override
|
||||
public String description() { return "You must choose a value from 0 to 25. 25 and all natural kelp can grow 25 blocks, choose 0 to make all generated kelp not to grow";}
|
||||
}
|
||||
@Rule(
|
||||
desc = "limits growth limit of newly naturally generated kelp to this amount of blocks",
|
||||
options = {"0", "2", "25"},
|
||||
category = FEATURE,
|
||||
strict = false,
|
||||
validate = KelpLimit.class
|
||||
options = {"0", "11"},
|
||||
validate = ChangeSpawnChunksValidator.class
|
||||
)
|
||||
public static int kelpGenerationGrowthLimit = 25;*/
|
||||
public static int spawnChunksSize = 11;
|
||||
|
||||
@Rule(desc = "Coral structures will grow with bonemeal from coral plants", category = FEATURE)
|
||||
public static boolean renewableCoral = false;
|
||||
@@ -573,13 +583,6 @@ public class CarpetSettings
|
||||
|
||||
@Rule(desc = "Spawning requires much less CPU and Memory", category = OPTIMIZATION)
|
||||
public static boolean lagFreeSpawning = false;
|
||||
|
||||
//@Rule(
|
||||
// desc = "Prevents horses and other mobs to wander into the distance after dismounting",
|
||||
// extra = "Fixes issues with various Joergens wandering off and disappearing client-side",
|
||||
// category = BUGFIX
|
||||
//)
|
||||
//public static boolean horseWanderingFix = false;
|
||||
|
||||
@Rule(
|
||||
desc = "Allows structure mobs to spawn in flat worlds",
|
||||
@@ -599,4 +602,54 @@ public class CarpetSettings
|
||||
category = CREATIVE
|
||||
)
|
||||
public static boolean extremeBehaviours = false;
|
||||
|
||||
@Rule(
|
||||
desc = "Removes fog from client in the nether and the end",
|
||||
extra = "Improves visibility, but looks weird",
|
||||
category = CLIENT
|
||||
)
|
||||
public static boolean fogOff = false;
|
||||
|
||||
@Rule(
|
||||
desc = "Creative No Clip",
|
||||
extra = {
|
||||
"On servers it needs to be set on both ",
|
||||
"client and server to function properly.",
|
||||
"Has no effect when set on the server only",
|
||||
"Can allow to phase through walls",
|
||||
"if only set on the carpet client side",
|
||||
"but requires some trapdoor magic to",
|
||||
"allow the player to enter blocks"
|
||||
},
|
||||
category = {CREATIVE, CLIENT}
|
||||
)
|
||||
public static boolean creativeNoClip = false;
|
||||
|
||||
|
||||
@Rule(
|
||||
desc = "Creative flying speed multiplier",
|
||||
extra = {
|
||||
"Purely client side setting, meaning that",
|
||||
"having it set on the decicated server has no effect",
|
||||
"but this also means it will work on vanilla servers as well"
|
||||
},
|
||||
category = {CREATIVE, CLIENT},
|
||||
validate = Validator.NONNEGATIVE_NUMBER.class
|
||||
)
|
||||
public static double creativeFlySpeed = 1.0;
|
||||
|
||||
@Rule(
|
||||
desc = "Creative air drag",
|
||||
extra = {
|
||||
"Increased drag will slow down your flight",
|
||||
"So need to adjust speed accordingly",
|
||||
"With 1.0 drag, using speed of 11 seems to matching vanilla speeds.",
|
||||
"Purely client side setting, meaning that",
|
||||
"having it set on the decicated server has no effect",
|
||||
"but this also means it will work on vanilla servers as well"
|
||||
},
|
||||
category = {CREATIVE, CLIENT},
|
||||
validate = Validator.PROBABILITY.class
|
||||
)
|
||||
public static double creativeFlyDrag = 0.09;
|
||||
}
|
||||
@@ -7,6 +7,11 @@ import com.google.common.collect.Lists;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
|
||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.pattern.CachedBlockPosition;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
@@ -18,12 +23,15 @@ import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.lang.Math;
|
||||
|
||||
import static net.minecraft.server.command.CommandManager.argument;
|
||||
import static net.minecraft.server.command.CommandManager.literal;
|
||||
import static net.minecraft.server.command.CommandSource.suggestMatching;
|
||||
|
||||
public class DrawCommand
|
||||
{
|
||||
@@ -32,45 +40,142 @@ public class DrawCommand
|
||||
LiteralArgumentBuilder<ServerCommandSource> command = literal("draw").
|
||||
requires((player) -> SettingsManager.canUseCommand(player, CarpetSettings.commandDraw)).
|
||||
then(literal("sphere").
|
||||
then(argument("center",BlockPosArgumentType.blockPos()).
|
||||
then(argument("radius",IntegerArgumentType.integer(1)).
|
||||
then(argument("block",BlockStateArgumentType.blockState()).
|
||||
executes((c)-> drawCircle(
|
||||
c.getSource(),
|
||||
BlockPosArgumentType.getBlockPos(c, "center"),
|
||||
IntegerArgumentType.getInteger(c, "radius"),
|
||||
BlockStateArgumentType.getBlockState (c,"block"),
|
||||
null
|
||||
)
|
||||
).
|
||||
then(literal("replace").
|
||||
then(argument("filter",BlockPredicateArgumentType.blockPredicate())
|
||||
.executes((c)-> drawCircle(
|
||||
c.getSource(),
|
||||
BlockPosArgumentType.getBlockPos(c, "center"),
|
||||
IntegerArgumentType.getInteger(c, "radius"),
|
||||
BlockStateArgumentType.getBlockState(c,"block"),
|
||||
BlockPredicateArgumentType.getBlockPredicate(c,
|
||||
"filter")
|
||||
))))))));
|
||||
then(argument("center", BlockPosArgumentType.blockPos()).
|
||||
then(argument("radius", IntegerArgumentType.integer(1)).
|
||||
then(drawShape(c -> DrawCommand.drawSphere(c, false)))))).
|
||||
then(literal("ball").
|
||||
then(argument("center", BlockPosArgumentType.blockPos()).
|
||||
then(argument("radius", IntegerArgumentType.integer(1)).
|
||||
then(drawShape(c -> DrawCommand.drawSphere(c, true)))))).
|
||||
then(literal("diamond").
|
||||
then(argument("center", BlockPosArgumentType.blockPos()).
|
||||
then(argument("radius", IntegerArgumentType.integer(1)).
|
||||
then(drawShape(c -> DrawCommand.drawDiamond(c, true)))))).
|
||||
then(literal("pyramid").
|
||||
then(argument("center", BlockPosArgumentType.blockPos()).
|
||||
then(argument("radius", IntegerArgumentType.integer(1)).
|
||||
then(argument("height",IntegerArgumentType.integer(1)).
|
||||
then(argument("pointing",StringArgumentType.word()).suggests( (c, b) -> suggestMatching(new String[]{"up","down"},b)).
|
||||
then(argument("orientation",StringArgumentType.word()).suggests( (c, b) -> suggestMatching(new String[]{"y","x","z"},b)).
|
||||
then(drawShape(c -> DrawCommand.drawPyramid(c, "square", true))))))))).
|
||||
then(literal("cone").
|
||||
then(argument("center", BlockPosArgumentType.blockPos()).
|
||||
then(argument("radius", IntegerArgumentType.integer(1)).
|
||||
then(argument("height",IntegerArgumentType.integer(1)).
|
||||
then(argument("pointing",StringArgumentType.word()).suggests( (c, b) -> suggestMatching(new String[]{"up","down"},b)).
|
||||
then(argument("orientation",StringArgumentType.word()).suggests( (c, b) -> suggestMatching(new String[]{"y","x","z"},b))
|
||||
.then(drawShape(c -> DrawCommand.drawPyramid(c, "circle", true))))))))).
|
||||
then(literal("cylinder").
|
||||
then(argument("center", BlockPosArgumentType.blockPos()).
|
||||
then(argument("radius", IntegerArgumentType.integer(1)).
|
||||
then(argument("height",IntegerArgumentType.integer(1)).
|
||||
then(argument("orientation",StringArgumentType.word()).suggests( (c, b) -> suggestMatching(new String[]{"y","x","z"},b))
|
||||
.then(drawShape(c -> DrawCommand.drawPrism(c, "circle")))))))).
|
||||
then(literal("cuboid").
|
||||
then(argument("center", BlockPosArgumentType.blockPos()).
|
||||
then(argument("radius", IntegerArgumentType.integer(1)).
|
||||
then(argument("height",IntegerArgumentType.integer(1)).
|
||||
then(argument("orientation",StringArgumentType.word()).suggests( (c, b) -> suggestMatching(new String[]{"y","x","z"},b))
|
||||
.then(drawShape(c -> DrawCommand.drawPrism(c, "square"))))))));
|
||||
dispatcher.register(command);
|
||||
}
|
||||
|
||||
|
||||
private static int drawCircle(ServerCommandSource source, BlockPos pos, int radius, BlockStateArgument block,
|
||||
Predicate<CachedBlockPosition> replacement)
|
||||
@FunctionalInterface
|
||||
private interface OptionalBlockSelector
|
||||
{
|
||||
return drawCircle(source, pos, (double)radius, (double)radius, (double)radius, block, replacement, false);
|
||||
Integer apply(final CommandContext<ServerCommandSource> ctx) throws CommandSyntaxException;
|
||||
}
|
||||
private static int drawCircle(ServerCommandSource source, BlockPos pos, double radiusX, double radiusY, double radiusZ,
|
||||
BlockStateArgument block, Predicate<CachedBlockPosition> replacement, boolean solid)
|
||||
{
|
||||
int affected = 0;
|
||||
ServerWorld world = source.getWorld();
|
||||
|
||||
radiusX += 0.5;
|
||||
radiusY += 0.5;
|
||||
radiusZ += 0.5;
|
||||
@FunctionalInterface
|
||||
private interface ArgumentExtractor<T>
|
||||
{
|
||||
T apply(final CommandContext<ServerCommandSource> ctx, final String argName) throws CommandSyntaxException;
|
||||
}
|
||||
|
||||
private static RequiredArgumentBuilder<ServerCommandSource, BlockStateArgument>
|
||||
drawShape(OptionalBlockSelector drawer)
|
||||
{
|
||||
return argument("block", BlockStateArgumentType.blockState()).
|
||||
executes(drawer::apply)
|
||||
.then(literal("replace")
|
||||
.then(argument("filter", BlockPredicateArgumentType.blockPredicate())
|
||||
.executes(drawer::apply)));
|
||||
}
|
||||
|
||||
private static class ErrorHandled extends RuntimeException {}
|
||||
|
||||
private static <T> T getArg(CommandContext<ServerCommandSource> ctx, ArgumentExtractor<T> extract, String hwat) throws CommandSyntaxException
|
||||
{
|
||||
return getArg(ctx, extract, hwat, false);
|
||||
}
|
||||
|
||||
private static <T> T getArg(CommandContext<ServerCommandSource> ctx, ArgumentExtractor<T> extract, String hwat, boolean optional) throws CommandSyntaxException
|
||||
{
|
||||
T arg = null;
|
||||
try
|
||||
{
|
||||
arg = extract.apply(ctx, hwat);
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
if (optional) return null;
|
||||
Messenger.m(ctx.getSource(), "rb Missing "+hwat);
|
||||
throw new ErrorHandled();
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
private static double lengthSq(double x, double y, double z)
|
||||
{
|
||||
return (x * x) + (y * y) + (z * z);
|
||||
}
|
||||
|
||||
private static int setBlock(
|
||||
ServerWorld world, BlockPos.Mutable mbpos, int x, int y, int z,
|
||||
BlockStateArgument block, Predicate<CachedBlockPosition> replacement,
|
||||
List<BlockPos> list
|
||||
)
|
||||
{
|
||||
mbpos.set(x, y, z);
|
||||
int success=0;
|
||||
if (replacement == null || replacement.test(new CachedBlockPosition(world, mbpos, true)))
|
||||
{
|
||||
BlockEntity tileentity = world.getBlockEntity(mbpos);
|
||||
if (tileentity instanceof Inventory)
|
||||
{
|
||||
((Inventory) tileentity).clear();
|
||||
}
|
||||
if (block.setBlockState(world, mbpos, 2))
|
||||
{
|
||||
list.add(mbpos.toImmutable());
|
||||
++success;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private static int drawSphere(CommandContext<ServerCommandSource> ctx, boolean solid) throws CommandSyntaxException
|
||||
{
|
||||
BlockPos pos;
|
||||
int radius;
|
||||
BlockStateArgument block;
|
||||
Predicate<CachedBlockPosition> replacement;
|
||||
try
|
||||
{
|
||||
pos = getArg(ctx, BlockPosArgumentType::getBlockPos, "center");
|
||||
radius = getArg(ctx, IntegerArgumentType::getInteger, "radius");
|
||||
block = getArg(ctx, BlockStateArgumentType::getBlockState, "block");
|
||||
replacement = getArg(ctx, BlockPredicateArgumentType::getBlockPredicate, "filter", true);
|
||||
}
|
||||
catch (ErrorHandled ignored) { return 0; }
|
||||
|
||||
int affected = 0;
|
||||
ServerWorld world = ctx.getSource().getWorld();
|
||||
|
||||
double radiusX = radius+0.5;
|
||||
double radiusY = radius+0.5;
|
||||
double radiusZ = radius+0.5;
|
||||
|
||||
final double invRadiusX = 1 / radiusX;
|
||||
final double invRadiusY = 1 / radiusY;
|
||||
@@ -85,22 +190,28 @@ public class DrawCommand
|
||||
|
||||
double nextXn = 0;
|
||||
|
||||
forX: for (int x = 0; x <= ceilRadiusX; ++x) {
|
||||
forX: for (int x = 0; x <= ceilRadiusX; ++x)
|
||||
{
|
||||
final double xn = nextXn;
|
||||
nextXn = (x + 1) * invRadiusX;
|
||||
double nextYn = 0;
|
||||
forY: for (int y = 0; y <= ceilRadiusY; ++y) {
|
||||
forY: for (int y = 0; y <= ceilRadiusY; ++y)
|
||||
{
|
||||
final double yn = nextYn;
|
||||
nextYn = (y + 1) * invRadiusY;
|
||||
double nextZn = 0;
|
||||
forZ: for (int z = 0; z <= ceilRadiusZ; ++z) {
|
||||
forZ: for (int z = 0; z <= ceilRadiusZ; ++z)
|
||||
{
|
||||
final double zn = nextZn;
|
||||
nextZn = (z + 1) * invRadiusZ;
|
||||
|
||||
double distanceSq = lengthSq(xn, yn, zn);
|
||||
if (distanceSq > 1) {
|
||||
if (z == 0) {
|
||||
if (y == 0) {
|
||||
if (distanceSq > 1)
|
||||
{
|
||||
if (z == 0)
|
||||
{
|
||||
if (y == 0)
|
||||
{
|
||||
break forX;
|
||||
}
|
||||
break forY;
|
||||
@@ -108,35 +219,22 @@ public class DrawCommand
|
||||
break forZ;
|
||||
}
|
||||
|
||||
if (!solid) {
|
||||
if (lengthSq(nextXn, yn, zn) <= 1 && lengthSq(xn, nextYn, zn) <= 1 && lengthSq(xn, yn, nextZn) <= 1) {
|
||||
continue;
|
||||
}
|
||||
if (!solid && lengthSq(nextXn, yn, zn) <= 1 && lengthSq(xn, nextYn, zn) <= 1 && lengthSq(xn, yn, nextZn) <= 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
CarpetSettings.impendingFillSkipUpdates = !CarpetSettings.fillUpdates;
|
||||
for (int xmod = -1; xmod < 2; xmod+= 2)
|
||||
for (int xmod = -1; xmod < 2; xmod += 2)
|
||||
{
|
||||
for (int ymod = -1; ymod < 2; ymod += 2)
|
||||
{
|
||||
for (int zmod = -1; zmod < 2; zmod += 2)
|
||||
{
|
||||
mbpos.set(pos.getX()+xmod*x, pos.getY()+ymod*y, pos.getZ()+zmod*z);
|
||||
if (replacement == null || replacement.test(
|
||||
new CachedBlockPosition( world, mbpos, true)))
|
||||
{
|
||||
BlockEntity tileentity = world.getBlockEntity(mbpos);
|
||||
if (tileentity instanceof Inventory)
|
||||
{
|
||||
((Inventory)tileentity).clear();
|
||||
}
|
||||
|
||||
if (block.setBlockState(world, mbpos,2))
|
||||
{
|
||||
list.add(mbpos.toImmutable());
|
||||
++affected;
|
||||
}
|
||||
}
|
||||
affected+= setBlock(world, mbpos,
|
||||
pos.getX() + xmod * x, pos.getY() + ymod * y, pos.getZ() + zmod * z,
|
||||
block, replacement, list
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,19 +244,212 @@ public class DrawCommand
|
||||
}
|
||||
if (CarpetSettings.fillUpdates)
|
||||
{
|
||||
list.forEach(blockpos1 -> world.updateNeighbors(blockpos1, world.getBlockState(blockpos1).getBlock()));
|
||||
}
|
||||
Messenger.m(ctx.getSource(), "gi Filled " + affected + " blocks");
|
||||
return affected;
|
||||
}
|
||||
|
||||
for (BlockPos blockpos1 : list)
|
||||
private static int drawDiamond(CommandContext<ServerCommandSource> ctx, boolean solid) throws CommandSyntaxException
|
||||
{
|
||||
BlockPos pos;
|
||||
int radius;
|
||||
BlockStateArgument block;
|
||||
Predicate<CachedBlockPosition> replacement;
|
||||
try
|
||||
{
|
||||
pos = getArg(ctx, BlockPosArgumentType::getBlockPos, "center");
|
||||
radius = getArg(ctx, IntegerArgumentType::getInteger, "radius");
|
||||
block = getArg(ctx, BlockStateArgumentType::getBlockState, "block");
|
||||
replacement = getArg(ctx, BlockPredicateArgumentType::getBlockPredicate, "filter", true);
|
||||
}
|
||||
catch (ErrorHandled ignored) { return 0; }
|
||||
|
||||
ServerCommandSource source = ctx.getSource();
|
||||
|
||||
int affected=0;
|
||||
|
||||
BlockPos.Mutable mbpos = new BlockPos.Mutable(pos);
|
||||
List<BlockPos> list = Lists.newArrayList();
|
||||
|
||||
ServerWorld world = source.getWorld();
|
||||
|
||||
CarpetSettings.impendingFillSkipUpdates = !CarpetSettings.fillUpdates;
|
||||
|
||||
for (int r = 0; r < radius; ++r)
|
||||
{
|
||||
int y=r-radius+1;
|
||||
for (int x = -r; x <= r; ++x)
|
||||
{
|
||||
Block blokc = world.getBlockState(blockpos1).getBlock();
|
||||
world.updateNeighbors(blockpos1, blokc); // or always version????
|
||||
int z=r-Math.abs(x);
|
||||
|
||||
affected+= setBlock(world, mbpos, pos.getX()+x, pos.getY()-y, pos.getZ()+z, block, replacement, list);
|
||||
affected+= setBlock(world, mbpos, pos.getX()+x, pos.getY()-y, pos.getZ()-z, block, replacement, list);
|
||||
affected+= setBlock(world, mbpos, pos.getX()+x, pos.getY()+y, pos.getZ()+z, block, replacement, list);
|
||||
affected+= setBlock(world, mbpos, pos.getX()+x, pos.getY()+y, pos.getZ()-z, block, replacement, list);
|
||||
}
|
||||
}
|
||||
Messenger.m(source, "gi Filled "+affected+" blocks");
|
||||
|
||||
return 1;
|
||||
}
|
||||
private static double lengthSq(double x, double y, double z)
|
||||
CarpetSettings.impendingFillSkipUpdates = false;
|
||||
|
||||
if (CarpetSettings.fillUpdates)
|
||||
{
|
||||
return (x * x) + (y * y) + (z * z);
|
||||
list.forEach(p -> world.updateNeighbors(p, world.getBlockState(p).getBlock()));
|
||||
}
|
||||
|
||||
Messenger.m(source, "gi Filled " + affected + " blocks");
|
||||
|
||||
return affected;
|
||||
}
|
||||
|
||||
private static int fillFlat(
|
||||
ServerWorld world, BlockPos pos, int offset, double dr, boolean rectangle, String orientation,
|
||||
BlockStateArgument block, Predicate<CachedBlockPosition> replacement,
|
||||
List<BlockPos> list, BlockPos.Mutable mbpos
|
||||
)
|
||||
{
|
||||
int successes=0;
|
||||
int r = MathHelper.floor(dr);
|
||||
double drsq = dr*dr;
|
||||
if (orientation.equalsIgnoreCase("x"))
|
||||
{
|
||||
for(int a=-r; a<=r; ++a) for(int b=-r; b<=r; ++b) if(rectangle || a*a + b*b <= drsq)
|
||||
{
|
||||
successes += setBlock(
|
||||
world, mbpos,pos.getX()+offset, pos.getY()+a, pos.getZ()+b,
|
||||
block, replacement, list
|
||||
);
|
||||
}
|
||||
return successes;
|
||||
}
|
||||
if (orientation.equalsIgnoreCase("y"))
|
||||
{
|
||||
for(int a=-r; a<=r; ++a) for(int b=-r; b<=r; ++b) if(rectangle || a*a + b*b <= drsq)
|
||||
{
|
||||
successes += setBlock(
|
||||
world, mbpos,pos.getX()+a, pos.getY()+offset, pos.getZ()+b,
|
||||
block, replacement, list
|
||||
);
|
||||
}
|
||||
return successes;
|
||||
}
|
||||
if (orientation.equalsIgnoreCase("z"))
|
||||
{
|
||||
for(int a=-r; a<=r; ++a) for(int b=-r; b<=r; ++b) if(rectangle || a*a + b*b <= drsq)
|
||||
{
|
||||
successes += setBlock(
|
||||
world, mbpos,pos.getX()+b, pos.getY()+a, pos.getZ()+offset,
|
||||
block, replacement, list
|
||||
);
|
||||
}
|
||||
return successes;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int drawPyramid(CommandContext<ServerCommandSource> ctx, String base, boolean solid) throws CommandSyntaxException
|
||||
{
|
||||
BlockPos pos;
|
||||
double radius;
|
||||
int height;
|
||||
boolean pointup;
|
||||
String orientation;
|
||||
BlockStateArgument block;
|
||||
Predicate<CachedBlockPosition> replacement;
|
||||
try
|
||||
{
|
||||
pos = getArg(ctx, BlockPosArgumentType::getBlockPos, "center");
|
||||
radius = getArg(ctx, IntegerArgumentType::getInteger, "radius")+0.5D;
|
||||
height = getArg(ctx, IntegerArgumentType::getInteger, "height");
|
||||
pointup = getArg(ctx, StringArgumentType::getString, "pointing").equalsIgnoreCase("up");
|
||||
orientation = getArg(ctx, StringArgumentType::getString,"orientation");
|
||||
block = getArg(ctx, BlockStateArgumentType::getBlockState, "block");
|
||||
replacement = getArg(ctx, BlockPredicateArgumentType::getBlockPredicate, "filter", true);
|
||||
}
|
||||
catch (ErrorHandled ignored) { return 0; }
|
||||
|
||||
ServerCommandSource source = ctx.getSource();
|
||||
|
||||
int affected = 0;
|
||||
BlockPos.Mutable mbpos = new BlockPos.Mutable(pos);
|
||||
|
||||
List<BlockPos> list = Lists.newArrayList();
|
||||
|
||||
ServerWorld world = source.getWorld();
|
||||
|
||||
CarpetSettings.impendingFillSkipUpdates = !CarpetSettings.fillUpdates;
|
||||
|
||||
boolean isSquare = base.equalsIgnoreCase("square");
|
||||
|
||||
for(int i =0; i<height;++i)
|
||||
{
|
||||
double r = pointup ? radius - radius * i / height - 1 : radius * i / height;
|
||||
affected+= fillFlat(world, pos, i, r, isSquare, orientation, block, replacement, list, mbpos);
|
||||
}
|
||||
|
||||
CarpetSettings.impendingFillSkipUpdates = false;
|
||||
|
||||
if (CarpetSettings.fillUpdates) {
|
||||
|
||||
for (BlockPos blockpos1 : list) {
|
||||
Block blokc = world.getBlockState(blockpos1).getBlock();
|
||||
world.updateNeighbors(blockpos1, blokc);
|
||||
}
|
||||
}
|
||||
|
||||
Messenger.m(source, "gi Filled " + affected + " blocks");
|
||||
|
||||
return affected;
|
||||
}
|
||||
|
||||
private static int drawPrism(CommandContext<ServerCommandSource> ctx, String base){
|
||||
BlockPos pos;
|
||||
double radius;
|
||||
int height;
|
||||
String orientation;
|
||||
BlockStateArgument block;
|
||||
Predicate<CachedBlockPosition> replacement;
|
||||
try
|
||||
{
|
||||
pos = getArg(ctx, BlockPosArgumentType::getBlockPos, "center");
|
||||
radius = getArg(ctx, IntegerArgumentType::getInteger, "radius")+0.5D;
|
||||
height = getArg(ctx, IntegerArgumentType::getInteger, "height");
|
||||
orientation = getArg(ctx, StringArgumentType::getString,"orientation");
|
||||
block = getArg(ctx, BlockStateArgumentType::getBlockState, "block");
|
||||
replacement = getArg(ctx, BlockPredicateArgumentType::getBlockPredicate, "filter", true);
|
||||
}
|
||||
catch (ErrorHandled | CommandSyntaxException ignored) { return 0; }
|
||||
|
||||
ServerCommandSource source = ctx.getSource();
|
||||
|
||||
int affected = 0;
|
||||
BlockPos.Mutable mbpos = new BlockPos.Mutable(pos);
|
||||
|
||||
List<BlockPos> list = Lists.newArrayList();
|
||||
|
||||
ServerWorld world = source.getWorld();
|
||||
|
||||
CarpetSettings.impendingFillSkipUpdates = !CarpetSettings.fillUpdates;
|
||||
|
||||
boolean isSquare = base.equalsIgnoreCase("square");
|
||||
|
||||
for(int i =0; i<height;++i)
|
||||
{
|
||||
affected+= fillFlat(world, pos, i, radius, isSquare, orientation, block, replacement, list, mbpos);
|
||||
}
|
||||
|
||||
CarpetSettings.impendingFillSkipUpdates = false;
|
||||
|
||||
if (CarpetSettings.fillUpdates) {
|
||||
|
||||
for (BlockPos blockpos1 : list) {
|
||||
Block blokc = world.getBlockState(blockpos1).getBlock();
|
||||
world.updateNeighbors(blockpos1, blokc);
|
||||
}
|
||||
}
|
||||
|
||||
Messenger.m(source, "gi Filled " + affected + " blocks");
|
||||
|
||||
return affected;
|
||||
}
|
||||
}
|
||||
@@ -296,6 +296,14 @@ public class PlayerCommand
|
||||
Messenger.m(context.getSource(), "r Cannot shadow fake players");
|
||||
return 0;
|
||||
}
|
||||
ServerPlayerEntity sendingPlayer = null;
|
||||
try
|
||||
{
|
||||
sendingPlayer = context.getSource().getPlayer();
|
||||
}
|
||||
catch (CommandSyntaxException ignored) { }
|
||||
|
||||
if (sendingPlayer!=player && cantManipulate(context)) return 0;
|
||||
EntityPlayerMPFake.createShadow(player.server, player);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import net.minecraft.command.arguments.DimensionArgumentType;
|
||||
import net.minecraft.entity.EntityCategory;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.util.DyeColor;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
@@ -98,7 +99,8 @@ public class SpawnCommand
|
||||
executes( (c) -> generalMobcaps(c.getSource()) ).
|
||||
then(argument("type", string()).
|
||||
suggests( (c, b)->suggestMatching(Arrays.stream(EntityCategory.values()).map(EntityCategory::getName), b)).
|
||||
executes( (c) -> listEntitiesOfType(c.getSource(), getString(c, "type")))));
|
||||
executes( (c) -> listEntitiesOfType(c.getSource(), getString(c, "type"), false)).
|
||||
then(literal("all").executes( (c) -> listEntitiesOfType(c.getSource(), getString(c, "type"), true)))));
|
||||
|
||||
dispatcher.register(literalargumentbuilder);
|
||||
}
|
||||
@@ -194,7 +196,7 @@ public class SpawnCommand
|
||||
TickSpeed.tickrate_advance(null, 0, null, null);
|
||||
// tick warp given player
|
||||
ServerCommandSource csource = null;
|
||||
PlayerEntity player = null;
|
||||
ServerPlayerEntity player = null;
|
||||
try
|
||||
{
|
||||
player = source.getPlayer();
|
||||
@@ -262,10 +264,10 @@ public class SpawnCommand
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int listEntitiesOfType(ServerCommandSource source, String mobtype) throws CommandSyntaxException
|
||||
private static int listEntitiesOfType(ServerCommandSource source, String mobtype, boolean all) throws CommandSyntaxException
|
||||
{
|
||||
EntityCategory cat = getCategory(mobtype);
|
||||
Messenger.send(source, SpawnReporter.printEntitiesByType(cat, source.getWorld()));
|
||||
Messenger.send(source, SpawnReporter.printEntitiesByType(cat, source.getWorld(), all));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.BaseText;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
|
||||
@@ -43,7 +44,8 @@ public class TickCommand
|
||||
c.getSource(),
|
||||
getInteger(c,"ticks"),
|
||||
getString(c, "tail command")))))).
|
||||
then(literal("freeze").executes( (c)-> toggleFreeze(c.getSource()))).
|
||||
then(literal("freeze").executes( (c)-> toggleFreeze(c.getSource(), false)).
|
||||
then(literal("deep").executes( (c)-> toggleFreeze(c.getSource(), true)))).
|
||||
then(literal("step").
|
||||
executes((c) -> step(1)).
|
||||
then(argument("ticks", integer(1,72000)).
|
||||
@@ -66,7 +68,7 @@ public class TickCommand
|
||||
|
||||
private static int setTps(ServerCommandSource source, float tps)
|
||||
{
|
||||
TickSpeed.tickrate(tps);
|
||||
TickSpeed.tickrate(tps, true);
|
||||
queryTps(source);
|
||||
return (int)tps;
|
||||
}
|
||||
@@ -79,7 +81,7 @@ public class TickCommand
|
||||
|
||||
private static int setWarp(ServerCommandSource source, int advance, String tail_command)
|
||||
{
|
||||
PlayerEntity player = null;
|
||||
ServerPlayerEntity player = null;
|
||||
try
|
||||
{
|
||||
player = source.getPlayer();
|
||||
@@ -95,15 +97,18 @@ public class TickCommand
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int toggleFreeze(ServerCommandSource source)
|
||||
private static int toggleFreeze(ServerCommandSource source, boolean isDeep)
|
||||
{
|
||||
TickSpeed.is_paused = !TickSpeed.is_paused;
|
||||
if (TickSpeed.is_paused)
|
||||
{
|
||||
Messenger.m(source, "gi Game is paused");
|
||||
TickSpeed.deepFreeze = isDeep;
|
||||
Messenger.m(source, "gi Game is "+(isDeep?"deeply ":"")+"frozen");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
TickSpeed.deepFreeze = false;
|
||||
Messenger.m(source, "gi Game runs normally");
|
||||
}
|
||||
return 1;
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package carpet.fakes;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import net.minecraft.server.world.ChunkTicket;
|
||||
import net.minecraft.util.SortedArraySet;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
|
||||
public interface ChunkTicketManagerInterface
|
||||
{
|
||||
void changeSpawnChunks(ChunkPos pos, int distance);
|
||||
Long2ObjectOpenHashMap<SortedArraySet<ChunkTicket<?>>> getTicketsByPosition();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package carpet.fakes;
|
||||
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.PacketByteBuf;
|
||||
|
||||
public interface CustomPayloadC2SPacketInterface
|
||||
{
|
||||
Identifier getPacketChannel();
|
||||
PacketByteBuf getPacketData();
|
||||
}
|
||||
@@ -11,4 +11,8 @@ public interface EntityInterface
|
||||
boolean isPermanentVehicle();
|
||||
|
||||
void setPermanentVehicle(boolean permanent);
|
||||
|
||||
int getPortalTimer();
|
||||
|
||||
void setPortalTimer(int amount);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package carpet.fakes;
|
||||
|
||||
public interface HungerManagerInterface {
|
||||
float getExhaustionCM();
|
||||
void setExhaustionCM(float exhaust);
|
||||
}
|
||||
@@ -2,6 +2,6 @@ package carpet.fakes;
|
||||
|
||||
public interface ItemEntityInterface
|
||||
{
|
||||
int getAge();
|
||||
int getPickupDelay();
|
||||
int getAgeCM();
|
||||
int getPickupDelayCM();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package carpet.fakes;
|
||||
|
||||
public interface LivingEntityInterface
|
||||
{
|
||||
void doJumpCM(); // added CM suffix to remove potential collisions with other mods
|
||||
boolean isJumpingCM();
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package carpet.fakes;
|
||||
|
||||
import net.minecraft.server.world.ChunkTicketManager;
|
||||
|
||||
public interface ServerChunkManagerInterface
|
||||
{
|
||||
ChunkTicketManager getCMTicketManager();
|
||||
}
|
||||
@@ -263,6 +263,15 @@ public class BlockRotator
|
||||
}
|
||||
world.setBlockState(blockpos, iblockstate.with(HorizontalFacingBlock.FACING, face), 3);
|
||||
}
|
||||
else if(block == Blocks.HOPPER )
|
||||
{
|
||||
Direction face = iblockstate.get(HopperBlock.FACING);
|
||||
if (face != Direction.DOWN)
|
||||
{
|
||||
face = rotateClockwise(face, Direction.Axis.Y);
|
||||
world.setBlockState(blockpos, iblockstate.with(HopperBlock.FACING, face), 3);
|
||||
}
|
||||
}
|
||||
// Send block update to the block that just have been rotated.
|
||||
world.updateNeighbor(blockpos, block, source.getBlockPos());
|
||||
|
||||
@@ -270,8 +279,6 @@ public class BlockRotator
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static boolean flip_block(BlockState state, World world, PlayerEntity player, Hand hand, BlockHitResult hit)
|
||||
{
|
||||
Block block = state.getBlock();
|
||||
|
||||
@@ -390,6 +390,7 @@ public class EntityPlayerActionPack
|
||||
{
|
||||
player.interactionManager.processBlockBreakingAction(pos, PlayerActionC2SPacket.Action.STOP_DESTROY_BLOCK, side, player.server.getWorldHeight());
|
||||
ap.currentBlock = null;
|
||||
ap.blockHitDelay = 5;
|
||||
blockBroken = true;
|
||||
}
|
||||
player.world.setBlockBreakingInfo(-1, pos, (int) (ap.curBlockDamageMP * 10));
|
||||
|
||||
@@ -6,13 +6,19 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Sets;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.structure.StructureManager;
|
||||
import net.minecraft.structure.StructureStart;
|
||||
import net.minecraft.util.math.BlockBox;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.biome.Biomes;
|
||||
import net.minecraft.world.biome.DefaultBiomeFeatures;
|
||||
import net.minecraft.world.biome.source.BiomeAccess;
|
||||
import net.minecraft.world.biome.source.BiomeSource;
|
||||
import net.minecraft.world.biome.source.VanillaLayeredBiomeSource;
|
||||
import net.minecraft.world.biome.source.VanillaLayeredBiomeSourceConfig;
|
||||
import net.minecraft.world.gen.ChunkRandom;
|
||||
import net.minecraft.world.gen.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.gen.chunk.OverworldChunkGenerator;
|
||||
import net.minecraft.world.gen.chunk.OverworldChunkGeneratorConfig;
|
||||
@@ -141,26 +147,47 @@ public class FeatureGenerator
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StructureStart shouldStructureStartAt(ServerWorld world, BlockPos pos, StructureFeature<?> structure, boolean computeBox)
|
||||
{
|
||||
ChunkGenerator<?> generator = world.getChunkManager().getChunkGenerator();
|
||||
if (!generator.getBiomeSource().hasStructureFeature(structure))
|
||||
return null;
|
||||
BiomeAccess biomeAccess = world.getBiomeAccess().withSource(generator.getBiomeSource());
|
||||
ChunkRandom chunkRandom = new ChunkRandom();
|
||||
ChunkPos chunkPos = new ChunkPos(pos);
|
||||
Biome biome = biomeAccess.getBiome(new BlockPos(chunkPos.getStartX() + 9, 0, chunkPos.getStartZ() + 9));
|
||||
if (structure.shouldStartAt(biomeAccess, generator, chunkRandom, chunkPos.x, chunkPos.z, biome))
|
||||
{
|
||||
if (!computeBox) return StructureStart.DEFAULT;
|
||||
StructureManager manager = world.getSaveHandler().getStructureManager();
|
||||
StructureStart structureStart3 = structure.getStructureStartFactory().create(structure, chunkPos.x, chunkPos.z, BlockBox.empty(), 0, generator.getSeed());
|
||||
structureStart3.initialize(generator, manager, chunkPos.x, chunkPos.z, biome);
|
||||
if (!structureStart3.hasChildren()) return null;
|
||||
return structureStart3;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static final Map<String, List<String>> structureToFeature = new HashMap<>();
|
||||
public static final Map<String, String> featureToStructure = new HashMap<>();
|
||||
static
|
||||
{
|
||||
structureToFeature.put("Monument", Collections.singletonList("monument"));
|
||||
structureToFeature.put("EndCity", Collections.singletonList("end_city"));
|
||||
structureToFeature.put("Ocean_Ruin", Arrays.asList("ocean_ruin", "ocean_ruin_warm", "ocean_ruin_small", "ocean_ruin_warm_small", "ocean_ruin_tall", "ocean_ruin_warm_tall"));
|
||||
structureToFeature.put("Village", Arrays.asList("village", "village_desert", "village_savanna", "village_taiga", "village_snowy"));
|
||||
structureToFeature.put("Mansion", Collections.singletonList("mansion"));
|
||||
structureToFeature.put("Buried_Treasure", Collections.singletonList("treasure"));
|
||||
structureToFeature.put("Swamp_Hut", Collections.singletonList("witch_hut"));
|
||||
structureToFeature.put("Stronghold", Collections.singletonList("stronghold"));
|
||||
structureToFeature.put("Desert_Pyramid", Collections.singletonList("desert_temple"));
|
||||
structureToFeature.put("Jungle_Pyramid", Collections.singletonList("jungle_temple"));
|
||||
structureToFeature.put("Shipwreck", Arrays.asList("shipwreck", "shipwreck2"));
|
||||
structureToFeature.put("Pillager_Outpost", Collections.singletonList("pillager_outpost"));
|
||||
structureToFeature.put("Mineshaft", Arrays.asList("mineshaft", "mineshaft_mesa"));
|
||||
structureToFeature.put("Igloo", Collections.singletonList("igloo"));
|
||||
structureToFeature.put("Fortress", Collections.singletonList("fortress"));
|
||||
structureToFeature.put(Feature.OCEAN_MONUMENT.getName(), Collections.singletonList("monument"));
|
||||
structureToFeature.put(Feature.END_CITY.getName(), Collections.singletonList("end_city"));
|
||||
structureToFeature.put(Feature.OCEAN_RUIN.getName(), Arrays.asList("ocean_ruin", "ocean_ruin_warm", "ocean_ruin_small", "ocean_ruin_warm_small", "ocean_ruin_tall", "ocean_ruin_warm_tall"));
|
||||
structureToFeature.put(Feature.VILLAGE.getName(), Arrays.asList("village", "village_desert", "village_savanna", "village_taiga", "village_snowy"));
|
||||
structureToFeature.put(Feature.WOODLAND_MANSION.getName(), Collections.singletonList("mansion"));
|
||||
structureToFeature.put(Feature.BURIED_TREASURE.getName(), Collections.singletonList("treasure"));
|
||||
structureToFeature.put(Feature.SWAMP_HUT.getName(), Collections.singletonList("witch_hut"));
|
||||
structureToFeature.put(Feature.STRONGHOLD.getName(), Collections.singletonList("stronghold"));
|
||||
structureToFeature.put(Feature.DESERT_PYRAMID.getName(), Collections.singletonList("desert_temple"));
|
||||
structureToFeature.put(Feature.JUNGLE_TEMPLE.getName(), Collections.singletonList("jungle_temple"));
|
||||
structureToFeature.put(Feature.SHIPWRECK.getName(), Arrays.asList("shipwreck", "shipwreck2"));
|
||||
structureToFeature.put(Feature.PILLAGER_OUTPOST.getName(), Collections.singletonList("pillager_outpost"));
|
||||
structureToFeature.put(Feature.MINESHAFT.getName(), Arrays.asList("mineshaft", "mineshaft_mesa"));
|
||||
structureToFeature.put(Feature.IGLOO.getName(), Collections.singletonList("igloo"));
|
||||
structureToFeature.put(Feature.NETHER_BRIDGE.getName(), Collections.singletonList("fortress"));
|
||||
|
||||
structureToFeature.forEach((key, value) -> value.forEach(el -> featureToStructure.put(el, key)));
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ public class HopperCounter
|
||||
color, ticks*1.0/(20*60), (realTime?" - real time":""), total, total*1.0*(20*60*60)/ticks),
|
||||
"nb [X]", "^g reset", "!/counter "+color+" reset"
|
||||
));
|
||||
items.addAll(counter.object2LongEntrySet().stream().map(e ->
|
||||
items.addAll(counter.object2LongEntrySet().stream().sorted((e, f) -> Long.compare(f.getLongValue(), e.getLongValue())).map(e ->
|
||||
{
|
||||
BaseText itemName = new TranslatableText(e.getKey().getTranslationKey());
|
||||
long count = e.getLongValue();
|
||||
|
||||
@@ -7,8 +7,10 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import carpet.logging.logHelpers.ExplosionLogHelper;
|
||||
import carpet.mixins.ExplosionAccessor;
|
||||
import carpet.CarpetSettings;
|
||||
import carpet.mixins.ExplosionMixin;
|
||||
import carpet.utils.Messenger;
|
||||
import com.google.common.collect.Lists;
|
||||
import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap;
|
||||
@@ -51,6 +53,7 @@ public class OptimizedExplosion
|
||||
private static List<Entity> entitylist;
|
||||
private static Vec3d vec3dmem;
|
||||
private static long tickmem;
|
||||
private static Vec3d vec3dZero = new Vec3d(0, 0, 0);
|
||||
// For disabling the explosion particles and sound
|
||||
public static int explosionSound = 0;
|
||||
|
||||
@@ -66,7 +69,7 @@ public class OptimizedExplosion
|
||||
private static ArrayList<Float> chances = new ArrayList<>();
|
||||
private static BlockPos blastChanceLocation;
|
||||
|
||||
public static void doExplosionA(Explosion e) {
|
||||
public static void doExplosionA(Explosion e, ExplosionLogHelper eLogger) {
|
||||
ExplosionAccessor eAccess = (ExplosionAccessor) e;
|
||||
|
||||
blastCalc(e);
|
||||
@@ -120,6 +123,9 @@ public class OptimizedExplosion
|
||||
entity.getX() == eAccess.getEntity().getX() &&
|
||||
entity.getY() == eAccess.getEntity().getY() &&
|
||||
entity.getZ() == eAccess.getEntity().getZ()) {
|
||||
if (eLogger != null) {
|
||||
eLogger.onEntityImpacted(entity, new Vec3d(0,-0.9923437498509884d, 0));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -158,6 +164,10 @@ public class OptimizedExplosion
|
||||
d11 = ProtectionEnchantment.transformExplosionKnockback((LivingEntity) entity, d10);
|
||||
}
|
||||
|
||||
if (eLogger != null) {
|
||||
eLogger.onEntityImpacted(entity, new Vec3d(d5 * d11, d7 * d11, d9 * d11));
|
||||
}
|
||||
|
||||
entity.setVelocity(entity.getVelocity().add(d5 * d11, d7 * d11, d9 * d11));
|
||||
|
||||
if (entity instanceof PlayerEntity) {
|
||||
|
||||
@@ -5,11 +5,12 @@ import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import carpet.CarpetServer;
|
||||
import carpet.network.ServerNetworkHandler;
|
||||
import carpet.utils.Messenger;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.command.CommandManager;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.BaseText;
|
||||
|
||||
public class TickSpeed
|
||||
@@ -20,11 +21,12 @@ public class TickSpeed
|
||||
public static long time_bias = 0;
|
||||
public static long time_warp_start_time = 0;
|
||||
public static long time_warp_scheduled_ticks = 0;
|
||||
public static PlayerEntity time_advancerer = null;
|
||||
public static ServerPlayerEntity time_advancerer = null;
|
||||
public static String tick_warp_callback = null;
|
||||
public static ServerCommandSource tick_warp_sender = null;
|
||||
public static int player_active_timeout = 0;
|
||||
public static boolean process_entities = true;
|
||||
public static boolean deepFreeze = false;
|
||||
public static boolean is_paused = false;
|
||||
public static boolean is_superHot = false;
|
||||
|
||||
@@ -43,18 +45,37 @@ public class TickSpeed
|
||||
}
|
||||
}
|
||||
|
||||
public static void reset()
|
||||
{
|
||||
tickrate = 20.0f;
|
||||
mspt = 50.0f;
|
||||
time_bias = 0;
|
||||
time_warp_start_time = 0;
|
||||
time_warp_scheduled_ticks = 0;
|
||||
time_advancerer = null;
|
||||
tick_warp_callback = null;
|
||||
tick_warp_sender = null;
|
||||
player_active_timeout = 0;
|
||||
process_entities = true;
|
||||
deepFreeze = false;
|
||||
is_paused = false;
|
||||
is_superHot = false;
|
||||
notifyTickrateListeners("carpet");
|
||||
}
|
||||
|
||||
public static void add_ticks_to_run_in_pause(int ticks)
|
||||
{
|
||||
player_active_timeout = PLAYER_GRACE+ticks;
|
||||
}
|
||||
|
||||
public static BaseText tickrate_advance(PlayerEntity player, int advance, String callback, ServerCommandSource source)
|
||||
public static BaseText tickrate_advance(ServerPlayerEntity player, int advance, String callback, ServerCommandSource source)
|
||||
{
|
||||
if (0 == advance)
|
||||
{
|
||||
tick_warp_callback = null;
|
||||
tick_warp_sender = null;
|
||||
if (source != tick_warp_sender) tick_warp_sender = null;
|
||||
finish_time_warp();
|
||||
tick_warp_sender = null;
|
||||
return Messenger.c("gi Warp interrupted");
|
||||
}
|
||||
if (time_bias > 0)
|
||||
@@ -157,8 +178,9 @@ public class TickSpeed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void tickrate(float rate)
|
||||
//unused - mod compat reasons
|
||||
public static void tickrate(float rate) {tickrate(rate, true);}
|
||||
public static void tickrate(float rate, boolean update)
|
||||
{
|
||||
tickrate = rate;
|
||||
long mspt = (long)(1000.0 / tickrate);
|
||||
@@ -170,7 +192,7 @@ public class TickSpeed
|
||||
|
||||
TickSpeed.mspt = (float)mspt;
|
||||
|
||||
notifyTickrateListeners("carpet");
|
||||
if (update) notifyTickrateListeners("carpet");
|
||||
}
|
||||
|
||||
private static void tickrateChanged(String modId, float rate)
|
||||
@@ -202,6 +224,7 @@ public class TickSpeed
|
||||
}
|
||||
}
|
||||
}
|
||||
ServerNetworkHandler.updateTickSpeedToConnectedPlayers();
|
||||
}
|
||||
|
||||
public static BiConsumer<String, Float> addTickrateListener(String modId, BiConsumer<String, Float> tickrateListener)
|
||||
|
||||
@@ -30,6 +30,7 @@ public class LoggerRegistry
|
||||
public static boolean __packets;
|
||||
public static boolean __weather;
|
||||
public static boolean __pathfinding;
|
||||
public static boolean __explosions;
|
||||
|
||||
public static void initLoggers()
|
||||
{
|
||||
@@ -52,6 +53,7 @@ public class LoggerRegistry
|
||||
registerLogger("packets", HUDLogger.stardardHUDLogger("packets", null, null));
|
||||
registerLogger("counter",HUDLogger.stardardHUDLogger("counter","white", Arrays.stream(DyeColor.values()).map(Object::toString).toArray(String[]::new)));
|
||||
registerLogger("mobcaps", HUDLogger.stardardHUDLogger("mobcaps", "dynamic",new String[]{"dynamic", "overworld", "nether","end"}));
|
||||
registerLogger("explosions", HUDLogger.stardardLogger("explosions", "brief",new String[]{"brief", "full"}));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
package carpet.logging.logHelpers;
|
||||
|
||||
import carpet.logging.LoggerRegistry;
|
||||
import carpet.utils.Messenger;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.text.BaseText;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.world.explosion.Explosion;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static carpet.utils.Messenger.c;
|
||||
|
||||
public class ExplosionLogHelper
|
||||
{
|
||||
private final boolean createFire;
|
||||
private final Explosion.DestructionType blockDestructionType;
|
||||
public final Vec3d pos;
|
||||
public final Entity entity;
|
||||
private final float power;
|
||||
private boolean affectBlocks = false;
|
||||
private Object2IntMap<EntityChangedStatusWithCount> impactedEntities = new Object2IntOpenHashMap<>();
|
||||
|
||||
private static long lastGametime = 0;
|
||||
private static int explosionCountInCurretGT = 0;
|
||||
|
||||
public ExplosionLogHelper(Entity entity, double x, double y, double z, float power, boolean createFire, Explosion.DestructionType blockDestructionType) {
|
||||
this.entity = entity;
|
||||
this.power = power;
|
||||
this.pos = new Vec3d(x,y,z);
|
||||
this.createFire = createFire;
|
||||
this.blockDestructionType = blockDestructionType;
|
||||
}
|
||||
|
||||
public void setAffectBlocks(boolean b)
|
||||
{
|
||||
affectBlocks = b;
|
||||
}
|
||||
|
||||
public void onExplosionDone(long gametime)
|
||||
{
|
||||
List<BaseText> messages = new ArrayList<>();
|
||||
if (!(lastGametime == gametime)){
|
||||
explosionCountInCurretGT = 0;
|
||||
lastGametime = gametime;
|
||||
messages.add(c("wb tick : ", "d " + gametime));
|
||||
}
|
||||
explosionCountInCurretGT++;
|
||||
LoggerRegistry.getLogger("explosions").log( (option) -> {
|
||||
if ("brief".equals(option))
|
||||
{
|
||||
messages.add( c("d #" + explosionCountInCurretGT,"gb ->",
|
||||
Messenger.dblt("l", pos.x, pos.y, pos.z), (affectBlocks)?"m (affects blocks)":"m (doesn't affect blocks)" ));
|
||||
}
|
||||
if ("full".equals(option))
|
||||
{
|
||||
messages.add( c("d #" + explosionCountInCurretGT,"gb ->", Messenger.dblt("l", pos.x, pos.y, pos.z) ));
|
||||
messages.add(c("w affects blocks: ", "m " + this.affectBlocks));
|
||||
messages.add(c("w creates fire: ", "m " + this.createFire));
|
||||
messages.add(c("w power: ", "c " + this.power));
|
||||
messages.add(c( "w destruction: ", "c " + this.blockDestructionType.name()));
|
||||
if (impactedEntities.isEmpty())
|
||||
{
|
||||
messages.add(c("w affected entities: ", "m None"));
|
||||
}
|
||||
else
|
||||
{
|
||||
messages.add(c("w affected entities:"));
|
||||
impactedEntities.forEach((k, v) ->
|
||||
{
|
||||
messages.add(c((k.pos.equals(pos))?"r - TNT":"w - ",
|
||||
Messenger.dblt((k.pos.equals(pos))?"r":"y", k.pos.x, k.pos.y, k.pos.z), "w dV",
|
||||
Messenger.dblt("d", k.accel.x, k.accel.y, k.accel.z),
|
||||
"w "+Registry.ENTITY_TYPE.getId(k.type).getPath(), (v>1)?"l ("+v+")":""
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
return messages.toArray(new BaseText[0]);
|
||||
});
|
||||
}
|
||||
|
||||
public void onEntityImpacted(Entity entity, Vec3d accel)
|
||||
{
|
||||
EntityChangedStatusWithCount ent = new EntityChangedStatusWithCount(entity, accel);
|
||||
impactedEntities.put(ent, impactedEntities.getOrDefault(ent, 0)+1);
|
||||
}
|
||||
|
||||
|
||||
public static class EntityChangedStatusWithCount
|
||||
{
|
||||
public final Vec3d pos;
|
||||
public final EntityType type;
|
||||
public final Vec3d accel;
|
||||
|
||||
public EntityChangedStatusWithCount(Entity e, Vec3d accel)
|
||||
{
|
||||
this.pos = e.getPos();
|
||||
this.type = e.getType();
|
||||
this.accel = accel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj instanceof EntityChangedStatusWithCount)
|
||||
{
|
||||
EntityChangedStatusWithCount other = (EntityChangedStatusWithCount) obj;
|
||||
return other.pos.equals(pos) && other.accel.equals(accel) && other.type.equals(type);
|
||||
}
|
||||
return super.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return pos.hashCode()+ type.hashCode()+accel.hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,8 @@ public class TNTLogHelper
|
||||
{
|
||||
public boolean initialized;
|
||||
private double primedX, primedY, primedZ;
|
||||
private static long lastGametime = 0;
|
||||
private static int tntCount = 0;
|
||||
private Vec3d primedAngle;
|
||||
/**
|
||||
* Runs when the TNT is primed. Expects the position and motion angle of the TNT.
|
||||
@@ -24,8 +26,13 @@ public class TNTLogHelper
|
||||
/**
|
||||
* Runs when the TNT explodes. Expects the position of the TNT.
|
||||
*/
|
||||
public void onExploded(double x, double y, double z)
|
||||
public void onExploded(double x, double y, double z, long gametime)
|
||||
{
|
||||
if (!(lastGametime == gametime)){
|
||||
tntCount = 0;
|
||||
lastGametime = gametime;
|
||||
}
|
||||
tntCount++;
|
||||
LoggerRegistry.getLogger("tnt").log( (option) -> {
|
||||
switch (option)
|
||||
{
|
||||
@@ -36,6 +43,9 @@ public class TNTLogHelper
|
||||
"r E ",Messenger.dblt("r",x, y, z))};
|
||||
case "full":
|
||||
return new BaseText[]{Messenger.c(
|
||||
"r #" + String.valueOf(tntCount),
|
||||
"m @" + String.valueOf(gametime),
|
||||
"g : ",
|
||||
"l P ",Messenger.dblf("l",primedX,primedY,primedZ),
|
||||
"w ",Messenger.dblf("l", primedAngle.x, primedAngle.y, primedAngle.z),
|
||||
"r E ",Messenger.dblf("r",x, y, z))};
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.CarpetSettings;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.EntityContext;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.ItemPlacementContext;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.shape.VoxelShape;
|
||||
import net.minecraft.world.World;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
@Mixin(BlockItem.class)
|
||||
public class BlockItem_creativeNoClipMixin
|
||||
{
|
||||
@Redirect(method = "canPlace", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/World;canPlace(Lnet/minecraft/block/BlockState;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/entity/EntityContext;)Z"
|
||||
))
|
||||
private boolean canSpectatingPlace(World world, BlockState state, BlockPos pos, EntityContext context,
|
||||
ItemPlacementContext contextOuter, BlockState stateOuter)
|
||||
{
|
||||
PlayerEntity player = contextOuter.getPlayer();
|
||||
if (CarpetSettings.creativeNoClip && player != null && player.isCreative() && player.abilities.flying)
|
||||
{
|
||||
// copy from canPlace
|
||||
VoxelShape voxelShape = state.getCollisionShape(world, pos, context);
|
||||
return voxelShape.isEmpty() || world.intersectsEntities(player, voxelShape.offset(pos.getX(), pos.getY(), pos.getZ()));
|
||||
|
||||
}
|
||||
return world.canPlace(state, pos, context);
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
@Mixin(Chunk.class)
|
||||
public abstract class ChunkMixin
|
||||
{
|
||||
// failed to mixin into interface. need to mixin in two places that uses it
|
||||
@Inject(method = "markBlockForPostProcessing(Lnet/minecraft/util/math/BlockPos;)V",
|
||||
at =@At("HEAD"), cancellable = true)
|
||||
private void squashWarnings(BlockPos blockPos_1, CallbackInfo ci)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.CarpetSettings;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.ChunkRegion;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ChunkRegion.class)
|
||||
public class ChunkRegion_scarpetPlopMixin
|
||||
{
|
||||
@Inject(method = "markBlockForPostProcessing", at = @At("HEAD"))
|
||||
private void markOrNot(BlockPos blockPos, CallbackInfo ci)
|
||||
{
|
||||
if (CarpetSettings.skipGenerationChecks) ci.cancel();
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,23 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.fakes.ChunkTicketManagerInterface;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import net.minecraft.server.world.ChunkTicket;
|
||||
import net.minecraft.server.world.ChunkTicketManager;
|
||||
import net.minecraft.util.SortedArraySet;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
@Mixin(ChunkTicketManager.class)
|
||||
public interface ChunkTicketManager_scarpetMixin
|
||||
public abstract class ChunkTicketManager_scarpetMixin implements ChunkTicketManagerInterface
|
||||
{
|
||||
@Accessor
|
||||
Long2ObjectOpenHashMap<SortedArraySet<ChunkTicket<?>>> getTicketsByPosition();
|
||||
@Shadow @Final private Long2ObjectOpenHashMap<SortedArraySet<ChunkTicket<?>>> ticketsByPosition;
|
||||
|
||||
@Override
|
||||
public Long2ObjectOpenHashMap<SortedArraySet<ChunkTicket<?>>> getTicketsByPosition()
|
||||
{
|
||||
return ticketsByPosition;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.fakes.ChunkTicketManagerInterface;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import net.minecraft.server.world.ChunkTicket;
|
||||
import net.minecraft.server.world.ChunkTicketManager;
|
||||
import net.minecraft.server.world.ChunkTicketType;
|
||||
import net.minecraft.util.SortedArraySet;
|
||||
import net.minecraft.util.Unit;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
@Mixin(ChunkTicketManager.class)
|
||||
public abstract class ChunkTicketManager_spawnChunksMixin implements ChunkTicketManagerInterface
|
||||
{
|
||||
|
||||
@Shadow protected abstract SortedArraySet<ChunkTicket<?>> getTicketSet(long position);
|
||||
|
||||
@Shadow @Final private Long2ObjectOpenHashMap<SortedArraySet<ChunkTicket<?>>> ticketsByPosition;
|
||||
|
||||
@Shadow public abstract <T> void removeTicket(ChunkTicketType<T> type, ChunkPos pos, int radius, T argument);
|
||||
|
||||
@Shadow protected abstract void removeTicket(long pos, ChunkTicket<?> ticket);
|
||||
|
||||
@Shadow public abstract <T> void addTicket(ChunkTicketType<T> type, ChunkPos pos, int radius, T argument);
|
||||
|
||||
@Override
|
||||
public void changeSpawnChunks(ChunkPos chunkPos, int distance)
|
||||
{
|
||||
long pos = chunkPos.toLong();
|
||||
SortedArraySet<ChunkTicket<?>> set = ticketsByPosition.get(pos);
|
||||
ChunkTicket existingTicket = null;
|
||||
if (set != null)
|
||||
{
|
||||
Iterator<ChunkTicket<?>> iter = set.iterator();
|
||||
while(iter.hasNext())
|
||||
{
|
||||
ChunkTicket ticket = iter.next();
|
||||
if (ticket.getType() == ChunkTicketType.START)
|
||||
{
|
||||
existingTicket = ticket;
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
set.add(existingTicket);
|
||||
}
|
||||
// the reason we are removing the ticket this way is that there are sideeffects of removal
|
||||
if (existingTicket != null)
|
||||
{
|
||||
removeTicket(pos, existingTicket);
|
||||
}
|
||||
// set optionally new spawn ticket
|
||||
if (distance > 0)
|
||||
addTicket(ChunkTicketType.START, chunkPos, distance, Unit.INSTANCE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.helpers.TickSpeed;
|
||||
import net.minecraft.server.world.ChunkTicketManager;
|
||||
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.CallbackInfo;
|
||||
|
||||
@Mixin(ChunkTicketManager.class)
|
||||
public class ChunkTicketManager_tickMixin
|
||||
{
|
||||
@Shadow private long age;
|
||||
|
||||
@Inject(method = "purge", at = @At("HEAD"), cancellable = true)
|
||||
private void pauseTicketSystem(CallbackInfo ci)
|
||||
{
|
||||
// pausing expiry of tickets
|
||||
// that will prevent also chunks from unloading, so require a deep frozen state
|
||||
if (!TickSpeed.process_entities && TickSpeed.deepFreeze) age--;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.network.CarpetClient;
|
||||
import carpet.network.ClientNetworkHandler;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket;
|
||||
import net.minecraft.text.Text;
|
||||
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.CallbackInfo;
|
||||
|
||||
@Mixin(ClientPlayNetworkHandler.class)
|
||||
public abstract class ClientPlayNetworkHandlerMixin
|
||||
{
|
||||
@Shadow private MinecraftClient client;
|
||||
|
||||
@Inject(method = "onCustomPayload", at = @At("HEAD"), cancellable = true)
|
||||
private void onOnCustomPayload(CustomPayloadS2CPacket packet, CallbackInfo ci)
|
||||
{
|
||||
if (CarpetClient.CARPET_CHANNEL.equals(packet.getChannel()))
|
||||
{
|
||||
ClientNetworkHandler.handleData(packet.getData(), client.player);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "onGameJoin", at = @At("RETURN"))
|
||||
private void onGameJoined(GameJoinS2CPacket packet, CallbackInfo info)
|
||||
{
|
||||
CarpetClient.gameJoined(client.player);
|
||||
}
|
||||
|
||||
@Inject(method = "onDisconnected", at = @At("HEAD"))
|
||||
private void onCMDisconnected(Text reason, CallbackInfo ci)
|
||||
{
|
||||
CarpetClient.disconnect();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.CarpetServer;
|
||||
import carpet.network.CarpetClient;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@@ -13,7 +14,10 @@ public class ClientPlayerEntity_clientCommandMixin
|
||||
@Inject(method = "sendChatMessage", at = @At("HEAD"))
|
||||
private void inspectMessage(String string, CallbackInfo ci)
|
||||
{
|
||||
if (CarpetServer.minecraft_server == null)
|
||||
CarpetServer.settingsManager.inspectClientsideCommand(string);
|
||||
if (CarpetServer.minecraft_server == null && !CarpetClient.isCarpet())
|
||||
{
|
||||
ClientPlayerEntity playerSource = (ClientPlayerEntity)(Object) this;
|
||||
CarpetServer.settingsManager.inspectClientsideCommand(playerSource.getCommandSource(), string);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.fakes.CustomPayloadC2SPacketInterface;
|
||||
import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.PacketByteBuf;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
@Mixin(CustomPayloadC2SPacket.class)
|
||||
public class CustomPayloadC2SPacketMixin implements CustomPayloadC2SPacketInterface
|
||||
{
|
||||
@Shadow
|
||||
private Identifier channel;
|
||||
@Shadow
|
||||
private PacketByteBuf data;
|
||||
|
||||
@Override
|
||||
public Identifier getPacketChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketByteBuf getPacketData() {
|
||||
return new PacketByteBuf(this.data.copy());
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import carpet.script.EntityEventsGroup;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
import net.minecraft.entity.damage.DamageTracker;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
@@ -12,8 +13,11 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import static carpet.script.CarpetEventServer.Event.PLAYER_DEALS_DAMAGE;
|
||||
import static carpet.script.CarpetEventServer.Event.PLAYER_TAKES_DAMAGE;
|
||||
|
||||
@Mixin(DamageTracker.class)
|
||||
public class DamageTracker_scarpetEventMixin
|
||||
public abstract class DamageTracker_scarpetEventMixin
|
||||
{
|
||||
@Shadow @Final private LivingEntity entity;
|
||||
|
||||
@@ -21,5 +25,13 @@ public class DamageTracker_scarpetEventMixin
|
||||
private void onDamageTaken(DamageSource damageSource_1, float float_1, float float_2, CallbackInfo ci)
|
||||
{
|
||||
((EntityInterface)entity).getEventContainer().onEvent(EntityEventsGroup.EntityEventType.ON_DAMAGE, entity, float_2, damageSource_1);
|
||||
if (entity instanceof ServerPlayerEntity && PLAYER_TAKES_DAMAGE.isNeeded())
|
||||
{
|
||||
PLAYER_TAKES_DAMAGE.onDamage(entity, float_2, damageSource_1);
|
||||
}
|
||||
if (damageSource_1.getAttacker() instanceof ServerPlayerEntity && PLAYER_DEALS_DAMAGE.isNeeded())
|
||||
{
|
||||
PLAYER_DEALS_DAMAGE.onDamage(entity, float_2, damageSource_1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.network.CarpetClient;
|
||||
import net.minecraft.client.render.debug.DebugRenderer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(DebugRenderer.class)
|
||||
public class DebugRenderer_scarpetRenderMixin
|
||||
{
|
||||
@Inject(method = "reset", at = @At("HEAD"))
|
||||
private void resetScarpetRenderes(CallbackInfo ci)
|
||||
{
|
||||
if (CarpetClient.shapes != null)
|
||||
CarpetClient.shapes.reset();
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ public abstract class Entity_scarpetEventsMixin implements EntityInterface
|
||||
{
|
||||
@Shadow public boolean removed;
|
||||
|
||||
@Shadow protected int netherPortalTime;
|
||||
private boolean permanentVehicle;
|
||||
|
||||
private final EntityEventsGroup events = new EntityEventsGroup();
|
||||
@@ -36,6 +37,18 @@ public abstract class Entity_scarpetEventsMixin implements EntityInterface
|
||||
permanentVehicle = permanent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPortalTimer()
|
||||
{
|
||||
return netherPortalTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPortalTimer(int amount)
|
||||
{
|
||||
netherPortalTime = amount;
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("HEAD"))
|
||||
private void onTickCall(CallbackInfo ci)
|
||||
{
|
||||
|
||||
@@ -2,9 +2,13 @@ package carpet.mixins;
|
||||
|
||||
import carpet.helpers.OptimizedExplosion;
|
||||
import carpet.CarpetSettings;
|
||||
import carpet.logging.LoggerRegistry;
|
||||
import carpet.logging.logHelpers.ExplosionLogHelper;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.explosion.Explosion;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
@@ -24,13 +28,17 @@ public abstract class ExplosionMixin
|
||||
@Final
|
||||
private List<BlockPos> affectedBlocks;
|
||||
|
||||
@Shadow @Final private World world;
|
||||
|
||||
private ExplosionLogHelper eLogger;
|
||||
|
||||
@Inject(method = "collectBlocksAndDamageEntities", at = @At("HEAD"),
|
||||
cancellable = true)
|
||||
private void onExplosionA(CallbackInfo ci)
|
||||
{
|
||||
if (CarpetSettings.optimizedTNT)
|
||||
{
|
||||
OptimizedExplosion.doExplosionA((Explosion) (Object) this);
|
||||
OptimizedExplosion.doExplosionA((Explosion) (Object) this, eLogger);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
@@ -39,6 +47,11 @@ public abstract class ExplosionMixin
|
||||
cancellable = true)
|
||||
private void onExplosionB(boolean spawnParticles, CallbackInfo ci)
|
||||
{
|
||||
if (eLogger != null)
|
||||
{
|
||||
eLogger.setAffectBlocks( ! affectedBlocks.isEmpty());
|
||||
eLogger.onExplosionDone(this.world.getTime());
|
||||
}
|
||||
if (CarpetSettings.explosionNoBlockDamage)
|
||||
{
|
||||
affectedBlocks.clear();
|
||||
@@ -58,4 +71,24 @@ public abstract class ExplosionMixin
|
||||
if (CarpetSettings.explosionNoBlockDamage) return Blocks.BEDROCK.getDefaultState();
|
||||
return world.getBlockState(pos);
|
||||
}
|
||||
|
||||
@Inject(method = "<init>(Lnet/minecraft/world/World;Lnet/minecraft/entity/Entity;DDDFZLnet/minecraft/world/explosion/Explosion$DestructionType;)V",
|
||||
at = @At(value = "RETURN"))
|
||||
private void onExplosionCreated(World world, Entity entity, double x, double y, double z, float power, boolean createFire, Explosion.DestructionType blockDestructionType, CallbackInfo ci)
|
||||
{
|
||||
if (LoggerRegistry.__explosions && ! world.isClient)
|
||||
{
|
||||
eLogger = new ExplosionLogHelper(entity, x, y, z, power, createFire, blockDestructionType);
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(method = "collectBlocksAndDamageEntities",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;setVelocity(Lnet/minecraft/util/math/Vec3d;)V"))
|
||||
private void setVelocityAndUpdateLogging(Entity entity, Vec3d velocity)
|
||||
{
|
||||
if (eLogger != null) {
|
||||
eLogger.onEntityImpacted(entity, velocity.subtract(entity.getVelocity()));
|
||||
}
|
||||
entity.setVelocity(velocity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.fakes.HungerManagerInterface;
|
||||
import net.minecraft.entity.player.HungerManager;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
@Mixin(HungerManager.class)
|
||||
public class HungerManagerMixin_scarpetEventsMixin implements HungerManagerInterface {
|
||||
@Shadow private float exhaustion;
|
||||
public float getExhaustionCM(){
|
||||
return exhaustion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExhaustionCM(float exhaust)
|
||||
{
|
||||
exhaustion = exhaust;
|
||||
}
|
||||
}
|
||||
@@ -30,12 +30,12 @@ public abstract class ItemEntityMixin extends Entity implements ItemEntityInterf
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAge() {
|
||||
public int getAgeCM() {
|
||||
return this.age;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPickupDelay() {
|
||||
public int getPickupDelayCM() {
|
||||
return this.pickupDelay;
|
||||
}
|
||||
|
||||
@@ -91,8 +91,8 @@ public abstract class ItemEntityMixin extends Entity implements ItemEntityInterf
|
||||
selfStack.increment(amount);
|
||||
self.setStack(selfStack);
|
||||
|
||||
this.pickupDelay = Math.max(((ItemEntityInterface)other).getPickupDelay(), this.pickupDelay);
|
||||
this.age = Math.min(((ItemEntityInterface)other).getAge(), this.age);
|
||||
this.pickupDelay = Math.max(((ItemEntityInterface)other).getPickupDelayCM(), this.pickupDelay);
|
||||
this.age = Math.min(((ItemEntityInterface)other).getAgeCM(), this.age);
|
||||
|
||||
otherStack.decrement(amount);
|
||||
if (otherStack.isEmpty())
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.CarpetSettings;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.world.World;
|
||||
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.Constant;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyConstant;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(LivingEntity.class)
|
||||
public abstract class LivingEntity_creativeFlyMixin extends Entity
|
||||
{
|
||||
@Shadow public float flyingSpeed;
|
||||
|
||||
public LivingEntity_creativeFlyMixin(EntityType<?> type, World world)
|
||||
{
|
||||
super(type, world);
|
||||
}
|
||||
|
||||
@ModifyConstant(method = "travel", constant = @Constant(floatValue = 0.91F), expect = 2)
|
||||
private float drag(float original)
|
||||
{
|
||||
if (CarpetSettings.creativeFlyDrag != 0.09 && (Object)this instanceof PlayerEntity)
|
||||
{
|
||||
PlayerEntity self = (PlayerEntity)(Object)(this);
|
||||
if (self.abilities.flying && ! onGround )
|
||||
return (float)(1.0-CarpetSettings.creativeFlyDrag);
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
||||
|
||||
@Inject(method = "getMovementSpeed(F)F", at = @At("HEAD"), cancellable = true)
|
||||
private void flyingAltSpeed(float slipperiness, CallbackInfoReturnable<Float> cir)
|
||||
{
|
||||
if (CarpetSettings.creativeFlySpeed != 1.0D && (Object)this instanceof PlayerEntity)
|
||||
{
|
||||
PlayerEntity self = (PlayerEntity)(Object)(this);
|
||||
if (self.abilities.flying && !onGround)
|
||||
cir.setReturnValue(flyingSpeed* (float)CarpetSettings.creativeFlySpeed);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,33 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.CarpetSettings;
|
||||
import carpet.fakes.EntityInterface;
|
||||
import carpet.fakes.LivingEntityInterface;
|
||||
import carpet.script.EntityEventsGroup;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.world.World;
|
||||
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.Constant;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyConstant;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(LivingEntity.class)
|
||||
public abstract class LivingEntity_scarpetEventsMixin extends Entity
|
||||
public abstract class LivingEntity_scarpetEventsMixin extends Entity implements LivingEntityInterface
|
||||
{
|
||||
|
||||
@Shadow protected abstract void jump();
|
||||
|
||||
@Shadow protected boolean jumping;
|
||||
|
||||
public LivingEntity_scarpetEventsMixin(EntityType<?> type, World world)
|
||||
{
|
||||
super(type, world);
|
||||
@@ -26,4 +38,16 @@ public abstract class LivingEntity_scarpetEventsMixin extends Entity
|
||||
{
|
||||
((EntityInterface)this).getEventContainer().onEvent(EntityEventsGroup.EntityEventType.ON_DEATH, this, damageSource_1.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doJumpCM()
|
||||
{
|
||||
jump();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJumpingCM()
|
||||
{
|
||||
return jumping;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.CarpetServer;
|
||||
import carpet.network.CarpetClient;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
@@ -18,4 +20,10 @@ public class MinecraftClientMixin
|
||||
//CM start game hook
|
||||
CarpetServer.onGameStarted();
|
||||
}
|
||||
|
||||
@Inject(method = "disconnect(Lnet/minecraft/client/gui/screen/Screen;)V", at = @At("HEAD"))
|
||||
private void onCloseGame(Screen screen, CallbackInfo ci)
|
||||
{
|
||||
CarpetClient.disconnect();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.CarpetServer;
|
||||
import carpet.CarpetSettings;
|
||||
import com.google.gson.JsonElement;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.WorldGenerationProgressListener;
|
||||
import net.minecraft.world.level.LevelGeneratorType;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@@ -41,4 +43,11 @@ public abstract class MinecraftServer_coreMixin
|
||||
{
|
||||
CarpetServer.onServerClosed((MinecraftServer) (Object) this);
|
||||
}
|
||||
|
||||
@Inject(method = "prepareStartRegion", at = @At("RETURN"))
|
||||
private void afterSpawnCreated(WorldGenerationProgressListener worldGenerationProgressListener, CallbackInfo ci)
|
||||
{
|
||||
if (CarpetSettings.spawnChunksSize != 11)
|
||||
CarpetSettings.ChangeSpawnChunksValidator.changeSpawnSize(CarpetSettings.spawnChunksSize);
|
||||
}
|
||||
}
|
||||
@@ -120,7 +120,7 @@ public abstract class MinecraftServer_tickspeedMixin extends ReentrantThreadExec
|
||||
|
||||
this.profiler.startTick();
|
||||
this.profiler.push("tick");
|
||||
this.tick(TickSpeed.time_warp_start_time != 0 ? ()->true : this::shouldKeepTicking);
|
||||
this.tick(TickSpeed.time_warp_start_time != 0 ? ()->!hasRunningTasks() : this::shouldKeepTicking);
|
||||
this.profiler.swap("nextTickWait");
|
||||
this.field_19249 = true;
|
||||
this.field_19248 = Math.max(Util.getMeasuringTimeMs() + /*50L*/ msThisTick, this.timeReference);
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.CarpetSettings;
|
||||
import net.minecraft.block.entity.PistonBlockEntity;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(PistonBlockEntity.class)
|
||||
public class PistonBlockEntity_creativeNoClipMixin
|
||||
{
|
||||
@Inject(method = "method_23672", at = @At("HEAD"), cancellable = true)
|
||||
private static void dontPushSpectators(Direction direction, Entity entity, double d, Direction direction2, CallbackInfo ci)
|
||||
{
|
||||
if (CarpetSettings.creativeNoClip && entity instanceof PlayerEntity && (((PlayerEntity) entity).isCreative()) && ((PlayerEntity) entity).abilities.flying) ci.cancel();
|
||||
}
|
||||
|
||||
@Redirect(method = "pushEntities", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;setVelocity(DDD)V"))
|
||||
private void ignoreAccel(Entity entity, double x, double y, double z)
|
||||
{
|
||||
if (CarpetSettings.creativeNoClip && entity instanceof PlayerEntity && (((PlayerEntity) entity).isCreative()) && ((PlayerEntity) entity).abilities.flying) return;
|
||||
entity.setVelocity(x,y,z);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import carpet.fakes.PistonBlockEntityInterface;
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.block.piston.PistonBehavior;
|
||||
import net.minecraft.block.piston.PistonHandler;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
@@ -62,6 +63,17 @@ public abstract class PistonBlock_movableTEMixin extends FacingBlock
|
||||
return !(CarpetSettings.movableBlockEntities && isPushableBlockEntity(block));
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(method = "isMovable", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/block/BlockState;getPistonBehavior()Lnet/minecraft/block/piston/PistonBehavior;"
|
||||
))
|
||||
private static PistonBehavior moveGrindstones(BlockState blockState)
|
||||
{
|
||||
if (CarpetSettings.movableBlockEntities && blockState.getBlock() == Blocks.GRINDSTONE) return PistonBehavior.NORMAL;
|
||||
return blockState.getPistonBehavior();
|
||||
}
|
||||
|
||||
@Inject(method = "move", at = @At(value = "INVOKE", shift = At.Shift.BEFORE,
|
||||
target = "Ljava/util/List;size()I", ordinal = 4),locals = LocalCapture.CAPTURE_FAILHARD)
|
||||
private void onMove(World world_1, BlockPos blockPos_1, Direction direction_1, boolean boolean_1,
|
||||
|
||||
@@ -23,7 +23,7 @@ public abstract class PlayerEntity_antiCheatDisabled
|
||||
@Inject(method = "method_23668", at = @At("HEAD"), cancellable = true)
|
||||
private void allowDeploys(CallbackInfoReturnable<Boolean> cir)
|
||||
{
|
||||
if (CarpetSettings.antiCheatDisabled && CarpetServer.minecraft_server.isDedicated())
|
||||
if (CarpetSettings.antiCheatDisabled && CarpetServer.minecraft_server != null && CarpetServer.minecraft_server.isDedicated())
|
||||
{
|
||||
ItemStack itemStack_1 = getEquippedStack(EquipmentSlot.CHEST);
|
||||
if (itemStack_1.getItem() == Items.ELYTRA && ElytraItem.isUsable(itemStack_1)) {
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.CarpetSettings;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.MovementType;
|
||||
import net.minecraft.entity.player.PlayerAbilities;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
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.Redirect;
|
||||
|
||||
@Mixin(PlayerEntity.class)
|
||||
public abstract class PlayerEntity_creativeNoClipMixin extends LivingEntity
|
||||
{
|
||||
@Shadow public abstract boolean isCreative();
|
||||
|
||||
@Shadow @Final public PlayerAbilities abilities;
|
||||
|
||||
protected PlayerEntity_creativeNoClipMixin(EntityType<? extends LivingEntity> type, World world)
|
||||
{
|
||||
super(type, world);
|
||||
}
|
||||
|
||||
@Redirect(method = "tick", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/entity/player/PlayerEntity;isSpectator()Z")
|
||||
)
|
||||
private boolean canClipTroughWorld(PlayerEntity playerEntity)
|
||||
{
|
||||
return playerEntity.isSpectator() || (CarpetSettings.creativeNoClip && playerEntity.isCreative() && playerEntity.abilities.flying);
|
||||
|
||||
}
|
||||
|
||||
@Redirect(method = "tickMovement", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/entity/player/PlayerEntity;isSpectator()Z")
|
||||
)
|
||||
private boolean collidesWithEntities(PlayerEntity playerEntity)
|
||||
{
|
||||
return playerEntity.isSpectator() || (CarpetSettings.creativeNoClip && playerEntity.isCreative() && playerEntity.abilities.flying);
|
||||
}
|
||||
|
||||
@Redirect(method = "updateSize", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/entity/player/PlayerEntity;isSpectator()Z")
|
||||
)
|
||||
private boolean spectatorsDontPose(PlayerEntity playerEntity)
|
||||
{
|
||||
return playerEntity.isSpectator() || (CarpetSettings.creativeNoClip && playerEntity.isCreative() && playerEntity.abilities.flying);
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,8 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import static carpet.script.CarpetEventServer.Event.PLAYER_CONNECTS;
|
||||
|
||||
@Mixin(PlayerManager.class)
|
||||
public class PlayerManager_coreMixin
|
||||
{
|
||||
@@ -16,5 +18,6 @@ public class PlayerManager_coreMixin
|
||||
private void onPlayerConnected(ClientConnection connection, ServerPlayerEntity player, CallbackInfo ci)
|
||||
{
|
||||
CarpetServer.onPlayerLoggedIn(player);
|
||||
PLAYER_CONNECTS.onPlayerEvent(player);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import net.minecraft.server.PlayerManager;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import static carpet.script.CarpetEventServer.Event.PLAYER_RESPAWNS;
|
||||
|
||||
@Mixin(PlayerManager.class)
|
||||
public class PlayerManager_scarpetEventsMixin
|
||||
{
|
||||
@Inject(method = "respawnPlayer", at = @At("HEAD"))
|
||||
private void onRespawn(ServerPlayerEntity player, DimensionType dimension, boolean alive, CallbackInfoReturnable<ServerPlayerEntity> cir)
|
||||
{
|
||||
PLAYER_RESPAWNS.onPlayerEvent(player);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.fakes.ServerChunkManagerInterface;
|
||||
import carpet.utils.SpawnReporter;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import net.minecraft.entity.EntityCategory;
|
||||
import net.minecraft.server.world.ChunkTicketManager;
|
||||
import net.minecraft.server.world.ServerChunkManager;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
@@ -24,12 +26,20 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
@Mixin(ServerChunkManager.class)
|
||||
public abstract class ServerChunkManagerMixin
|
||||
public abstract class ServerChunkManagerMixin implements ServerChunkManagerInterface
|
||||
{
|
||||
@Shadow @Final private ServerWorld world;
|
||||
|
||||
@Shadow @Final private static int CHUNKS_ELIGIBLE_FOR_SPAWNING;
|
||||
|
||||
@Shadow @Final private ChunkTicketManager ticketManager;
|
||||
|
||||
@Override // shared between scarpet and spawnChunks setting
|
||||
public ChunkTicketManager getCMTicketManager()
|
||||
{
|
||||
return ticketManager;
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "tickChunks",
|
||||
locals = LocalCapture.CAPTURE_FAILHARD,
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import net.minecraft.server.world.ChunkTicketManager;
|
||||
import net.minecraft.server.world.ServerChunkManager;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(ServerChunkManager.class)
|
||||
public interface ServerChunkManager_scarpetMixin
|
||||
{
|
||||
@Accessor
|
||||
ChunkTicketManager getTicketManager();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.fakes.CustomPayloadC2SPacketInterface;
|
||||
import carpet.network.CarpetClient;
|
||||
import carpet.network.ServerNetworkHandler;
|
||||
import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket;
|
||||
import net.minecraft.server.network.ServerPlayNetworkHandler;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.util.Identifier;
|
||||
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.CallbackInfo;
|
||||
|
||||
@Mixin(ServerPlayNetworkHandler.class)
|
||||
public class ServerPlayNetworkHandlerMixin
|
||||
{
|
||||
@Shadow public ServerPlayerEntity player;
|
||||
|
||||
@Inject(method = "onCustomPayload", at = @At("HEAD"), cancellable = true)
|
||||
private void onCustomCarpetPayload(CustomPayloadC2SPacket packet, CallbackInfo ci)
|
||||
{
|
||||
Identifier channel = ((CustomPayloadC2SPacketInterface) packet).getPacketChannel();
|
||||
if (CarpetClient.CARPET_CHANNEL.equals(channel))
|
||||
{
|
||||
ServerNetworkHandler.handleData(((CustomPayloadC2SPacketInterface) packet).getPacketData(), player);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,8 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import static carpet.script.CarpetEventServer.Event.PLAYER_DISCONNECTS;
|
||||
|
||||
@Mixin(ServerPlayNetworkHandler.class)
|
||||
public class ServerPlayNetworkHandler_coreMixin {
|
||||
@Shadow
|
||||
@@ -21,5 +23,6 @@ public class ServerPlayNetworkHandler_coreMixin {
|
||||
@Inject(method = "onDisconnected", at = @At("HEAD"))
|
||||
private void onPlayerDisconnect(Text reason, CallbackInfo ci) {
|
||||
CarpetServer.onPlayerLoggedOut(this.player);
|
||||
if (PLAYER_DISCONNECTS.isNeeded()) PLAYER_DISCONNECTS.onPlayerMessage(player, reason.asString());
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,10 @@ public class ServerPlayNetworkHandler_tickMixin
|
||||
}
|
||||
}
|
||||
|
||||
// to skip reposition adjustment check
|
||||
private static long lastMovedTick = 0L;
|
||||
private static double lastMoved = 0.0D;
|
||||
|
||||
@Inject(method = "onPlayerMove", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/server/network/ServerPlayerEntity;isSleeping()Z",
|
||||
@@ -38,10 +42,23 @@ public class ServerPlayNetworkHandler_tickMixin
|
||||
))
|
||||
private void checkMove(PlayerMoveC2SPacket p, CallbackInfo ci)
|
||||
{
|
||||
if (Math.abs(p.getX(player.getX()) - lastTickX) > 0.0001D
|
||||
|| Math.abs(p.getY(player.getY()) - lastTickY) > 0.0001D
|
||||
|| Math.abs(p.getY(player.getZ()) - lastTickZ) > 0.0001D)
|
||||
double movedBy = player.getPos().squaredDistanceTo(lastTickX, lastTickY, lastTickZ);
|
||||
if (movedBy == 0.0D) return;
|
||||
// corrective tick
|
||||
if (movedBy < 0.0009 && lastMoved > 0.0009 && Math.abs(player.getServer().getTicks()-lastMovedTick-20)<2)
|
||||
{
|
||||
//CarpetSettings.LOG.error("Corrective movement packet");
|
||||
return;
|
||||
}
|
||||
if (movedBy > 0.0D)
|
||||
{
|
||||
//CarpetSettings.LOG.error(String.format(
|
||||
// "moved by %.6f at %d",
|
||||
// player.getPos().squaredDistanceTo(lastTickX, lastTickY, lastTickZ),
|
||||
// player.getServer().getTicks()-lastMovedTick
|
||||
//));
|
||||
lastMoved = movedBy;
|
||||
lastMovedTick = player.getServer().getTicks();
|
||||
TickSpeed.reset_player_active_timeout();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,20 +3,26 @@ package carpet.mixins;
|
||||
import carpet.fakes.EntityInterface;
|
||||
import carpet.script.EntityEventsGroup;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.stat.Stat;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
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.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import static carpet.script.CarpetEventServer.Event.PLAYER_CHANGES_DIMENSION;
|
||||
import static carpet.script.CarpetEventServer.Event.PLAYER_DIES;
|
||||
import static carpet.script.CarpetEventServer.Event.PLAYER_FINISHED_USING_ITEM;
|
||||
import static carpet.script.CarpetEventServer.Event.STATISTICS;
|
||||
|
||||
@@ -30,6 +36,8 @@ public abstract class ServerPlayerEntity_scarpetEventMixin extends PlayerEntity
|
||||
|
||||
@Shadow protected abstract void consumeItem();
|
||||
|
||||
@Shadow public boolean notInAnyWorld;
|
||||
|
||||
@Redirect(method = "consumeItem", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/entity/player/PlayerEntity;consumeItem()V"
|
||||
@@ -61,6 +69,10 @@ public abstract class ServerPlayerEntity_scarpetEventMixin extends PlayerEntity
|
||||
private void onDeathEvent(DamageSource source, CallbackInfo ci)
|
||||
{
|
||||
((EntityInterface)this).getEventContainer().onEvent(EntityEventsGroup.EntityEventType.ON_DEATH, this, source.name);
|
||||
if (PLAYER_DIES.isNeeded())
|
||||
{
|
||||
PLAYER_DIES.onPlayerEvent((ServerPlayerEntity) (Object)this);
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(method = "method_14218", at = @At(
|
||||
@@ -72,4 +84,30 @@ public abstract class ServerPlayerEntity_scarpetEventMixin extends PlayerEntity
|
||||
if (!((EntityInterface)serverPlayerEntity.getVehicle()).isPermanentVehicle()) // won't since that method makes sure its not null
|
||||
serverPlayerEntity.setSneaking(sneaking);
|
||||
}
|
||||
|
||||
private Vec3d previousLocation;
|
||||
private DimensionType previousDimension;
|
||||
|
||||
@Inject(method = "changeDimension", at = @At("HEAD"))
|
||||
private void logPreviousCoordinates(DimensionType newDimension, CallbackInfoReturnable<Entity> cir)
|
||||
{
|
||||
previousLocation = getPos();
|
||||
previousDimension = dimension;
|
||||
}
|
||||
|
||||
@Inject(method = "changeDimension", at = @At("RETURN"))
|
||||
private void atChangeDimension(DimensionType newDimension, CallbackInfoReturnable<Entity> cir)
|
||||
{
|
||||
if (PLAYER_CHANGES_DIMENSION.isNeeded())
|
||||
{
|
||||
ServerPlayerEntity player = (ServerPlayerEntity) (Object)this;
|
||||
Vec3d to = null;
|
||||
if (!notInAnyWorld || previousDimension != DimensionType.THE_END || newDimension != DimensionType.OVERWORLD)
|
||||
{
|
||||
to = getPos();
|
||||
}
|
||||
PLAYER_CHANGES_DIMENSION.onDimensionChange(player, previousLocation, to, previousDimension, newDimension);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.CarpetSettings;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.Constant;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyConstant;
|
||||
|
||||
@Mixin(ServerWorld.class)
|
||||
public class ServerWorld_spawnChunksMixin
|
||||
{
|
||||
@ModifyConstant(method = "setSpawnPos", constant = @Constant(intValue = 11), expect = 2)
|
||||
private int pushLimit(int original)
|
||||
{
|
||||
return CarpetSettings.spawnChunksSize;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.CarpetSettings;
|
||||
import net.minecraft.structure.StructurePiece;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
@Mixin(StructurePiece.class)
|
||||
public class StructurePiece_scarpetPlopMixin
|
||||
{
|
||||
@Redirect(method = "addBlock", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/chunk/Chunk;markBlockForPostProcessing(Lnet/minecraft/util/math/BlockPos;)V"
|
||||
))
|
||||
private void markOrNot(Chunk chunk, BlockPos pos)
|
||||
{
|
||||
if (!CarpetSettings.skipGenerationChecks) chunk.markBlockForPostProcessing(pos);
|
||||
}
|
||||
}
|
||||
@@ -72,7 +72,7 @@ public abstract class TntEntityMixin extends Entity implements TntEntityInterfac
|
||||
private void onExplode(CallbackInfo ci)
|
||||
{
|
||||
if (LoggerRegistry.__tnt && logHelper != null)
|
||||
logHelper.onExploded(getX(), getY(), getZ());
|
||||
logHelper.onExploded(getX(), getY(), getZ(), this.world.getTime());
|
||||
|
||||
if (mergedTNT > 1)
|
||||
for (int i = 0; i < mergedTNT - 1; i++)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.CarpetSettings;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.client.render.WorldRenderer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
@Mixin(WorldRenderer.class)
|
||||
public class WorldRenderer_creativeNoClipMixin
|
||||
{
|
||||
@Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isSpectator()Z"))
|
||||
private boolean canSeeWorld(ClientPlayerEntity clientPlayerEntity)
|
||||
{
|
||||
return clientPlayerEntity.isSpectator() || (CarpetSettings.creativeNoClip && clientPlayerEntity.isCreative());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.CarpetSettings;
|
||||
import net.minecraft.client.render.WorldRenderer;
|
||||
import net.minecraft.world.dimension.Dimension;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
@Mixin(value = WorldRenderer.class, priority = 69420)
|
||||
public class WorldRenderer_fogOffMixin
|
||||
{
|
||||
@Redirect(method = "render", require = 0, expect = 0, at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/dimension/Dimension;isFogThick(II)Z"
|
||||
))
|
||||
private boolean isReallyThick(Dimension dimension, int x, int z)
|
||||
{
|
||||
if (CarpetSettings.fogOff) return false;
|
||||
return dimension.isFogThick(x, z);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.network.CarpetClient;
|
||||
import carpet.script.utils.ShapesRenderer;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.BufferBuilderStorage;
|
||||
import net.minecraft.client.render.Camera;
|
||||
import net.minecraft.client.render.GameRenderer;
|
||||
import net.minecraft.client.render.LightmapTextureManager;
|
||||
import net.minecraft.client.render.WorldRenderer;
|
||||
import net.minecraft.client.util.math.Matrix4f;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(WorldRenderer.class)
|
||||
public class WorldRenderer_scarpetRenderMixin
|
||||
{
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void addRenderers(MinecraftClient client, BufferBuilderStorage bufferBuilders, CallbackInfo ci)
|
||||
{
|
||||
CarpetClient.shapes = new ShapesRenderer(client);
|
||||
}
|
||||
|
||||
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/debug/DebugRenderer;render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider$Immediate;DDD)V"))
|
||||
private void renderScarpetThings(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci)
|
||||
{
|
||||
if (CarpetClient.shapes != null) CarpetClient.shapes.render(camera, tickDelta);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package carpet.network;
|
||||
|
||||
import carpet.CarpetServer;
|
||||
import carpet.script.utils.ShapesRenderer;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public class CarpetClient
|
||||
{
|
||||
public static final Object sync = new Object();
|
||||
public static final int HI = 69;
|
||||
public static final int HELLO = 420;
|
||||
public static final int DATA = 1;
|
||||
public static ShapesRenderer shapes = null;
|
||||
|
||||
private static ClientPlayerEntity clientPlayer = null;
|
||||
private static boolean isServerCarpet = false;
|
||||
public static String serverCarpetVersion;
|
||||
public static final Identifier CARPET_CHANNEL = new Identifier("carpet:hello");
|
||||
|
||||
public static void gameJoined(ClientPlayerEntity player)
|
||||
{
|
||||
synchronized (sync)
|
||||
{
|
||||
clientPlayer = player;
|
||||
// client didn't say hi back yet
|
||||
if (isServerCarpet)
|
||||
ClientNetworkHandler.respondHello();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static void disconnect()
|
||||
{
|
||||
isServerCarpet = false;
|
||||
clientPlayer = null;
|
||||
CarpetServer.disconnect();
|
||||
}
|
||||
|
||||
public static void setCarpet()
|
||||
{
|
||||
isServerCarpet = true;
|
||||
}
|
||||
|
||||
public static ClientPlayerEntity getPlayer()
|
||||
{
|
||||
return clientPlayer;
|
||||
}
|
||||
|
||||
public static boolean isCarpet()
|
||||
{
|
||||
return isServerCarpet;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package carpet.network;
|
||||
|
||||
import carpet.CarpetServer;
|
||||
import carpet.CarpetSettings;
|
||||
import carpet.helpers.TickSpeed;
|
||||
import carpet.settings.ParsedRule;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.nbt.AbstractNumberTag;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket;
|
||||
import net.minecraft.util.PacketByteBuf;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class ClientNetworkHandler
|
||||
{
|
||||
private static Map<String, BiConsumer<ClientPlayerEntity, Tag>> dataHandlers = new HashMap<String, BiConsumer<ClientPlayerEntity, Tag>>(){{
|
||||
put("Rules", (p, t) -> {
|
||||
CompoundTag ruleset = (CompoundTag)t;
|
||||
for (String ruleName: ruleset.getKeys())
|
||||
{
|
||||
ParsedRule<?> rule = CarpetServer.settingsManager.getRule(ruleName);
|
||||
if (rule == null)
|
||||
CarpetSettings.LOG.error("Received unknown rule: "+ruleName);
|
||||
else
|
||||
{
|
||||
CompoundTag ruleNBT = (CompoundTag) ruleset.get(ruleName);
|
||||
String value = ruleNBT.getString("Value");
|
||||
rule.set(null, value);
|
||||
}
|
||||
}
|
||||
});
|
||||
put("TickRate", (p, t) -> TickSpeed.tickrate(((AbstractNumberTag)t).getFloat(), false));
|
||||
put("scShape", (p, t) -> { // deprecated
|
||||
if (CarpetClient.shapes != null)
|
||||
CarpetClient.shapes.addShape((CompoundTag)t);
|
||||
});
|
||||
put("scShapes", (p, t) -> {
|
||||
if (CarpetClient.shapes != null)
|
||||
CarpetClient.shapes.addShapes((ListTag) t);
|
||||
});
|
||||
}};
|
||||
|
||||
|
||||
public static void handleData(PacketByteBuf data, ClientPlayerEntity player)
|
||||
{
|
||||
if (data != null)
|
||||
{
|
||||
int id = data.readVarInt();
|
||||
if (id == CarpetClient.HI)
|
||||
onHi(data);
|
||||
if (id == CarpetClient.DATA)
|
||||
onSyncData(data, player);
|
||||
}
|
||||
}
|
||||
|
||||
private static void onHi(PacketByteBuf data)
|
||||
{
|
||||
synchronized (CarpetClient.sync)
|
||||
{
|
||||
CarpetClient.setCarpet();
|
||||
CarpetClient.serverCarpetVersion = data.readString(64);
|
||||
if (CarpetSettings.carpetVersion.equals(CarpetClient.serverCarpetVersion))
|
||||
{
|
||||
CarpetSettings.LOG.info("Joined carpet server with matching carpet version");
|
||||
}
|
||||
else
|
||||
{
|
||||
CarpetSettings.LOG.warn("Joined carpet server with another carpet version: "+CarpetClient.serverCarpetVersion);
|
||||
}
|
||||
if (CarpetClient.getPlayer() != null)
|
||||
respondHello();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static void respondHello()
|
||||
{
|
||||
CarpetClient.getPlayer().networkHandler.sendPacket(new CustomPayloadC2SPacket(
|
||||
CarpetClient.CARPET_CHANNEL,
|
||||
(new PacketByteBuf(Unpooled.buffer())).writeVarInt(CarpetClient.HELLO).writeString(CarpetSettings.carpetVersion)
|
||||
));
|
||||
}
|
||||
|
||||
private static void onSyncData(PacketByteBuf data, ClientPlayerEntity player)
|
||||
{
|
||||
CompoundTag compound = data.readCompoundTag();
|
||||
if (compound == null) return;
|
||||
for (String key: compound.getKeys())
|
||||
{
|
||||
if (dataHandlers.containsKey(key))
|
||||
dataHandlers.get(key).accept(player, compound.get(key));
|
||||
else
|
||||
CarpetSettings.LOG.error("Unknown carpet data: "+key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
package carpet.network;
|
||||
|
||||
import carpet.CarpetServer;
|
||||
import carpet.CarpetSettings;
|
||||
import carpet.helpers.TickSpeed;
|
||||
import carpet.settings.ParsedRule;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.util.PacketByteBuf;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class ServerNetworkHandler
|
||||
{
|
||||
private static Map<ServerPlayerEntity, String> remoteCarpetPlayers = new HashMap<>();
|
||||
private static Set<ServerPlayerEntity> validCarpetPlayers = new HashSet<>();
|
||||
|
||||
public static void handleData(PacketByteBuf data, ServerPlayerEntity player)
|
||||
{
|
||||
if (data != null)
|
||||
{
|
||||
int id = data.readVarInt();
|
||||
if (id == CarpetClient.HELLO)
|
||||
onHello(player, data);
|
||||
}
|
||||
}
|
||||
public static void onPlayerJoin(ServerPlayerEntity playerEntity)
|
||||
{
|
||||
if (!playerEntity.networkHandler.connection.isLocal())
|
||||
{
|
||||
playerEntity.networkHandler.sendPacket(new CustomPayloadS2CPacket(
|
||||
CarpetClient.CARPET_CHANNEL,
|
||||
(new PacketByteBuf(Unpooled.buffer())).writeVarInt(CarpetClient.HI).writeString(CarpetSettings.carpetVersion)
|
||||
));
|
||||
}
|
||||
else
|
||||
{
|
||||
validCarpetPlayers.add(playerEntity);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void onHello(ServerPlayerEntity playerEntity, PacketByteBuf packetData)
|
||||
{
|
||||
|
||||
validCarpetPlayers.add(playerEntity);
|
||||
String clientVersion = packetData.readString(64);
|
||||
remoteCarpetPlayers.put(playerEntity, clientVersion);
|
||||
if (clientVersion.equals(CarpetSettings.carpetVersion))
|
||||
CarpetSettings.LOG.info("Player "+playerEntity.getName().getString()+" joined with a matching carpet client");
|
||||
else
|
||||
CarpetSettings.LOG.warn("Player "+playerEntity.getName().getString()+" joined with another carpet version: "+clientVersion);
|
||||
DataBuilder data = DataBuilder.create().withTickRate();
|
||||
CarpetServer.settingsManager.getRules().forEach(data::withRule);
|
||||
playerEntity.networkHandler.sendPacket(new CustomPayloadS2CPacket(CarpetClient.CARPET_CHANNEL, data.build() ));
|
||||
}
|
||||
|
||||
public static void updateRuleWithConnectedClients(ParsedRule<?> rule)
|
||||
{
|
||||
if (CarpetSettings.superSecretSetting) return;
|
||||
for (ServerPlayerEntity player : remoteCarpetPlayers.keySet())
|
||||
{
|
||||
player.networkHandler.sendPacket(new CustomPayloadS2CPacket(
|
||||
CarpetClient.CARPET_CHANNEL,
|
||||
DataBuilder.create().withRule(rule).build()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateTickSpeedToConnectedPlayers()
|
||||
{
|
||||
if (CarpetSettings.superSecretSetting) return;
|
||||
for (ServerPlayerEntity player : remoteCarpetPlayers.keySet())
|
||||
{
|
||||
player.networkHandler.sendPacket(new CustomPayloadS2CPacket(
|
||||
CarpetClient.CARPET_CHANNEL,
|
||||
DataBuilder.create().withTickRate().build()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
public static void broadcastCustomCommand(String command, Tag data)
|
||||
{
|
||||
if (CarpetSettings.superSecretSetting) return;
|
||||
for (ServerPlayerEntity player : validCarpetPlayers)
|
||||
{
|
||||
player.networkHandler.sendPacket(new CustomPayloadS2CPacket(
|
||||
CarpetClient.CARPET_CHANNEL,
|
||||
DataBuilder.create().withCustomNbt(command, data).build()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendCustomCommand(ServerPlayerEntity player, String command, Tag data)
|
||||
{
|
||||
if (isValidCarpetPlayer(player))
|
||||
{
|
||||
player.networkHandler.sendPacket(new CustomPayloadS2CPacket(
|
||||
CarpetClient.CARPET_CHANNEL,
|
||||
DataBuilder.create().withCustomNbt(command, data).build()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void onPlayerLoggedOut(ServerPlayerEntity player)
|
||||
{
|
||||
validCarpetPlayers.remove(player);
|
||||
if (!player.networkHandler.connection.isLocal())
|
||||
remoteCarpetPlayers.remove(player);
|
||||
}
|
||||
|
||||
public static void close()
|
||||
{
|
||||
remoteCarpetPlayers.clear();
|
||||
validCarpetPlayers.clear();
|
||||
}
|
||||
|
||||
public static boolean isValidCarpetPlayer(ServerPlayerEntity player)
|
||||
{
|
||||
if (CarpetSettings.superSecretSetting) return false;
|
||||
return validCarpetPlayers.contains(player);
|
||||
|
||||
}
|
||||
|
||||
private static class DataBuilder
|
||||
{
|
||||
private CompoundTag tag;
|
||||
private static DataBuilder create()
|
||||
{
|
||||
return new DataBuilder();
|
||||
}
|
||||
private DataBuilder()
|
||||
{
|
||||
tag = new CompoundTag();
|
||||
}
|
||||
private DataBuilder withTickRate()
|
||||
{
|
||||
tag.putFloat("TickRate", TickSpeed.tickrate);
|
||||
return this;
|
||||
}
|
||||
private DataBuilder withRule(ParsedRule<?> rule)
|
||||
{
|
||||
CompoundTag rules = (CompoundTag) tag.get("Rules");
|
||||
if (rules == null)
|
||||
{
|
||||
rules = new CompoundTag();
|
||||
tag.put("Rules", rules);
|
||||
}
|
||||
CompoundTag ruleNBT = new CompoundTag();
|
||||
ruleNBT.putString("Value", rule.getAsString());
|
||||
rules.put(rule.name, ruleNBT);
|
||||
return this;
|
||||
}
|
||||
|
||||
public DataBuilder withCustomNbt(String key, Tag value)
|
||||
{
|
||||
tag.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
private PacketByteBuf build()
|
||||
{
|
||||
PacketByteBuf packetBuf = new PacketByteBuf(Unpooled.buffer());
|
||||
packetBuf.writeVarInt(CarpetClient.DATA);
|
||||
packetBuf.writeCompoundTag(tag);
|
||||
return packetBuf;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,8 @@ import carpet.script.value.StringValue;
|
||||
import carpet.script.value.Value;
|
||||
import carpet.utils.Messenger;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
@@ -50,6 +52,7 @@ import java.util.stream.Collectors;
|
||||
public class CarpetEventServer
|
||||
{
|
||||
public final List<ScheduledCall> scheduledCalls = new LinkedList<>();
|
||||
public final MinecraftServer server;
|
||||
|
||||
public static class Callback
|
||||
{
|
||||
@@ -125,7 +128,13 @@ public class CarpetEventServer
|
||||
List<LazyValue> argv = argumentSupplier.get(); // empty for onTickDone
|
||||
ServerCommandSource source = cmdSourceSupplier.get();
|
||||
assert argv.size() == reqArgs;
|
||||
callList.removeIf(call -> !CarpetServer.scriptServer.runas(source, call.host, call.function, argv)); // this actually does the calls
|
||||
List<Callback> fails = new ArrayList<>();
|
||||
for (Callback call: callList)
|
||||
{
|
||||
if (!CarpetServer.scriptServer.runas(source, call.host, call.function, argv))
|
||||
fails.add(call);
|
||||
}
|
||||
for (Callback call : fails) callList.remove(call);
|
||||
}
|
||||
}
|
||||
public boolean addEventCall(ServerCommandSource source, String hostName, String funName, Function<ScriptHost, Boolean> verifier)
|
||||
@@ -479,6 +488,90 @@ public class CarpetEventServer
|
||||
handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
|
||||
}
|
||||
},
|
||||
PLAYER_TAKES_DAMAGE("player_takes_damage", 4, false)
|
||||
{
|
||||
@Override
|
||||
public void onDamage(Entity target, float amount, DamageSource source)
|
||||
{
|
||||
handler.call( () ->
|
||||
{
|
||||
return Arrays.asList(
|
||||
((c, t) -> new EntityValue(target)),
|
||||
((c, t) -> new NumericValue(amount)),
|
||||
((c, t) ->new StringValue(source.getName())),
|
||||
((c, t) -> source.getAttacker()==null?Value.NULL:new EntityValue(source.getAttacker()))
|
||||
);
|
||||
}, target::getCommandSource);
|
||||
}
|
||||
},
|
||||
PLAYER_DEALS_DAMAGE("player_deals_damage", 3, false)
|
||||
{
|
||||
@Override
|
||||
public void onDamage(Entity target, float amount, DamageSource source)
|
||||
{
|
||||
handler.call( () ->
|
||||
{
|
||||
return Arrays.asList(
|
||||
((c, t) -> new EntityValue(source.getAttacker())),
|
||||
((c, t) -> new NumericValue(amount)),
|
||||
((c, t) -> new EntityValue(target))
|
||||
);
|
||||
}, () -> source.getAttacker().getCommandSource());
|
||||
}
|
||||
},
|
||||
PLAYER_DIES("player_dies", 1, false)
|
||||
{
|
||||
@Override
|
||||
public void onPlayerEvent(ServerPlayerEntity player)
|
||||
{
|
||||
handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
|
||||
}
|
||||
},
|
||||
PLAYER_RESPAWNS("player_respawns", 1, false)
|
||||
{
|
||||
@Override
|
||||
public void onPlayerEvent(ServerPlayerEntity player)
|
||||
{
|
||||
handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
|
||||
}
|
||||
},
|
||||
PLAYER_CHANGES_DIMENSION("player_changes_dimension", 5, false)
|
||||
{
|
||||
@Override
|
||||
public void onDimensionChange(ServerPlayerEntity player, Vec3d from, Vec3d to, DimensionType fromDim, DimensionType dimTo)
|
||||
{
|
||||
// eligibility already checked in mixin
|
||||
Value fromValue = ListValue.fromTriple(from.x, from.y, from.z);
|
||||
Value toValue = (to == null)?Value.NULL:ListValue.fromTriple(to.x, to.y, to.z);
|
||||
Value fromDimStr = new StringValue(NBTSerializableValue.nameFromRegistryId(Registry.DIMENSION_TYPE.getId(fromDim)));
|
||||
Value toDimStr = new StringValue(NBTSerializableValue.nameFromRegistryId(Registry.DIMENSION_TYPE.getId(dimTo)));
|
||||
|
||||
handler.call( () -> Arrays.asList(
|
||||
((c, t) -> new EntityValue(player)),
|
||||
((c, t) -> fromValue),
|
||||
((c, t) -> fromDimStr),
|
||||
((c, t) -> toValue),
|
||||
((c, t) -> toDimStr)
|
||||
), player::getCommandSource);
|
||||
}
|
||||
},
|
||||
PLAYER_CONNECTS("player_connects", 1, false) {
|
||||
@Override
|
||||
public void onPlayerEvent(ServerPlayerEntity player)
|
||||
{
|
||||
handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
|
||||
}
|
||||
},
|
||||
PLAYER_DISCONNECTS("player_disconnects", 2, false) {
|
||||
@Override
|
||||
public void onPlayerMessage(ServerPlayerEntity player, String message)
|
||||
{
|
||||
handler.call( () -> Arrays.asList(
|
||||
((c, t) -> new EntityValue(player)),
|
||||
((c, t) -> new StringValue(message))
|
||||
), player::getCommandSource);
|
||||
}
|
||||
},
|
||||
STATISTICS("statistic", 4, false)
|
||||
{
|
||||
private <T> Identifier getStatId(Stat<T> stat)
|
||||
@@ -543,6 +636,7 @@ public class CarpetEventServer
|
||||
public void onTick() { }
|
||||
public void onChunkGenerated(ServerWorld world, Chunk chunk) { }
|
||||
public void onPlayerEvent(ServerPlayerEntity player) { }
|
||||
public void onPlayerMessage(ServerPlayerEntity player, String message) { }
|
||||
public void onPlayerStatistic(ServerPlayerEntity player, Stat<?> stat, int amount) { }
|
||||
public void onMountControls(ServerPlayerEntity player, float strafeSpeed, float forwardSpeed, boolean jumping, boolean sneaking) { }
|
||||
public void onItemAction(ServerPlayerEntity player, Hand enumhand, ItemStack itemstack) { }
|
||||
@@ -551,13 +645,18 @@ public class CarpetEventServer
|
||||
public void onBlockBroken(ServerPlayerEntity player, BlockPos pos, BlockState previousBS) { }
|
||||
public void onBlockPlaced(ServerPlayerEntity player, BlockPos pos, Hand enumhand, ItemStack itemstack) { }
|
||||
public void onEntityAction(ServerPlayerEntity player, Entity entity, Hand enumhand) { }
|
||||
public void onDimensionChange(ServerPlayerEntity player, Vec3d from, Vec3d to, DimensionType fromDim, DimensionType dimTo) {}
|
||||
public void onDamage(Entity target, float amount, DamageSource source) { }
|
||||
|
||||
|
||||
public void onWorldEvent(ServerWorld world, BlockPos pos) { }
|
||||
public void onWorldEventFlag(ServerWorld world, BlockPos pos, int flag) { }
|
||||
}
|
||||
|
||||
|
||||
public CarpetEventServer()
|
||||
public CarpetEventServer(MinecraftServer server)
|
||||
{
|
||||
this.server = server;
|
||||
for (Event e: Event.values())
|
||||
e.handler.callList.clear();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -96,7 +96,7 @@ public class CarpetScriptHost extends ScriptHost
|
||||
public void addUserDefinedFunction(Context ctx, Module module, String funName, FunctionValue function)
|
||||
{
|
||||
super.addUserDefinedFunction(ctx, module, funName, function);
|
||||
// mcarpet
|
||||
if (ctx.host.main != module) return; // not dealing with automatic imports / exports /configs / apps from imports
|
||||
if (funName.startsWith("__")) // potential fishy activity
|
||||
{
|
||||
if (funName.startsWith("__on_")) // here we can make a determination if we want to only accept events from main module.
|
||||
@@ -323,7 +323,7 @@ public class CarpetScriptHost extends ScriptHost
|
||||
{
|
||||
try
|
||||
{
|
||||
callUDF(BlockPos.ORIGIN, CarpetServer.minecraft_server.getCommandSource(), closing, Collections.emptyList());
|
||||
callUDF(BlockPos.ORIGIN, scriptServer.server.getCommandSource(), closing, Collections.emptyList());
|
||||
}
|
||||
catch (InvalidCallbackException ignored)
|
||||
{
|
||||
@@ -334,8 +334,8 @@ public class CarpetScriptHost extends ScriptHost
|
||||
FunctionValue userClosing = value.getFunction("__on_close");
|
||||
if (userClosing != null)
|
||||
{
|
||||
ServerPlayerEntity player = CarpetServer.minecraft_server.getPlayerManager().getPlayer(key);
|
||||
ServerCommandSource source = (player != null)?player.getCommandSource():CarpetServer.minecraft_server.getCommandSource();
|
||||
ServerPlayerEntity player = scriptServer.server.getPlayerManager().getPlayer(key);
|
||||
ServerCommandSource source = (player != null)?player.getCommandSource():scriptServer.server.getCommandSource();
|
||||
try
|
||||
{
|
||||
((CarpetScriptHost) value).callUDF(BlockPos.ORIGIN, source, userClosing, Collections.emptyList());
|
||||
@@ -347,7 +347,7 @@ public class CarpetScriptHost extends ScriptHost
|
||||
});
|
||||
|
||||
String markerName = CarpetExpression.MARKER_STRING+"_"+((getName()==null)?"":getName());
|
||||
for (ServerWorld world : CarpetServer.minecraft_server.getWorlds())
|
||||
for (ServerWorld world : scriptServer.server.getWorlds())
|
||||
{
|
||||
for (Entity e : world.getEntities(EntityType.ARMOR_STAND, (as) -> as.getScoreboardTags().contains(markerName)))
|
||||
{
|
||||
@@ -361,32 +361,31 @@ public class CarpetScriptHost extends ScriptHost
|
||||
|
||||
private void dumpState()
|
||||
{
|
||||
main.saveData(null, globalState);
|
||||
Module.saveData(main, null, globalState, false);
|
||||
}
|
||||
|
||||
private Tag loadState()
|
||||
{
|
||||
return main.getData(null);
|
||||
return Module.getData(main, null, false);
|
||||
}
|
||||
|
||||
public Tag getGlobalState(String file)
|
||||
public Tag readFileTag(String file, boolean isShared)
|
||||
{
|
||||
if (getName() == null ) return null;
|
||||
if (getName() == null && !isShared) return null;
|
||||
if (file != null)
|
||||
return main.getData(file);
|
||||
return Module.getData(main, file, isShared);
|
||||
if (parent == null)
|
||||
return globalState;
|
||||
return ((CarpetScriptHost)parent).globalState;
|
||||
}
|
||||
|
||||
public void setGlobalState(Tag tag, String file)
|
||||
public boolean writeTagFile(Tag tag, String file, boolean isShared)
|
||||
{
|
||||
if (getName() == null ) return;
|
||||
if (getName() == null && !isShared) return false; // if belongs to an app, cannot be default host.
|
||||
|
||||
if (file!= null)
|
||||
{
|
||||
main.saveData(file, tag);
|
||||
return;
|
||||
return Module.saveData(main, file, tag, isShared);
|
||||
}
|
||||
|
||||
CarpetScriptHost responsibleHost = (parent != null)?(CarpetScriptHost) parent:this;
|
||||
@@ -396,8 +395,28 @@ public class CarpetScriptHost extends ScriptHost
|
||||
responsibleHost.dumpState();
|
||||
responsibleHost.saveTimeout = 200;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean removeResourceFile(String resource, boolean isShared, String type)
|
||||
{
|
||||
if (getName() == null && !isShared) return false; //
|
||||
return Module.dropExistingFile(main, resource, type.equals("nbt")?"nbt":"txt", isShared);
|
||||
}
|
||||
|
||||
public boolean appendLogFile(String resource, boolean isShared, String type, List<String> data)
|
||||
{
|
||||
if (getName() == null && !isShared) return false; // if belongs to an app, cannot be default host.
|
||||
return Module.appendToTextFile(main, resource, type, isShared, data);
|
||||
}
|
||||
|
||||
public List<String> readTextResource(String resource, boolean isShared)
|
||||
{
|
||||
if (getName() == null && !isShared) return null; //
|
||||
return Module.listFile(main, resource, "txt", isShared);
|
||||
}
|
||||
|
||||
|
||||
public void tick()
|
||||
{
|
||||
if (this.saveTimeout > 0)
|
||||
@@ -491,4 +510,9 @@ public class CarpetScriptHost extends ScriptHost
|
||||
{
|
||||
handleErrorWithStack(message, new CarpetExpressionException(exc.getMessage(), exc.stack));
|
||||
}
|
||||
|
||||
public CarpetScriptServer getScriptServer()
|
||||
{
|
||||
return scriptServer;
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import carpet.utils.Messenger;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.tree.CommandNode;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
@@ -34,6 +35,7 @@ import static net.minecraft.server.command.CommandManager.literal;
|
||||
public class CarpetScriptServer
|
||||
{
|
||||
//make static for now, but will change that later:
|
||||
public final MinecraftServer server;
|
||||
public final CarpetScriptHost globalHost;
|
||||
public final Map<String, CarpetScriptHost> modules;
|
||||
public long tickStart;
|
||||
@@ -47,16 +49,18 @@ public class CarpetScriptServer
|
||||
add(new BundledModule("event_test", false));
|
||||
add(new BundledModule("stats_test", false));
|
||||
add(new BundledModule("math", true));
|
||||
add(new BundledModule("chunk_display", false));
|
||||
}};
|
||||
|
||||
public CarpetScriptServer()
|
||||
public CarpetScriptServer(MinecraftServer server)
|
||||
{
|
||||
this.server = server;
|
||||
ScriptHost.systemGlobals.clear();
|
||||
events = new CarpetEventServer();
|
||||
events = new CarpetEventServer(server);
|
||||
modules = new HashMap<>();
|
||||
tickStart = 0L;
|
||||
stopAll = false;
|
||||
holyMoly = CarpetServer.minecraft_server.getCommandManager().getDispatcher().getRoot().getChildren().stream().map(CommandNode::getName).collect(Collectors.toSet());
|
||||
holyMoly = server.getCommandManager().getDispatcher().getRoot().getChildren().stream().map(CommandNode::getName).collect(Collectors.toSet());
|
||||
globalHost = CarpetScriptHost.create(this, null, false, null);
|
||||
}
|
||||
|
||||
@@ -64,10 +68,10 @@ public class CarpetScriptServer
|
||||
{
|
||||
if (CarpetSettings.scriptsAutoload)
|
||||
{
|
||||
Messenger.m(CarpetServer.minecraft_server.getCommandSource(), "Auto-loading world scarpet apps");
|
||||
Messenger.m(server.getCommandSource(), "Auto-loading world scarpet apps");
|
||||
for (String moduleName: listAvailableModules(false))
|
||||
{
|
||||
addScriptHost(CarpetServer.minecraft_server.getCommandSource(), moduleName, true, true);
|
||||
addScriptHost(server.getCommandSource(), moduleName, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,8 +79,8 @@ public class CarpetScriptServer
|
||||
|
||||
public Module getModule(String name, boolean allowLibraries)
|
||||
{
|
||||
File folder = CarpetServer.minecraft_server.getLevelStorage().resolveFile(
|
||||
CarpetServer.minecraft_server.getLevelName(), "scripts");
|
||||
File folder = server.getLevelStorage().resolveFile(
|
||||
server.getLevelName(), "scripts");
|
||||
File[] listOfFiles = folder.listFiles();
|
||||
if (listOfFiles != null)
|
||||
for (File script : listOfFiles)
|
||||
@@ -110,8 +114,8 @@ public class CarpetScriptServer
|
||||
if (!mi.isLibrary()) moduleNames.add(mi.getName());
|
||||
}
|
||||
}
|
||||
File folder = CarpetServer.minecraft_server.getLevelStorage().resolveFile(
|
||||
CarpetServer.minecraft_server.getLevelName(), "scripts");
|
||||
File folder = server.getLevelStorage().resolveFile(
|
||||
server.getLevelName(), "scripts");
|
||||
File[] listOfFiles = folder.listFiles();
|
||||
if (listOfFiles == null)
|
||||
return moduleNames;
|
||||
@@ -223,7 +227,7 @@ public class CarpetScriptServer
|
||||
})));
|
||||
}
|
||||
Messenger.m(source, "gi "+hostName+" app loaded with /"+hostName+" command");
|
||||
CarpetServer.minecraft_server.getCommandManager().getDispatcher().register(command);
|
||||
server.getCommandManager().getDispatcher().register(command);
|
||||
CarpetServer.settingsManager.notifyPlayersCommandsChanged();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import carpet.script.Fluff.QuadFunction;
|
||||
import carpet.script.Fluff.QuinnFunction;
|
||||
import carpet.script.Fluff.SexFunction;
|
||||
import carpet.script.Fluff.TriFunction;
|
||||
import carpet.script.argument.FunctionArgument;
|
||||
import carpet.script.bundled.Module;
|
||||
import carpet.script.exception.BreakStatement;
|
||||
import carpet.script.exception.ContinueStatement;
|
||||
@@ -417,6 +418,12 @@ public class Expression
|
||||
return result;
|
||||
}
|
||||
|
||||
public void alias(String copy, String original)
|
||||
{
|
||||
functions.put(copy, functions.get(original));
|
||||
}
|
||||
|
||||
|
||||
private void UserDefinedFunctionsAndControlFlow() // public just to get the javadoc right
|
||||
{
|
||||
// artificial construct to handle user defined functions and function definitions
|
||||
@@ -439,19 +446,9 @@ public class Expression
|
||||
//lv.remove(lv.size()-1); // aint gonna cut it // maybe it will because of the eager eval changes
|
||||
if (t != Context.SIGNATURE) // just call the function
|
||||
{
|
||||
Value functionValue = lv.get(0).evalValue(c);
|
||||
if (!(functionValue instanceof FunctionValue))
|
||||
{
|
||||
String name = functionValue.getString();
|
||||
functionValue = c.host.getAssertFunction(module, name);
|
||||
}
|
||||
List<LazyValue> lvargs = new ArrayList<>(lv.size()-1);
|
||||
for (int i=1; i< lv.size(); i++)
|
||||
{
|
||||
lvargs.add(lv.get(i));
|
||||
}
|
||||
FunctionValue fun = (FunctionValue)functionValue;
|
||||
Value retval = fun.callInContext(expr, c, t, fun.getExpression(), fun.getToken(), lvargs).evalValue(c);
|
||||
FunctionArgument functionArgument = FunctionArgument.findIn(c, module, lv, 0, false, true);
|
||||
FunctionValue fun = functionArgument.function;
|
||||
Value retval = fun.callInContext(expr, c, t, fun.getExpression(), fun.getToken(), functionArgument.args).evalValue(c);
|
||||
return (cc, tt) -> retval; ///!!!! dono might need to store expr and token in statics? (e? t?)
|
||||
}
|
||||
// gimme signature
|
||||
@@ -657,9 +654,18 @@ public class Expression
|
||||
throw new InternalExpressionException("Failed to resolve left hand side of the += operation");
|
||||
}
|
||||
Value key = ((LContainerValue) v1).getAddress();
|
||||
Value res = cvi.get(key).add(v2);
|
||||
cvi.put(key, res);
|
||||
return (cc, tt) -> res;
|
||||
Value value = cvi.get(key);
|
||||
if (value instanceof ListValue || value instanceof MapValue)
|
||||
{
|
||||
((AbstractListValue) value).append(v2);
|
||||
return (cc, tt) -> value;
|
||||
}
|
||||
else
|
||||
{
|
||||
Value res = value.add(v2);
|
||||
cvi.put(key, res);
|
||||
return (cc, tt) -> res;
|
||||
}
|
||||
}
|
||||
v1.assertAssignable();
|
||||
String varname = v1.getVariable();
|
||||
@@ -1114,7 +1120,7 @@ public class Expression
|
||||
{
|
||||
Value rval= lv.get(0).evalValue(c);
|
||||
if (!(rval instanceof AbstractListValue))
|
||||
throw new InternalExpressionException("Second argument of 'for' function should be a list or iterator");
|
||||
throw new InternalExpressionException("First argument of 'for' function should be a list or iterator");
|
||||
Iterator<Value> iterator = ((AbstractListValue) rval).iterator();
|
||||
LazyValue expr = lv.get(1);
|
||||
//scoping
|
||||
@@ -1558,7 +1564,7 @@ public class Expression
|
||||
if (lv.size() == 1)
|
||||
return new StringValue(format);
|
||||
int argIndex = 1;
|
||||
if (lv.get(1) instanceof ListValue)
|
||||
if (lv.get(1) instanceof ListValue && lv.size() == 2)
|
||||
{
|
||||
lv = ((ListValue) lv.get(1)).getItems();
|
||||
argIndex = 0;
|
||||
@@ -1861,26 +1867,10 @@ public class Expression
|
||||
addLazyFunctionWithDelegation("task", -1, (c, t, expr, tok, lv) -> {
|
||||
if (lv.size() == 0)
|
||||
throw new InternalExpressionException("'task' requires at least function to call as a parameter");
|
||||
Value funcDesc = lv.get(0).evalValue(c);
|
||||
if (!(funcDesc instanceof FunctionValue))
|
||||
{
|
||||
String name = funcDesc.getString();
|
||||
funcDesc = c.host.getAssertFunction(module, name);
|
||||
}
|
||||
FunctionValue fun = (FunctionValue)funcDesc;
|
||||
int extraargs = lv.size() - fun.getArguments().size();
|
||||
if (extraargs != 1 && extraargs != 2)
|
||||
{
|
||||
throw new InternalExpressionException("Function takes "+fun.getArguments().size()+" arguments.");
|
||||
}
|
||||
List<LazyValue> lvargs = new ArrayList<>();
|
||||
for (int i=0; i< fun.getArguments().size(); i++)
|
||||
{
|
||||
lvargs.add(lv.get(i+1));
|
||||
}
|
||||
FunctionArgument functionArgument = FunctionArgument.findIn(c, module, lv, 0, true, false);
|
||||
Value queue = Value.NULL;
|
||||
if (extraargs == 2) queue = lv.get(lv.size()-1).evalValue(c);
|
||||
ThreadValue thread = new ThreadValue(queue, fun, expr, tok, c, lvargs);
|
||||
if (lv.size() > functionArgument.offset) queue = lv.get(functionArgument.offset).evalValue(c);
|
||||
ThreadValue thread = new ThreadValue(queue, functionArgument.function, expr, tok, c, functionArgument.args);
|
||||
Thread.yield();
|
||||
return (cc, tt) -> thread;
|
||||
});
|
||||
@@ -1906,6 +1896,12 @@ public class Expression
|
||||
return ((ThreadValue) v).join();
|
||||
});
|
||||
|
||||
addLazyFunction("task_dock", 1, (c, t, lv) -> {
|
||||
// pass through placeholder
|
||||
// implmenetation should dock the task on the main thread.
|
||||
return lv.get(0);
|
||||
});
|
||||
|
||||
addUnaryFunction("task_completed", (v) -> {
|
||||
if (!(v instanceof ThreadValue))
|
||||
throw new InternalExpressionException("'task_completed' could only be used with a task value");
|
||||
|
||||
@@ -173,9 +173,9 @@ public class Tokenizer implements Iterator<Tokenizer.Token>
|
||||
}
|
||||
else if (nextChar == 't')
|
||||
{
|
||||
throw new ExpressionException(context, this.expression, token,
|
||||
"Tab character is not supported");
|
||||
//token.append('\t');
|
||||
//throw new ExpressionException(context, this.expression, token,
|
||||
// "Tab character is not supported");
|
||||
token.append('\t');
|
||||
}
|
||||
else if (nextChar == 'r')
|
||||
{
|
||||
@@ -201,6 +201,11 @@ public class Tokenizer implements Iterator<Tokenizer.Token>
|
||||
{
|
||||
token.append(input.charAt(pos++));
|
||||
linepos++;
|
||||
if (ch=='\n')
|
||||
{
|
||||
lineno++;
|
||||
linepos = 0;
|
||||
}
|
||||
if (pos == input.length() && expression != null && context != null)
|
||||
throw new ExpressionException(context, this.expression, token, "Program truncated");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package carpet.script.argument;
|
||||
|
||||
public abstract class Argument
|
||||
{
|
||||
public int offset;
|
||||
protected Argument(int offset)
|
||||
{
|
||||
this.offset = offset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package carpet.script.argument;
|
||||
|
||||
import carpet.script.CarpetContext;
|
||||
import carpet.script.LazyValue;
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
import carpet.script.value.BlockValue;
|
||||
import carpet.script.value.ListValue;
|
||||
import carpet.script.value.NullValue;
|
||||
import carpet.script.value.NumericValue;
|
||||
import carpet.script.value.StringValue;
|
||||
import carpet.script.value.Value;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BlockArgument extends Argument
|
||||
{
|
||||
public final BlockValue block;
|
||||
private BlockArgument(BlockValue b, int o)
|
||||
{
|
||||
super(o);
|
||||
block = b;
|
||||
}
|
||||
public static BlockArgument findIn(CarpetContext c, List<LazyValue> params, int offset)
|
||||
{
|
||||
return findIn(c, params,offset, false, false);
|
||||
}
|
||||
|
||||
public static BlockArgument findIn(CarpetContext c, List<LazyValue> params, int offset, boolean acceptString)
|
||||
{
|
||||
return findIn(c, params,offset, acceptString, false);
|
||||
}
|
||||
|
||||
public static BlockArgument findIn(CarpetContext c, List<LazyValue> params, int offset, boolean acceptString, boolean optional)
|
||||
{
|
||||
try
|
||||
{
|
||||
Value v1 = params.get(0 + offset).evalValue(c);
|
||||
//add conditional from string name
|
||||
if (optional && v1 instanceof NullValue)
|
||||
{
|
||||
return new BlockArgument(null, 1+offset);
|
||||
}
|
||||
if (acceptString && v1 instanceof StringValue)
|
||||
{
|
||||
return new BlockArgument(BlockValue.fromString(v1.getString()), 1+offset);
|
||||
}
|
||||
if (v1 instanceof BlockValue)
|
||||
{
|
||||
return new BlockArgument(((BlockValue) v1), 1+offset);
|
||||
}
|
||||
if (v1 instanceof ListValue)
|
||||
{
|
||||
List<Value> args = ((ListValue) v1).getItems();
|
||||
int xpos = (int) NumericValue.asNumber(args.get(0)).getLong();
|
||||
int ypos = (int) NumericValue.asNumber(args.get(1)).getLong();
|
||||
int zpos = (int) NumericValue.asNumber(args.get(2)).getLong();
|
||||
return new BlockArgument(
|
||||
new BlockValue(
|
||||
null,
|
||||
c.s.getWorld(),
|
||||
new BlockPos(c.origin.getX() + xpos, c.origin.getY() + ypos, c.origin.getZ() + zpos)
|
||||
),
|
||||
1+offset);
|
||||
}
|
||||
int xpos = (int) NumericValue.asNumber(v1).getLong();
|
||||
int ypos = (int) NumericValue.asNumber( params.get(1 + offset).evalValue(c)).getLong();
|
||||
int zpos = (int) NumericValue.asNumber( params.get(2 + offset).evalValue(c)).getLong();
|
||||
return new BlockArgument(
|
||||
new BlockValue(
|
||||
null,
|
||||
c.s.getWorld(),
|
||||
new BlockPos(c.origin.getX() + xpos, c.origin.getY() + ypos, c.origin.getZ() + zpos)
|
||||
),
|
||||
3+offset
|
||||
);
|
||||
}
|
||||
catch (IndexOutOfBoundsException e)
|
||||
{
|
||||
throw handleError(optional, acceptString);
|
||||
}
|
||||
}
|
||||
|
||||
public static BlockArgument findInValues(CarpetContext c, List<Value> params, int offset, boolean acceptString, boolean optional)
|
||||
{
|
||||
try
|
||||
{
|
||||
Value v1 = params.get(0 + offset);
|
||||
//add conditional from string name
|
||||
if (optional && v1 instanceof NullValue)
|
||||
{
|
||||
return new BlockArgument(null, 1+offset);
|
||||
}
|
||||
if (acceptString && v1 instanceof StringValue)
|
||||
{
|
||||
return new BlockArgument(BlockValue.fromString(v1.getString()), 1+offset);
|
||||
}
|
||||
if (v1 instanceof BlockValue)
|
||||
{
|
||||
return new BlockArgument(((BlockValue) v1), 1+offset);
|
||||
}
|
||||
if (v1 instanceof ListValue)
|
||||
{
|
||||
List<Value> args = ((ListValue) v1).getItems();
|
||||
int xpos = (int) NumericValue.asNumber(args.get(0)).getLong();
|
||||
int ypos = (int) NumericValue.asNumber(args.get(1)).getLong();
|
||||
int zpos = (int) NumericValue.asNumber(args.get(2)).getLong();
|
||||
return new BlockArgument(
|
||||
new BlockValue(
|
||||
null,
|
||||
c.s.getWorld(),
|
||||
new BlockPos(c.origin.getX() + xpos, c.origin.getY() + ypos, c.origin.getZ() + zpos)
|
||||
),
|
||||
1+offset);
|
||||
}
|
||||
int xpos = (int) NumericValue.asNumber(v1).getLong();
|
||||
int ypos = (int) NumericValue.asNumber( params.get(1 + offset)).getLong();
|
||||
int zpos = (int) NumericValue.asNumber( params.get(2 + offset)).getLong();
|
||||
return new BlockArgument(
|
||||
new BlockValue(
|
||||
null,
|
||||
c.s.getWorld(),
|
||||
new BlockPos(c.origin.getX() + xpos, c.origin.getY() + ypos, c.origin.getZ() + zpos)
|
||||
),
|
||||
3+offset
|
||||
);
|
||||
}
|
||||
catch (IndexOutOfBoundsException e)
|
||||
{
|
||||
throw handleError(optional, acceptString);
|
||||
}
|
||||
}
|
||||
|
||||
private static InternalExpressionException handleError(boolean optional, boolean acceptString)
|
||||
{
|
||||
String message = "Block-type argument should be defined either by three coordinates (a triple or by three arguments), or a block value";
|
||||
if (acceptString)
|
||||
message+=", or a string with block description";
|
||||
if (optional)
|
||||
message+=", or null";
|
||||
return new InternalExpressionException(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package carpet.script.argument;
|
||||
|
||||
import carpet.script.CarpetContext;
|
||||
import carpet.script.Context;
|
||||
import carpet.script.LazyValue;
|
||||
import carpet.script.bundled.Module;
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
import carpet.script.value.FunctionValue;
|
||||
import carpet.script.value.Value;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FunctionArgument extends Argument
|
||||
{
|
||||
public FunctionValue function;
|
||||
public List<LazyValue> args;
|
||||
|
||||
private FunctionArgument(FunctionValue function, int offset, List<LazyValue> args)
|
||||
{
|
||||
super(offset);
|
||||
this.function = function;
|
||||
this.args = args;
|
||||
}
|
||||
public static FunctionArgument findIn(Context c, Module module, List<LazyValue> params, int offset, boolean prematureEvaluation, boolean strict)
|
||||
{
|
||||
Value functionValue = params.get(offset).evalValue(c);
|
||||
if (!(functionValue instanceof FunctionValue))
|
||||
{
|
||||
String name = functionValue.getString();
|
||||
functionValue = c.host.getAssertFunction(module, name);
|
||||
}
|
||||
FunctionValue fun = (FunctionValue)functionValue;
|
||||
int argsize = fun.getArguments().size();
|
||||
int extraargs = params.size() - argsize - offset - 1;
|
||||
if (extraargs < 0 || (extraargs > 0 && strict))
|
||||
throw new InternalExpressionException("Function "+fun.getPrettyString()+" requires "+fun.getArguments().size()+" arguments");
|
||||
List<LazyValue> lvargs = new ArrayList<>();
|
||||
if (prematureEvaluation)
|
||||
{
|
||||
for (int i = 0; i < argsize; i++)
|
||||
{
|
||||
Value arg = params.get(offset + 1 + i).evalValue(c);
|
||||
lvargs.add((cc, tt) -> arg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < argsize; i++) lvargs.add(params.get(offset + 1 + i));
|
||||
}
|
||||
return new FunctionArgument(fun, offset+1+argsize, lvargs);
|
||||
}
|
||||
|
||||
public List<Value> resolveArgs(Context context, Integer type)
|
||||
{
|
||||
List<Value> res = new ArrayList<>(args.size());
|
||||
for (LazyValue arg : args) res.add(arg.evalValue(context, type));
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package carpet.script.argument;
|
||||
|
||||
import carpet.script.CarpetContext;
|
||||
import carpet.script.LazyValue;
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
import carpet.script.value.BlockValue;
|
||||
import carpet.script.value.ListValue;
|
||||
import carpet.script.value.NumericValue;
|
||||
import carpet.script.value.Value;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Vector3Argument extends Argument
|
||||
{
|
||||
public Vec3d vec;
|
||||
public final double yaw;
|
||||
public final double pitch;
|
||||
public boolean fromBlock;
|
||||
private Vector3Argument(Vec3d v, int o)
|
||||
{
|
||||
super(o);
|
||||
this.vec = v;
|
||||
this.yaw = 0.0D;
|
||||
this.pitch = 0.0D;
|
||||
}
|
||||
private Vector3Argument(Vec3d v, int o, double y, double p)
|
||||
{
|
||||
super(o);
|
||||
this.vec = v;
|
||||
this.yaw = y;
|
||||
this.pitch = p;
|
||||
}
|
||||
|
||||
private Vector3Argument fromBlock()
|
||||
{
|
||||
fromBlock = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public static Vector3Argument findIn(CarpetContext c, List<LazyValue> params, int offset)
|
||||
{
|
||||
return findIn(c,params, offset, false);
|
||||
}
|
||||
|
||||
public static Vector3Argument findIn(CarpetContext c, List<LazyValue> params, int offset, boolean optionalDirection)
|
||||
{
|
||||
try
|
||||
{
|
||||
Value v1 = params.get(0 + offset).evalValue(c);
|
||||
if (v1 instanceof BlockValue)
|
||||
{
|
||||
return (new Vector3Argument(new Vec3d(((BlockValue) v1).getPos()).add(0.5,0.5,0.5), 1+offset)).fromBlock();
|
||||
}
|
||||
if (v1 instanceof ListValue)
|
||||
{
|
||||
List<Value> args = ((ListValue) v1).getItems();
|
||||
Vec3d pos = new Vec3d(
|
||||
NumericValue.asNumber(args.get(0)).getDouble(),
|
||||
NumericValue.asNumber(args.get(1)).getDouble(),
|
||||
NumericValue.asNumber(args.get(2)).getDouble());
|
||||
double yaw = 0.0D;
|
||||
double pitch = 0.0D;
|
||||
if (args.size()>3 && optionalDirection)
|
||||
{
|
||||
yaw = NumericValue.asNumber(args.get(3)).getDouble();
|
||||
pitch = NumericValue.asNumber(args.get(4)).getDouble();
|
||||
}
|
||||
return new Vector3Argument(pos,offset+1, yaw, pitch);
|
||||
}
|
||||
Vec3d pos = new Vec3d(
|
||||
NumericValue.asNumber(v1).getDouble(),
|
||||
NumericValue.asNumber(params.get(1 + offset).evalValue(c)).getDouble(),
|
||||
NumericValue.asNumber(params.get(2 + offset).evalValue(c)).getDouble());
|
||||
double yaw = 0.0D;
|
||||
double pitch = 0.0D;
|
||||
int eatenLength = 3;
|
||||
if (params.size()>3+offset && optionalDirection)
|
||||
{
|
||||
yaw = NumericValue.asNumber(params.get(3 + offset).evalValue(c)).getDouble();
|
||||
pitch = NumericValue.asNumber(params.get(4 + offset).evalValue(c)).getDouble();
|
||||
eatenLength = 5;
|
||||
}
|
||||
|
||||
return new Vector3Argument(pos,offset+eatenLength, yaw, pitch);
|
||||
}
|
||||
catch (IndexOutOfBoundsException e)
|
||||
{
|
||||
throw new InternalExpressionException("Position argument should be defined either by three coordinates (a triple or by three arguments), or a positioned block value");
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector3Argument findIn(List<Value> params, int offset, boolean optionalDirection)
|
||||
{
|
||||
try
|
||||
{
|
||||
Value v1 = params.get(0 + offset);
|
||||
if (v1 instanceof BlockValue)
|
||||
{
|
||||
return (new Vector3Argument(new Vec3d(((BlockValue) v1).getPos()).add(0.5,0.5,0.5), 1+offset)).fromBlock();
|
||||
}
|
||||
if (v1 instanceof ListValue)
|
||||
{
|
||||
List<Value> args = ((ListValue) v1).getItems();
|
||||
Vec3d pos = new Vec3d(
|
||||
NumericValue.asNumber(args.get(0)).getDouble(),
|
||||
NumericValue.asNumber(args.get(1)).getDouble(),
|
||||
NumericValue.asNumber(args.get(2)).getDouble());
|
||||
double yaw = 0.0D;
|
||||
double pitch = 0.0D;
|
||||
if (args.size()>3 && optionalDirection)
|
||||
{
|
||||
yaw = NumericValue.asNumber(args.get(3)).getDouble();
|
||||
pitch = NumericValue.asNumber(args.get(4)).getDouble();
|
||||
}
|
||||
return new Vector3Argument(pos,offset+1, yaw, pitch);
|
||||
}
|
||||
Vec3d pos = new Vec3d(
|
||||
NumericValue.asNumber(v1).getDouble(),
|
||||
NumericValue.asNumber(params.get(1 + offset)).getDouble(),
|
||||
NumericValue.asNumber(params.get(2 + offset)).getDouble());
|
||||
double yaw = 0.0D;
|
||||
double pitch = 0.0D;
|
||||
int eatenLength = 3;
|
||||
if (params.size()>3+offset && optionalDirection)
|
||||
{
|
||||
yaw = NumericValue.asNumber(params.get(3 + offset)).getDouble();
|
||||
pitch = NumericValue.asNumber(params.get(4 + offset)).getDouble();
|
||||
eatenLength = 5;
|
||||
}
|
||||
|
||||
return new Vector3Argument(pos,offset+eatenLength, yaw, pitch);
|
||||
}
|
||||
catch (IndexOutOfBoundsException e)
|
||||
{
|
||||
throw new InternalExpressionException("Position argument should be defined either by three coordinates (a triple or by three arguments), or a positioned block value");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,24 @@
|
||||
package carpet.script.bundled;
|
||||
|
||||
import carpet.CarpetServer;
|
||||
import net.minecraft.nbt.PositionTracker;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.nbt.TagReaders;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class FileModule extends Module
|
||||
@@ -74,7 +81,7 @@ public class FileModule extends Module
|
||||
}
|
||||
|
||||
//copied private method from net.minecraft.nbt.NbtIo.write() and client method safe_write
|
||||
public static void write(Tag tag_1, File file)
|
||||
public static boolean write(Tag tag_1, File file)
|
||||
{
|
||||
File file_2 = new File(file.getAbsolutePath() + "_tmp");
|
||||
if (file_2.exists()) file_2.delete();
|
||||
@@ -90,9 +97,50 @@ public class FileModule extends Module
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (file.exists()) file.delete();
|
||||
if (!file.exists()) file_2.renameTo(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean appendText(File filePath, boolean addNewLines, List<String> data)
|
||||
{
|
||||
try
|
||||
{
|
||||
OutputStream out = Files.newOutputStream(filePath.toPath(), StandardOpenOption.APPEND, StandardOpenOption.CREATE);
|
||||
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8)))
|
||||
{
|
||||
for (String line: data)
|
||||
{
|
||||
writer.append(line);
|
||||
if (addNewLines) writer.newLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static List<String> listFileContent(File filePath)
|
||||
{
|
||||
try (BufferedReader reader = Files.newBufferedReader(filePath.toPath(), StandardCharsets.UTF_8)) {
|
||||
List<String> result = new ArrayList<>();
|
||||
for (;;) {
|
||||
String line = reader.readLine();
|
||||
if (line == null)
|
||||
break;
|
||||
result.add(line.replaceAll("[\n\r]+",""));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,42 +4,76 @@ import carpet.CarpetServer;
|
||||
import net.minecraft.nbt.Tag;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import static carpet.script.bundled.FileModule.read;
|
||||
import static carpet.script.bundled.FileModule.write;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class Module
|
||||
{
|
||||
public abstract String getName();
|
||||
public abstract String getCode();
|
||||
public abstract boolean isLibrary();
|
||||
public final static Object writeIOSync = new Object();
|
||||
|
||||
public Tag getData(String file)
|
||||
private static String getDescriptor(Module module, String file, boolean isShared)
|
||||
{
|
||||
File dataFile = CarpetServer.minecraft_server.getLevelStorage().resolveFile(
|
||||
CarpetServer.minecraft_server.getLevelName(), "scripts/"+getName()+".data"+(file==null?"":"."+file)+".nbt");
|
||||
if (!Files.exists(dataFile.toPath()) || !(dataFile.isFile())) return null;
|
||||
return read(dataFile);
|
||||
if (isShared)
|
||||
{
|
||||
return "shared/"+file;
|
||||
}
|
||||
else if (module != null && module.getName() != null) // appdata
|
||||
{
|
||||
return module.getName()+".data"+(file==null?"":"/"+file);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException("Invalid file descriptor: "+file);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveData(String file, Tag globalState)
|
||||
public static Tag getData(Module module, String file, boolean isShared)
|
||||
{
|
||||
File dataFile =CarpetServer.minecraft_server.getLevelStorage().resolveFile(
|
||||
CarpetServer.minecraft_server.getLevelName(), "scripts/"+getName()+".data"+(file==null?"":"."+file)+".nbt");
|
||||
if (!Files.exists(dataFile.toPath().getParent()))
|
||||
{
|
||||
try
|
||||
{
|
||||
Files.createDirectory(dataFile.toPath().getParent());
|
||||
}
|
||||
catch (IOException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
write(globalState, dataFile);
|
||||
File dataFile = resolveResource(module, file, "nbt", isShared);
|
||||
if (dataFile == null) return null;
|
||||
if (!Files.exists(dataFile.toPath()) || !(dataFile.isFile())) return null;
|
||||
synchronized (writeIOSync) { return FileModule.read(dataFile); }
|
||||
}
|
||||
|
||||
public static boolean saveData(Module module, String file, Tag globalState, boolean isShared)
|
||||
{
|
||||
File dataFile = resolveResource(module, file, "nbt", isShared);
|
||||
if (dataFile == null) return false;
|
||||
if (!Files.exists(dataFile.toPath().getParent()) && !dataFile.getParentFile().mkdirs()) return false;
|
||||
synchronized (writeIOSync) { return FileModule.write(globalState, dataFile); }
|
||||
}
|
||||
|
||||
public static boolean appendToTextFile(Module module, String resourceName, String type, boolean isShared, List<String> message)
|
||||
{
|
||||
File dataFile = resolveResource(module, resourceName, "txt", isShared);
|
||||
if (dataFile == null) return false;
|
||||
if (!Files.exists(dataFile.toPath().getParent()) && !dataFile.getParentFile().mkdirs()) return false;
|
||||
synchronized (writeIOSync) { return FileModule.appendText(dataFile, type.equals("text"), message); }
|
||||
}
|
||||
|
||||
public static boolean dropExistingFile(Module module, String resourceName, String ext, boolean isShared)
|
||||
{
|
||||
File dataFile = resolveResource(module, resourceName, ext, isShared);
|
||||
if (dataFile == null) return false;
|
||||
synchronized (writeIOSync) { return dataFile.delete(); }
|
||||
}
|
||||
|
||||
public static List<String> listFile(Module module, String resourceName, String ext, boolean isShared)
|
||||
{
|
||||
File dataFile = resolveResource(module, resourceName, ext, isShared);
|
||||
if (dataFile == null) return null;
|
||||
if (!dataFile.exists()) return null;
|
||||
synchronized (writeIOSync) { return FileModule.listFileContent(dataFile); }
|
||||
}
|
||||
|
||||
private static File resolveResource(Module module, String resourceName, String ext, boolean isShared)
|
||||
{
|
||||
if (!isShared && (module == null || module.getName() == null)) return null;
|
||||
return CarpetServer.minecraft_server.getLevelStorage().resolveFile(
|
||||
CarpetServer.minecraft_server.getLevelName(), "scripts/"+getDescriptor(module, resourceName, isShared)+"."+ext);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,790 @@
|
||||
package carpet.script.utils;
|
||||
|
||||
import carpet.CarpetSettings;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.BufferBuilder;
|
||||
import net.minecraft.client.render.Camera;
|
||||
import net.minecraft.client.render.Tessellator;
|
||||
import net.minecraft.client.render.VertexFormats;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.IWorld;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class ShapesRenderer
|
||||
{
|
||||
private final Map<DimensionType, Long2ObjectOpenHashMap<RenderedShape<? extends ShapeDispatcher.ExpiringShape>>> shapes;
|
||||
private MinecraftClient client;
|
||||
|
||||
private Map<String, BiFunction<MinecraftClient, ShapeDispatcher.ExpiringShape, RenderedShape<? extends ShapeDispatcher.ExpiringShape >>> renderedShapes
|
||||
= new HashMap<String, BiFunction<MinecraftClient, ShapeDispatcher.ExpiringShape, RenderedShape<? extends ShapeDispatcher.ExpiringShape>>>()
|
||||
{{
|
||||
put("line", RenderedLine::new);
|
||||
put("box", RenderedBox::new);
|
||||
put("sphere", RenderedSphere::new);
|
||||
put("cylinder", RenderedCylinder::new);
|
||||
}};
|
||||
|
||||
public ShapesRenderer(MinecraftClient minecraftClient)
|
||||
{
|
||||
this.client = minecraftClient;
|
||||
shapes = new HashMap<>();
|
||||
shapes.put(DimensionType.OVERWORLD, new Long2ObjectOpenHashMap<>());
|
||||
shapes.put(DimensionType.THE_NETHER, new Long2ObjectOpenHashMap<>());
|
||||
shapes.put(DimensionType.THE_END, new Long2ObjectOpenHashMap<>());
|
||||
}
|
||||
|
||||
public void render(Camera camera, float partialTick)
|
||||
{
|
||||
IWorld iWorld = this.client.world;
|
||||
DimensionType dimensionType = iWorld.getDimension().getType();
|
||||
if (shapes.get(dimensionType).isEmpty()) return;
|
||||
long currentTime = client.world.getTime();
|
||||
RenderSystem.disableTexture();
|
||||
RenderSystem.enableDepthTest();
|
||||
RenderSystem.depthFunc(515);
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.defaultBlendFunc();
|
||||
//RenderSystem.blendFuncSeparate(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE, GlStateManager.SrcFactor.ONE, GlStateManager.DstFactor.ZERO);
|
||||
//RenderSystem.shadeModel(7425);
|
||||
RenderSystem.shadeModel(GL11.GL_FLAT);
|
||||
RenderSystem.enableAlphaTest();
|
||||
RenderSystem.defaultAlphaFunc();
|
||||
//RenderSystem.alphaFunc(GL11.GL_GREATER, 0.005F);
|
||||
RenderSystem.disableCull();
|
||||
RenderSystem.disableLighting();
|
||||
RenderSystem.depthMask(false);
|
||||
//RenderSystem.polygonOffset(-3f, -3f);
|
||||
//RenderSystem.enablePolygonOffset();
|
||||
//Entity entity = this.client.gameRenderer.getCamera().getFocusedEntity();
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder bufferBuilder = tessellator.getBuffer();
|
||||
|
||||
// render
|
||||
double cameraX = camera.getPos().x;
|
||||
double cameraY = camera.getPos().y;
|
||||
double cameraZ = camera.getPos().z;
|
||||
|
||||
synchronized (shapes)
|
||||
{
|
||||
shapes.get(dimensionType).long2ObjectEntrySet().removeIf(
|
||||
entry -> entry.getValue().isExpired(currentTime)
|
||||
);
|
||||
shapes.get(dimensionType).values().forEach(
|
||||
s ->
|
||||
{
|
||||
if ( s.shouldRender(dimensionType))
|
||||
s.renderFaces(tessellator, bufferBuilder, cameraX, cameraY, cameraZ, partialTick);
|
||||
}
|
||||
);
|
||||
//lines
|
||||
shapes.get(dimensionType).values().forEach(
|
||||
|
||||
s -> {
|
||||
if ( s.shouldRender(dimensionType))
|
||||
s.renderLines(tessellator, bufferBuilder, cameraX, cameraY, cameraZ, partialTick);
|
||||
}
|
||||
);
|
||||
}
|
||||
RenderSystem.enableCull();
|
||||
RenderSystem.depthMask(true);
|
||||
RenderSystem.lineWidth(1.0F);
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.defaultBlendFunc();
|
||||
RenderSystem.enableTexture();
|
||||
RenderSystem.shadeModel(7424);
|
||||
}
|
||||
|
||||
public void addShapes(ListTag tag)
|
||||
{
|
||||
for (int i=0, count = tag.size(); i < count; i++)
|
||||
{
|
||||
addShape(tag.getCompound(i));
|
||||
}
|
||||
}
|
||||
|
||||
public void addShape(CompoundTag tag)
|
||||
{
|
||||
ShapeDispatcher.ExpiringShape shape = ShapeDispatcher.fromTag(tag);
|
||||
if (shape == null) return;
|
||||
BiFunction<MinecraftClient, ShapeDispatcher.ExpiringShape, RenderedShape<? extends ShapeDispatcher.ExpiringShape >> shapeFactory;
|
||||
shapeFactory = renderedShapes.get(tag.getString("shape"));
|
||||
if (shapeFactory == null)
|
||||
{
|
||||
CarpetSettings.LOG.info("Unrecognized shape: "+tag.getString("shape"));
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderedShape<?> rshape = shapeFactory.apply(client, shape);
|
||||
DimensionType dim = shape.shapeDimension;
|
||||
long key = rshape.key();
|
||||
synchronized (shapes)
|
||||
{
|
||||
RenderedShape<?> existing = shapes.get(dim).get(key);
|
||||
if (existing != null)
|
||||
{ // promoting previous shape
|
||||
existing.expiryTick = rshape.expiryTick;
|
||||
}
|
||||
else
|
||||
{
|
||||
shapes.get(dim).put(key, rshape);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void reset()
|
||||
{
|
||||
synchronized (shapes)
|
||||
{
|
||||
shapes.values().forEach(Long2ObjectOpenHashMap::clear);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public abstract static class RenderedShape<T extends ShapeDispatcher.ExpiringShape>
|
||||
{
|
||||
protected T shape;
|
||||
protected MinecraftClient client;
|
||||
long expiryTick;
|
||||
double renderEpsilon = 0;
|
||||
public abstract void renderLines(Tessellator tessellator, BufferBuilder builder, double cx, double cy, double cz, float partialTick );
|
||||
public void renderFaces(Tessellator tessellator, BufferBuilder builder, double cx, double cy, double cz, float partialTick ) {}
|
||||
protected RenderedShape(MinecraftClient client, T shape)
|
||||
{
|
||||
this.shape = shape;
|
||||
expiryTick = client.world.getTime()+shape.getExpiry();
|
||||
renderEpsilon = (3+((double)shape.key())/Long.MAX_VALUE)/1000;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public boolean isExpired(long currentTick)
|
||||
{
|
||||
return expiryTick < currentTick;
|
||||
}
|
||||
public long key()
|
||||
{
|
||||
return shape.key();
|
||||
};
|
||||
public boolean shouldRender(DimensionType dim)
|
||||
{
|
||||
if (shape.followEntity <=0 ) return true;
|
||||
if (client.world == null) return false;
|
||||
if (client.world.getEntityById(shape.followEntity) == null) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static class RenderedBox extends RenderedShape<ShapeDispatcher.Box>
|
||||
{
|
||||
|
||||
private RenderedBox(MinecraftClient client, ShapeDispatcher.ExpiringShape shape)
|
||||
{
|
||||
super(client, (ShapeDispatcher.Box)shape);
|
||||
|
||||
}
|
||||
@Override
|
||||
public void renderLines(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz, float partialTick)
|
||||
{
|
||||
if (shape.a == 0.0) return;
|
||||
Vec3d v1 = shape.relativiseRender(client.world, shape.from, partialTick);
|
||||
Vec3d v2 = shape.relativiseRender(client.world, shape.to, partialTick);
|
||||
RenderSystem.lineWidth(shape.lineWidth);
|
||||
drawBoxWireGLLines(tessellator, bufferBuilder,
|
||||
(float)(v1.x-cx-renderEpsilon), (float)(v1.y-cy-renderEpsilon), (float)(v1.z-cz-renderEpsilon),
|
||||
(float)(v2.x-cx+renderEpsilon), (float)(v2.y-cy+renderEpsilon), (float)(v2.z-cz+renderEpsilon),
|
||||
v1.x!=v2.x, v1.y!=v2.y, v1.z!=v2.z,
|
||||
shape.r, shape.g, shape.b, shape.a, shape.r, shape.g, shape.b
|
||||
);
|
||||
}
|
||||
@Override
|
||||
public void renderFaces(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz, float partialTick)
|
||||
{
|
||||
if (shape.fa == 0.0) return;
|
||||
Vec3d v1 = shape.relativiseRender(client.world, shape.from, partialTick);
|
||||
Vec3d v2 = shape.relativiseRender(client.world, shape.to, partialTick);
|
||||
RenderSystem.lineWidth(1.0F);
|
||||
drawBoxFaces(tessellator, bufferBuilder,
|
||||
(float)(v1.x-cx-renderEpsilon), (float)(v1.y-cy-renderEpsilon), (float)(v1.z-cz-renderEpsilon),
|
||||
(float)(v2.x-cx+renderEpsilon), (float)(v2.y-cy+renderEpsilon), (float)(v2.z-cz+renderEpsilon),
|
||||
v1.x!=v2.x, v1.y!=v2.y, v1.z!=v2.z,
|
||||
shape.fr, shape.fg, shape.fb, shape.fa
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class RenderedLine extends RenderedShape<ShapeDispatcher.Line>
|
||||
{
|
||||
public RenderedLine(MinecraftClient client, ShapeDispatcher.ExpiringShape shape)
|
||||
{
|
||||
super(client, (ShapeDispatcher.Line)shape);
|
||||
}
|
||||
@Override
|
||||
public void renderLines(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz, float partialTick)
|
||||
{
|
||||
Vec3d v1 = shape.relativiseRender(client.world, shape.from, partialTick);
|
||||
Vec3d v2 = shape.relativiseRender(client.world, shape.to, partialTick);
|
||||
RenderSystem.lineWidth(shape.lineWidth);
|
||||
drawLine(tessellator, bufferBuilder,
|
||||
(float)(v1.x-cx-renderEpsilon), (float)(v1.y-cy-renderEpsilon), (float)(v1.z-cz-renderEpsilon),
|
||||
(float)(v2.x-cx+renderEpsilon), (float)(v2.y-cy+renderEpsilon), (float)(v2.z-cz+renderEpsilon),
|
||||
shape.r, shape.g, shape.b, shape.a
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static class RenderedSphere extends RenderedShape<ShapeDispatcher.Sphere>
|
||||
{
|
||||
public RenderedSphere(MinecraftClient client, ShapeDispatcher.ExpiringShape shape)
|
||||
{
|
||||
super(client, (ShapeDispatcher.Sphere)shape);
|
||||
}
|
||||
@Override
|
||||
public void renderLines(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz, float partialTick)
|
||||
{
|
||||
if (shape.a == 0.0) return;
|
||||
Vec3d vc = shape.relativiseRender(client.world, shape.center, partialTick);
|
||||
RenderSystem.lineWidth(shape.lineWidth);
|
||||
drawSphereWireframe(tessellator, bufferBuilder,
|
||||
(float)(vc.x-cx), (float)(vc.y-cy), (float)(vc.z-cz),
|
||||
(float)(shape.radius+renderEpsilon), shape.subdivisions,
|
||||
shape.r, shape.g, shape.b, shape.a);
|
||||
}
|
||||
@Override
|
||||
public void renderFaces(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz, float partialTick)
|
||||
{
|
||||
if (shape.fa == 0.0) return;
|
||||
Vec3d vc = shape.relativiseRender(client.world, shape.center, partialTick);
|
||||
RenderSystem.lineWidth(1.0f);
|
||||
drawSphereFaces(tessellator, bufferBuilder,
|
||||
(float)(vc.x-cx), (float)(vc.y-cy), (float)(vc.z-cz),
|
||||
(float)(shape.radius+renderEpsilon), shape.subdivisions,
|
||||
shape.fr, shape.fg, shape.fb, shape.fa);
|
||||
}
|
||||
}
|
||||
|
||||
public static class RenderedCylinder extends RenderedShape<ShapeDispatcher.Cylinder>
|
||||
{
|
||||
public RenderedCylinder(MinecraftClient client, ShapeDispatcher.ExpiringShape shape)
|
||||
{
|
||||
super(client, (ShapeDispatcher.Cylinder)shape);
|
||||
}
|
||||
@Override
|
||||
public void renderLines(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz, float partialTick)
|
||||
{
|
||||
if (shape.a == 0.0) return;
|
||||
Vec3d vc = shape.relativiseRender(client.world, shape.center, partialTick);
|
||||
RenderSystem.lineWidth(shape.lineWidth);
|
||||
double dir = MathHelper.sign(shape.height);
|
||||
drawCylinderWireframe(tessellator, bufferBuilder,
|
||||
(float) (vc.x - cx - dir * renderEpsilon), (float) (vc.y - cy - dir * renderEpsilon), (float) (vc.z - cz - dir * renderEpsilon),
|
||||
(float) (shape.radius + renderEpsilon), (float) (shape.height + 2*dir*renderEpsilon), shape.axis,
|
||||
shape.subdivisions, shape.radius == 0,
|
||||
shape.r, shape.g, shape.b, shape.a);
|
||||
|
||||
}
|
||||
@Override
|
||||
public void renderFaces(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz, float partialTick)
|
||||
{
|
||||
if (shape.fa == 0.0) return;
|
||||
Vec3d vc = shape.relativiseRender(client.world, shape.center, partialTick);
|
||||
RenderSystem.lineWidth(1.0f);
|
||||
double dir = MathHelper.sign(shape.height);
|
||||
drawCylinderFaces(tessellator, bufferBuilder,
|
||||
(float) (vc.x - cx - dir * renderEpsilon), (float) (vc.y - cy - dir * renderEpsilon), (float) (vc.z - cz - dir * renderEpsilon),
|
||||
(float) (shape.radius + renderEpsilon), (float) (shape.height + 2*dir*renderEpsilon), shape.axis,
|
||||
shape.subdivisions, shape.radius == 0,
|
||||
shape.fr, shape.fg, shape.fb, shape.fa);
|
||||
}
|
||||
}
|
||||
|
||||
// some raw shit
|
||||
|
||||
public static void drawLine(Tessellator tessellator, BufferBuilder builder, float x1, float y1, float z1, float x2, float y2, float z2, float red1, float grn1, float blu1, float alpha) {
|
||||
builder.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR); // 3
|
||||
builder.vertex(x1, y1, z1).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next();
|
||||
tessellator.draw();
|
||||
}
|
||||
|
||||
public static void drawBoxWireGLLines(
|
||||
Tessellator tessellator, BufferBuilder builder,
|
||||
float x1, float y1, float z1,
|
||||
float x2, float y2, float z2,
|
||||
boolean xthick, boolean ythick, boolean zthick,
|
||||
float red1, float grn1, float blu1, float alpha, float red2, float grn2, float blu2)
|
||||
{
|
||||
builder.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR); // 3
|
||||
if (xthick)
|
||||
{
|
||||
builder.vertex(x1, y1, z1).color(red1, grn2, blu2, alpha).next();
|
||||
builder.vertex(x2, y1, z1).color(red1, grn2, blu2, alpha).next();
|
||||
|
||||
builder.vertex(x2, y2, z1).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x1, y2, z1).color(red1, grn1, blu1, alpha).next();
|
||||
|
||||
builder.vertex(x1, y1, z2).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x2, y1, z2).color(red1, grn1, blu1, alpha).next();
|
||||
|
||||
builder.vertex(x1, y2, z2).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next();
|
||||
}
|
||||
if (ythick)
|
||||
{
|
||||
builder.vertex(x1, y1, z1).color(red2, grn1, blu2, alpha).next();
|
||||
builder.vertex(x1, y2, z1).color(red2, grn1, blu2, alpha).next();
|
||||
|
||||
builder.vertex(x2, y1, z1).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x2, y2, z1).color(red1, grn1, blu1, alpha).next();
|
||||
|
||||
builder.vertex(x1, y2, z2).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x1, y1, z2).color(red1, grn1, blu1, alpha).next();
|
||||
|
||||
builder.vertex(x2, y1, z2).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next();
|
||||
}
|
||||
if (zthick)
|
||||
{
|
||||
builder.vertex(x1, y1, z1).color(red2, grn2, blu1, alpha).next();
|
||||
builder.vertex(x1, y1, z2).color(red2, grn2, blu1, alpha).next();
|
||||
|
||||
builder.vertex(x1, y2, z1).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x1, y2, z2).color(red1, grn1, blu1, alpha).next();
|
||||
|
||||
builder.vertex(x2, y1, z2).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x2, y1, z1).color(red1, grn1, blu1, alpha).next();
|
||||
|
||||
builder.vertex(x2, y2, z1).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next();
|
||||
}
|
||||
tessellator.draw();
|
||||
}
|
||||
|
||||
public static void drawBoxFaces(
|
||||
Tessellator tessellator, BufferBuilder builder,
|
||||
float x1, float y1, float z1,
|
||||
float x2, float y2, float z2,
|
||||
boolean xthick, boolean ythick, boolean zthick,
|
||||
float red1, float grn1, float blu1, float alpha)
|
||||
{
|
||||
builder.begin(GL11.GL_QUADS, VertexFormats.POSITION_COLOR);
|
||||
|
||||
if (xthick && ythick)
|
||||
{
|
||||
builder.vertex(x1, y1, z1).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x2, y1, z1).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x2, y2, z1).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x1, y2, z1).color(red1, grn1, blu1, alpha).next();
|
||||
if (zthick)
|
||||
{
|
||||
builder.vertex(x1, y1, z2).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x1, y2, z2).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x2, y1, z2).color(red1, grn1, blu1, alpha).next();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (zthick && ythick)
|
||||
{
|
||||
builder.vertex(x1, y1, z1).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x1, y2, z1).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x1, y2, z2).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x1, y1, z2).color(red1, grn1, blu1, alpha).next();
|
||||
|
||||
if (xthick)
|
||||
{
|
||||
builder.vertex(x2, y1, z1).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x2, y1, z2).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x2, y2, z1).color(red1, grn1, blu1, alpha).next();
|
||||
}
|
||||
}
|
||||
|
||||
// now at least drawing one
|
||||
if (zthick && xthick)
|
||||
{
|
||||
builder.vertex(x1, y1, z1).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x2, y1, z1).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x2, y1, z2).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x1, y1, z2).color(red1, grn1, blu1, alpha).next();
|
||||
|
||||
|
||||
if (ythick)
|
||||
{
|
||||
builder.vertex(x1, y2, z1).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x2, y2, z1).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x1, y2, z2).color(red1, grn1, blu1, alpha).next();
|
||||
}
|
||||
}
|
||||
tessellator.draw();
|
||||
}
|
||||
|
||||
public static void drawCylinderWireframe(Tessellator tessellator, BufferBuilder builder,
|
||||
float cx, float cy, float cz,
|
||||
float r, float h, Direction.Axis axis, int subd, boolean isFlat,
|
||||
float red, float grn, float blu, float alpha)
|
||||
{
|
||||
float step = (float)Math.PI / (subd/2);
|
||||
int num_steps180 = (int)(Math.PI / step)+1;
|
||||
int num_steps360 = (int)(2*Math.PI / step);
|
||||
int hsteps = 1;
|
||||
float hstep = 1.0f;
|
||||
if (!isFlat)
|
||||
{
|
||||
hsteps = (int) Math.ceil(MathHelper.abs(h) / (step * r)) + 1;
|
||||
hstep = h / (hsteps - 1);
|
||||
}// draw base
|
||||
|
||||
if (axis == Direction.Axis.Y)
|
||||
{
|
||||
for (int dh = 0; dh < hsteps; dh++)
|
||||
{
|
||||
float hh = dh*hstep;
|
||||
builder.begin(GL11.GL_LINE_LOOP, VertexFormats.POSITION_COLOR);
|
||||
for (int i = 0; i <= num_steps360; i++)
|
||||
{
|
||||
float theta = step * i;
|
||||
float x = r * MathHelper.cos(theta);
|
||||
float y = hh;
|
||||
float z = r * MathHelper.sin(theta);
|
||||
builder.vertex(x + cx, y + cy, z + cz).color(red, grn, blu, alpha).next();
|
||||
}
|
||||
tessellator.draw();
|
||||
}
|
||||
|
||||
if (!isFlat)
|
||||
{
|
||||
for (int i = 0; i <= num_steps180; i++)
|
||||
{
|
||||
builder.begin(GL11.GL_LINE_LOOP, VertexFormats.POSITION_COLOR);
|
||||
float theta = step * i;
|
||||
float x = r * MathHelper.cos(theta);
|
||||
|
||||
float z = r * MathHelper.sin(theta);
|
||||
|
||||
builder.vertex(cx - x, cy + 0, cz + z).color(red, grn, blu, alpha).next();
|
||||
builder.vertex(cx + x, cy + 0, cz - z).color(red, grn, blu, alpha).next();
|
||||
builder.vertex(cx + x, cy + h, cz - z).color(red, grn, blu, alpha).next();
|
||||
builder.vertex(cx - x, cy + h, cz + z).color(red, grn, blu, alpha).next();
|
||||
tessellator.draw();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR);
|
||||
for (int i = 0; i <= num_steps180; i++)
|
||||
{
|
||||
float theta = step * i;
|
||||
float x = r * MathHelper.cos(theta);
|
||||
float z = r * MathHelper.sin(theta);
|
||||
builder.vertex(cx - x, cy, cz + z).color(red, grn, blu, alpha).next();
|
||||
builder.vertex(cx + x, cy, cz - z).color(red, grn, blu, alpha).next();
|
||||
}
|
||||
tessellator.draw();
|
||||
}
|
||||
|
||||
}
|
||||
else if (axis == Direction.Axis.X)
|
||||
{
|
||||
for (int dh = 0; dh < hsteps; dh++)
|
||||
{
|
||||
float hh = dh * hstep;
|
||||
builder.begin(GL11.GL_LINE_LOOP, VertexFormats.POSITION_COLOR);
|
||||
for (int i = 0; i <= num_steps360; i++)
|
||||
{
|
||||
float theta = step * i;
|
||||
float z = r * MathHelper.cos(theta);
|
||||
float x = hh;
|
||||
float y = r * MathHelper.sin(theta);
|
||||
builder.vertex(x + cx, y + cy, z + cz).color(red, grn, blu, alpha).next();
|
||||
}
|
||||
tessellator.draw();
|
||||
}
|
||||
|
||||
if (!isFlat)
|
||||
{
|
||||
for (int i = 0; i <= num_steps180; i++)
|
||||
{
|
||||
builder.begin(GL11.GL_LINE_LOOP, VertexFormats.POSITION_COLOR);
|
||||
float theta = step * i;
|
||||
float y = r * MathHelper.cos(theta);
|
||||
|
||||
float z = r * MathHelper.sin(theta);
|
||||
|
||||
builder.vertex(cx + 0, cy - y, cz + z).color(red, grn, blu, alpha).next();
|
||||
builder.vertex(cx + 0, cy + y, cz - z).color(red, grn, blu, alpha).next();
|
||||
builder.vertex(cx + h, cy + y, cz - z).color(red, grn, blu, alpha).next();
|
||||
builder.vertex(cx + h, cy - y, cz + z).color(red, grn, blu, alpha).next();
|
||||
tessellator.draw();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR);
|
||||
for (int i = 0; i <= num_steps180; i++)
|
||||
{
|
||||
float theta = step * i;
|
||||
float y = r * MathHelper.cos(theta);
|
||||
float z = r * MathHelper.sin(theta);
|
||||
builder.vertex(cx, cy - y, cz + z).color(red, grn, blu, alpha).next();
|
||||
builder.vertex(cx, cy + y, cz - z).color(red, grn, blu, alpha).next();
|
||||
}
|
||||
tessellator.draw();
|
||||
}
|
||||
}
|
||||
else if (axis == Direction.Axis.Z)
|
||||
{
|
||||
for (int dh = 0; dh < hsteps; dh++)
|
||||
{
|
||||
float hh = dh * hstep;
|
||||
builder.begin(GL11.GL_LINE_LOOP, VertexFormats.POSITION_COLOR);
|
||||
for (int i = 0; i <= num_steps360; i++)
|
||||
{
|
||||
float theta = step * i;
|
||||
float y = r * MathHelper.cos(theta);
|
||||
float z = hh;
|
||||
float x = r * MathHelper.sin(theta);
|
||||
builder.vertex(x + cx, y + cy, z + cz).color(red, grn, blu, alpha).next();
|
||||
}
|
||||
tessellator.draw();
|
||||
}
|
||||
if (!isFlat)
|
||||
{
|
||||
for (int i = 0; i <= num_steps180; i++)
|
||||
{
|
||||
builder.begin(GL11.GL_LINE_LOOP, VertexFormats.POSITION_COLOR);
|
||||
float theta = step * i;
|
||||
float x = r * MathHelper.cos(theta);
|
||||
|
||||
float y = r * MathHelper.sin(theta);
|
||||
|
||||
builder.vertex(cx + x, cy - y, cz + 0).color(red, grn, blu, alpha).next();
|
||||
builder.vertex(cx - x, cy + y, cz + 0).color(red, grn, blu, alpha).next();
|
||||
builder.vertex(cx - x, cy + y, cz + h).color(red, grn, blu, alpha).next();
|
||||
builder.vertex(cx + x, cy - y, cz + h).color(red, grn, blu, alpha).next();
|
||||
tessellator.draw();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR);
|
||||
for (int i = 0; i <= num_steps180; i++)
|
||||
{
|
||||
float theta = step * i;
|
||||
float x = r * MathHelper.cos(theta);
|
||||
float y = r * MathHelper.sin(theta);
|
||||
builder.vertex(cx + x, cy - y, cz).color(red, grn, blu, alpha).next();
|
||||
builder.vertex(cx - x, cy + y, cz).color(red, grn, blu, alpha).next();
|
||||
}
|
||||
tessellator.draw();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawCylinderFaces(Tessellator tessellator, BufferBuilder builder,
|
||||
float cx, float cy, float cz,
|
||||
float r, float h, Direction.Axis axis, int subd, boolean isFlat,
|
||||
float red, float grn, float blu, float alpha)
|
||||
{
|
||||
float step = (float)Math.PI / (subd/2);
|
||||
int num_steps180 = (int)(Math.PI / step)+1;
|
||||
int num_steps360 = (int)(2*Math.PI / step)+1;
|
||||
|
||||
if (axis == Direction.Axis.Y)
|
||||
{
|
||||
|
||||
builder.begin(GL11.GL_TRIANGLE_FAN, VertexFormats.POSITION_COLOR);
|
||||
builder.vertex(cx, cy, cz).color(red, grn, blu, alpha).next();
|
||||
for (int i = 0; i <= num_steps360; i++)
|
||||
{
|
||||
float theta = step * i;
|
||||
float x = r * MathHelper.cos(theta);
|
||||
float z = r * MathHelper.sin(theta);
|
||||
builder.vertex(x + cx, cy, z + cz).color(red, grn, blu, alpha).next();
|
||||
}
|
||||
tessellator.draw();
|
||||
if (!isFlat)
|
||||
{
|
||||
builder.begin(GL11.GL_TRIANGLE_FAN, VertexFormats.POSITION_COLOR);
|
||||
builder.vertex(cx, cy+h, cz).color(red, grn, blu, alpha).next();
|
||||
for (int i = 0; i <= num_steps360; i++)
|
||||
{
|
||||
float theta = step * i;
|
||||
float x = r * MathHelper.cos(theta);
|
||||
float z = r * MathHelper.sin(theta);
|
||||
builder.vertex(x + cx, cy+h, z + cz).color(red, grn, blu, alpha).next();
|
||||
}
|
||||
tessellator.draw();
|
||||
|
||||
builder.begin(GL11.GL_QUAD_STRIP, VertexFormats.POSITION_COLOR);
|
||||
for (int i = 0; i <= num_steps360; i++)
|
||||
{
|
||||
float theta = step * i;
|
||||
float x = r * MathHelper.cos(theta);
|
||||
float z = r * MathHelper.sin(theta);
|
||||
builder.vertex(cx + x, cy + 0, cz + z).color(red, grn, blu, alpha).next();
|
||||
builder.vertex(cx + x, cy + h, cz + z).color(red, grn, blu, alpha).next();
|
||||
}
|
||||
tessellator.draw();
|
||||
}
|
||||
|
||||
}
|
||||
else if (axis == Direction.Axis.X)
|
||||
{
|
||||
builder.begin(GL11.GL_TRIANGLE_FAN, VertexFormats.POSITION_COLOR);
|
||||
builder.vertex(cx, cy, cz).color(red, grn, blu, alpha).next();
|
||||
for (int i = 0; i <= num_steps360; i++)
|
||||
{
|
||||
float theta = step * i;
|
||||
float y = r * MathHelper.cos(theta);
|
||||
float z = r * MathHelper.sin(theta);
|
||||
builder.vertex(cx, cy + y, z + cz).color(red, grn, blu, alpha).next();
|
||||
}
|
||||
tessellator.draw();
|
||||
if (!isFlat)
|
||||
{
|
||||
builder.begin(GL11.GL_TRIANGLE_FAN, VertexFormats.POSITION_COLOR);
|
||||
builder.vertex(cx+h, cy, cz).color(red, grn, blu, alpha).next();
|
||||
for (int i = 0; i <= num_steps360; i++)
|
||||
{
|
||||
float theta = step * i;
|
||||
float y = r * MathHelper.cos(theta);
|
||||
float z = r * MathHelper.sin(theta);
|
||||
builder.vertex(cx+h, cy + y, cz + z).color(red, grn, blu, alpha).next();
|
||||
}
|
||||
tessellator.draw();
|
||||
|
||||
builder.begin(GL11.GL_QUAD_STRIP, VertexFormats.POSITION_COLOR);
|
||||
for (int i = 0; i <= num_steps360; i++)
|
||||
{
|
||||
float theta = step * i;
|
||||
float y = r * MathHelper.cos(theta);
|
||||
float z = r * MathHelper.sin(theta);
|
||||
builder.vertex(cx + 0, cy + y, cz + z).color(red, grn, blu, alpha).next();
|
||||
builder.vertex(cx + h, cy + y, cz + z).color(red, grn, blu, alpha).next();
|
||||
}
|
||||
tessellator.draw();
|
||||
}
|
||||
}
|
||||
else if (axis == Direction.Axis.Z)
|
||||
{
|
||||
builder.begin(GL11.GL_TRIANGLE_FAN, VertexFormats.POSITION_COLOR);
|
||||
builder.vertex(cx, cy, cz).color(red, grn, blu, alpha).next();
|
||||
for (int i = 0; i <= num_steps360; i++)
|
||||
{
|
||||
float theta = step * i;
|
||||
float x = r * MathHelper.cos(theta);
|
||||
float y = r * MathHelper.sin(theta);
|
||||
builder.vertex(x + cx, cy+y, cz).color(red, grn, blu, alpha).next();
|
||||
}
|
||||
tessellator.draw();
|
||||
if (!isFlat)
|
||||
{
|
||||
builder.begin(GL11.GL_TRIANGLE_FAN, VertexFormats.POSITION_COLOR);
|
||||
builder.vertex(cx, cy, cz+h).color(red, grn, blu, alpha).next();
|
||||
for (int i = 0; i <= num_steps360; i++)
|
||||
{
|
||||
float theta = step * i;
|
||||
float x = r * MathHelper.cos(theta);
|
||||
float y = r * MathHelper.sin(theta);
|
||||
builder.vertex(x + cx, cy+y, cz+h).color(red, grn, blu, alpha).next();
|
||||
}
|
||||
tessellator.draw();
|
||||
|
||||
builder.begin(GL11.GL_QUAD_STRIP, VertexFormats.POSITION_COLOR);
|
||||
for (int i = 0; i <= num_steps360; i++)
|
||||
{
|
||||
float theta = step * i;
|
||||
float x = r * MathHelper.cos(theta);
|
||||
float y = r * MathHelper.sin(theta);
|
||||
builder.vertex(cx + x, cy + y, cz + 0).color(red, grn, blu, alpha).next();
|
||||
builder.vertex(cx + x, cy + y, cz + h).color(red, grn, blu, alpha).next();
|
||||
}
|
||||
tessellator.draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawSphereWireframe(Tessellator tessellator, BufferBuilder builder,
|
||||
float cx, float cy, float cz,
|
||||
float r, int subd,
|
||||
float red, float grn, float blu, float alpha)
|
||||
{
|
||||
float step = (float)Math.PI / (subd/2);
|
||||
int num_steps180 = (int)(Math.PI / step)+1;
|
||||
int num_steps360 = (int)(2*Math.PI / step);
|
||||
for (int i = 0; i <= num_steps360; i++)
|
||||
{
|
||||
builder.begin(GL11.GL_LINE_STRIP, VertexFormats.POSITION_COLOR);
|
||||
float theta = step * i ;
|
||||
for (int j = 0; j <= num_steps180; j++)
|
||||
{
|
||||
float phi = step * j ;
|
||||
float x = r * MathHelper.sin(phi) * MathHelper.cos(theta);
|
||||
float z = r * MathHelper.sin(phi) * MathHelper.sin(theta);
|
||||
float y = r * MathHelper.cos(phi);
|
||||
builder.vertex(x+cx, y+cy, z+cz).color(red, grn, blu, alpha).next();
|
||||
}
|
||||
tessellator.draw();
|
||||
}
|
||||
for (int j = 0; j <= num_steps180; j++)
|
||||
{
|
||||
builder.begin(GL11.GL_LINE_LOOP, VertexFormats.POSITION_COLOR);
|
||||
float phi = step * j ;
|
||||
|
||||
for (int i = 0; i <= num_steps360; i++)
|
||||
{
|
||||
float theta = step * i;
|
||||
float x = r * MathHelper.sin(phi) * MathHelper.cos(theta);
|
||||
float z = r * MathHelper.sin(phi) * MathHelper.sin(theta);
|
||||
float y = r * MathHelper.cos(phi);
|
||||
builder.vertex(x+cx, y+cy, z+cz).color(red, grn, blu, alpha).next();
|
||||
}
|
||||
tessellator.draw();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void drawSphereFaces(Tessellator tessellator, BufferBuilder builder,
|
||||
float cx, float cy, float cz,
|
||||
float r, int subd,
|
||||
float red, float grn, float blu, float alpha)
|
||||
{
|
||||
|
||||
float step = (float)Math.PI / (subd/2);
|
||||
int num_steps180 = (int)(Math.PI / step)+1;
|
||||
int num_steps360 = (int)(2*Math.PI / step);
|
||||
for (int i = 0; i <= num_steps360; i++)
|
||||
{
|
||||
float theta = i * step;
|
||||
float thetaprime = theta+step;
|
||||
builder.begin(GL11.GL_QUAD_STRIP, VertexFormats.POSITION_COLOR);
|
||||
for (int j = 0; j <= num_steps180; j++)
|
||||
{
|
||||
float phi = j * step;
|
||||
float x = r * MathHelper.sin(phi) * MathHelper.cos(theta);
|
||||
float z = r * MathHelper.sin(phi) * MathHelper.sin(theta);
|
||||
float y = r * MathHelper.cos(phi);
|
||||
float xp = r * MathHelper.sin(phi) * MathHelper.cos(thetaprime);
|
||||
float zp = r * MathHelper.sin(phi) * MathHelper.sin(thetaprime);
|
||||
builder.vertex(x + cx, y + cy, z + cz).color(red, grn, blu, alpha).next();
|
||||
builder.vertex(xp + cx, y + cy, zp + cz).color(red, grn, blu, alpha).next();
|
||||
}
|
||||
tessellator.draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,172 +72,11 @@ public class BlockValue extends Value
|
||||
throw new InternalExpressionException("Cannot parse block: "+str);
|
||||
}
|
||||
|
||||
public static VectorLocator locateVec(CarpetContext c, List<LazyValue> params, int offset)
|
||||
{
|
||||
return locateVec(c,params, offset, false);
|
||||
}
|
||||
public static VectorLocator locateVec(CarpetContext c, List<LazyValue> params, int offset, boolean optionalDirection)
|
||||
{
|
||||
try
|
||||
{
|
||||
Value v1 = params.get(0 + offset).evalValue(c);
|
||||
if (v1 instanceof BlockValue)
|
||||
{
|
||||
return (new VectorLocator(new Vec3d(((BlockValue) v1).getPos()).add(0.5,0.5,0.5), 1+offset)).fromBlock();
|
||||
}
|
||||
if (v1 instanceof ListValue)
|
||||
{
|
||||
List<Value> args = ((ListValue) v1).getItems();
|
||||
Vec3d pos = new Vec3d(
|
||||
NumericValue.asNumber(args.get(0)).getDouble(),
|
||||
NumericValue.asNumber(args.get(1)).getDouble(),
|
||||
NumericValue.asNumber(args.get(2)).getDouble());
|
||||
double yaw = 0.0D;
|
||||
double pitch = 0.0D;
|
||||
if (args.size()>3 && optionalDirection)
|
||||
{
|
||||
yaw = NumericValue.asNumber(args.get(3)).getDouble();
|
||||
pitch = NumericValue.asNumber(args.get(4)).getDouble();
|
||||
}
|
||||
return new VectorLocator(pos,offset+1, yaw, pitch);
|
||||
}
|
||||
Vec3d pos = new Vec3d(
|
||||
NumericValue.asNumber(v1).getDouble(),
|
||||
NumericValue.asNumber(params.get(1 + offset).evalValue(c)).getDouble(),
|
||||
NumericValue.asNumber(params.get(2 + offset).evalValue(c)).getDouble());
|
||||
double yaw = 0.0D;
|
||||
double pitch = 0.0D;
|
||||
int eatenLength = 3;
|
||||
if (params.size()>3+offset && optionalDirection)
|
||||
{
|
||||
yaw = NumericValue.asNumber(params.get(3 + offset).evalValue(c)).getDouble();
|
||||
pitch = NumericValue.asNumber(params.get(4 + offset).evalValue(c)).getDouble();
|
||||
eatenLength = 5;
|
||||
}
|
||||
|
||||
return new VectorLocator(pos,offset+eatenLength, yaw, pitch);
|
||||
}
|
||||
catch (IndexOutOfBoundsException e)
|
||||
{
|
||||
throw new InternalExpressionException("Position should be defined either by three coordinates, or a block value");
|
||||
}
|
||||
}
|
||||
|
||||
public static BlockPos locateBlockPos(CarpetContext c, int xpos, int ypos, int zpos)
|
||||
{
|
||||
return new BlockPos(c.origin.getX() + xpos, c.origin.getY() + ypos, c.origin.getZ() + zpos);
|
||||
}
|
||||
|
||||
public static LocatorResult fromParams(CarpetContext c, List<LazyValue> params, int offset)
|
||||
{
|
||||
return fromParams(c, params,offset, false, false);
|
||||
}
|
||||
|
||||
public static LocatorResult fromParams(CarpetContext c, List<LazyValue> params, int offset, boolean acceptString)
|
||||
{
|
||||
return fromParams(c, params,offset, acceptString, false);
|
||||
}
|
||||
|
||||
public static LocatorResult fromParams(CarpetContext c, List<LazyValue> params, int offset, boolean acceptString, boolean optional)
|
||||
{
|
||||
try
|
||||
{
|
||||
Value v1 = params.get(0 + offset).evalValue(c);
|
||||
//add conditional from string name
|
||||
if (optional && v1 instanceof NullValue)
|
||||
{
|
||||
return new LocatorResult(null, 1+offset);
|
||||
}
|
||||
if (acceptString && v1 instanceof StringValue)
|
||||
{
|
||||
return new LocatorResult(fromString(v1.getString()), 1+offset);
|
||||
}
|
||||
if (v1 instanceof BlockValue)
|
||||
{
|
||||
return new LocatorResult(((BlockValue) v1), 1+offset);
|
||||
}
|
||||
if (v1 instanceof ListValue)
|
||||
{
|
||||
List<Value> args = ((ListValue) v1).getItems();
|
||||
int xpos = (int) NumericValue.asNumber(args.get(0)).getLong();
|
||||
int ypos = (int) NumericValue.asNumber(args.get(1)).getLong();
|
||||
int zpos = (int) NumericValue.asNumber(args.get(2)).getLong();
|
||||
return new LocatorResult(
|
||||
new BlockValue(
|
||||
null,
|
||||
c.s.getWorld(),
|
||||
new BlockPos(c.origin.getX() + xpos, c.origin.getY() + ypos, c.origin.getZ() + zpos)
|
||||
),
|
||||
1+offset);
|
||||
}
|
||||
int xpos = (int) NumericValue.asNumber(v1).getLong();
|
||||
int ypos = (int) NumericValue.asNumber( params.get(1 + offset).evalValue(c)).getLong();
|
||||
int zpos = (int) NumericValue.asNumber( params.get(2 + offset).evalValue(c)).getLong();
|
||||
return new LocatorResult(
|
||||
new BlockValue(
|
||||
null,
|
||||
c.s.getWorld(),
|
||||
new BlockPos(c.origin.getX() + xpos, c.origin.getY() + ypos, c.origin.getZ() + zpos)
|
||||
),
|
||||
3+offset
|
||||
);
|
||||
}
|
||||
catch (IndexOutOfBoundsException e)
|
||||
{
|
||||
throw new InternalExpressionException("Block should be defined either by three coordinates, a block value, or a proper string");
|
||||
}
|
||||
}
|
||||
|
||||
public static LocatorResult fromParamValues(CarpetContext c, List<Value> params, int offset, boolean acceptString, boolean optional)
|
||||
{
|
||||
try
|
||||
{
|
||||
Value v1 = params.get(0 + offset);
|
||||
//add conditional from string name
|
||||
if (optional && v1 instanceof NullValue)
|
||||
{
|
||||
return new LocatorResult(null, 1+offset);
|
||||
}
|
||||
if (acceptString && v1 instanceof StringValue)
|
||||
{
|
||||
return new LocatorResult(fromString(v1.getString()), 1+offset);
|
||||
}
|
||||
if (v1 instanceof BlockValue)
|
||||
{
|
||||
return new LocatorResult(((BlockValue) v1), 1+offset);
|
||||
}
|
||||
if (v1 instanceof ListValue)
|
||||
{
|
||||
List<Value> args = ((ListValue) v1).getItems();
|
||||
int xpos = (int) NumericValue.asNumber(args.get(0)).getLong();
|
||||
int ypos = (int) NumericValue.asNumber(args.get(1)).getLong();
|
||||
int zpos = (int) NumericValue.asNumber(args.get(2)).getLong();
|
||||
return new LocatorResult(
|
||||
new BlockValue(
|
||||
null,
|
||||
c.s.getWorld(),
|
||||
new BlockPos(c.origin.getX() + xpos, c.origin.getY() + ypos, c.origin.getZ() + zpos)
|
||||
),
|
||||
1+offset);
|
||||
}
|
||||
int xpos = (int) NumericValue.asNumber(v1).getLong();
|
||||
int ypos = (int) NumericValue.asNumber( params.get(1 + offset)).getLong();
|
||||
int zpos = (int) NumericValue.asNumber( params.get(2 + offset)).getLong();
|
||||
return new LocatorResult(
|
||||
new BlockValue(
|
||||
null,
|
||||
c.s.getWorld(),
|
||||
new BlockPos(c.origin.getX() + xpos, c.origin.getY() + ypos, c.origin.getZ() + zpos)
|
||||
),
|
||||
3+offset
|
||||
);
|
||||
}
|
||||
catch (IndexOutOfBoundsException e)
|
||||
{
|
||||
throw new InternalExpressionException("Block should be defined either by three coordinates, a block value, or a proper string");
|
||||
}
|
||||
}
|
||||
|
||||
public BlockState getBlockState()
|
||||
{
|
||||
if (blockState != null)
|
||||
@@ -342,46 +181,6 @@ public class BlockValue extends Value
|
||||
public ServerWorld getWorld() { return world;}
|
||||
|
||||
|
||||
public static class LocatorResult
|
||||
{
|
||||
public final BlockValue block;
|
||||
public final int offset;
|
||||
LocatorResult(BlockValue b, int o)
|
||||
{
|
||||
block = b;
|
||||
offset = o;
|
||||
}
|
||||
}
|
||||
|
||||
public static class VectorLocator
|
||||
{
|
||||
public Vec3d vec;
|
||||
public final int offset;
|
||||
public final double yaw;
|
||||
public final double pitch;
|
||||
public boolean fromBlock;
|
||||
VectorLocator(Vec3d v, int o)
|
||||
{
|
||||
vec = v;
|
||||
offset = o;
|
||||
yaw = 0.0D;
|
||||
pitch = 0.0D;
|
||||
}
|
||||
VectorLocator(Vec3d v, int o, double y, double p)
|
||||
{
|
||||
vec = v;
|
||||
offset = o;
|
||||
yaw = y;
|
||||
pitch = p;
|
||||
}
|
||||
|
||||
public VectorLocator fromBlock()
|
||||
{
|
||||
fromBlock = true;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public enum SpecificDirection {
|
||||
UP("up",0.5, 0.0, 0.5, Direction.UP),
|
||||
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
package carpet.script.value;
|
||||
|
||||
import carpet.CarpetSettings;
|
||||
import carpet.fakes.EntityInterface;
|
||||
import carpet.fakes.ItemEntityInterface;
|
||||
import carpet.fakes.LivingEntityInterface;
|
||||
import carpet.fakes.MobEntityInterface;
|
||||
import carpet.fakes.HungerManagerInterface;
|
||||
import carpet.helpers.Tracer;
|
||||
import carpet.patches.EntityPlayerMPFake;
|
||||
import carpet.script.CarpetContext;
|
||||
import carpet.script.EntityEventsGroup;
|
||||
import carpet.script.argument.Vector3Argument;
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
import carpet.utils.Messenger;
|
||||
import com.mojang.brigadier.StringReader;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import net.minecraft.entity.player.HungerManager;
|
||||
import net.minecraft.network.packet.s2c.play.EntityPassengersSetS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.EntityPositionS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket;
|
||||
@@ -45,6 +51,7 @@ import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.world.GameMode;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -60,6 +67,7 @@ import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static carpet.script.value.NBTSerializableValue.nameFromRegistryId;
|
||||
import static carpet.utils.MobAI.genericJump;
|
||||
|
||||
// TODO: decide whether copy(entity) should duplicate entity in the world.
|
||||
public class EntityValue extends Value
|
||||
@@ -118,7 +126,7 @@ public class EntityValue extends Value
|
||||
@Override
|
||||
public String getString()
|
||||
{
|
||||
return entity.getDisplayName().getString();
|
||||
return entity.getName().getString();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -220,7 +228,9 @@ public class EntityValue extends Value
|
||||
put("motion_x", (e, a) -> new NumericValue(e.getVelocity().x));
|
||||
put("motion_y", (e, a) -> new NumericValue(e.getVelocity().y));
|
||||
put("motion_z", (e, a) -> new NumericValue(e.getVelocity().z));
|
||||
put("name", (e, a) -> new StringValue(e.getDisplayName().getString()));
|
||||
put("name", (e, a) -> new StringValue(e.getName().getString()));
|
||||
put("display_name", (e, a) -> new StringValue(e.getDisplayName().getString()));
|
||||
put("command_name", (e, a) -> new StringValue(e.getEntityName()));
|
||||
put("custom_name", (e, a) -> e.hasCustomName()?new StringValue(e.getCustomName().getString()):Value.NULL);
|
||||
put("type", (e, a) -> new StringValue(nameFromRegistryId(Registry.ENTITY_TYPE.getId(e.getType()))));
|
||||
put("is_riding", (e, a) -> new NumericValue(e.hasVehicle()));
|
||||
@@ -252,7 +262,9 @@ public class EntityValue extends Value
|
||||
put("despawn_timer", (e, a) -> e instanceof LivingEntity?new NumericValue(((LivingEntity) e).getDespawnCounter()):Value.NULL);
|
||||
put("item", (e, a) -> (e instanceof ItemEntity)?ListValue.fromItemStack(((ItemEntity) e).getStack()):Value.NULL);
|
||||
put("count", (e, a) -> (e instanceof ItemEntity)?new NumericValue(((ItemEntity) e).getStack().getCount()):Value.NULL);
|
||||
put("pickup_delay", (e, a) -> (e instanceof ItemEntity)?new NumericValue(((ItemEntityInterface) e).getPickupDelay()):Value.NULL);
|
||||
put("pickup_delay", (e, a) -> (e instanceof ItemEntity)?new NumericValue(((ItemEntityInterface) e).getPickupDelayCM()):Value.NULL);
|
||||
put("portal_cooldown", (e , a) ->new NumericValue(((EntityInterface)e).getPortalTimer()));
|
||||
put("portal_timer", (e , a) ->new NumericValue(e.netherPortalCooldown));
|
||||
// ItemEntity -> despawn timer via ssGetAge
|
||||
put("is_baby", (e, a) -> (e instanceof LivingEntity)?new NumericValue(((LivingEntity) e).isBaby()):Value.NULL);
|
||||
put("target", (e, a) -> {
|
||||
@@ -277,13 +289,27 @@ public class EntityValue extends Value
|
||||
put("sneaking", (e, a) -> e.isSneaking()?Value.TRUE:Value.FALSE);
|
||||
put("sprinting", (e, a) -> e.isSprinting()?Value.TRUE:Value.FALSE);
|
||||
put("swimming", (e, a) -> e.isSwimming()?Value.TRUE:Value.FALSE);
|
||||
/*put("jumping", (e, a) -> {
|
||||
put("hunger", (e, a) -> {
|
||||
if(e instanceof PlayerEntity) return new NumericValue(((PlayerEntity) e).getHungerManager().getFoodLevel());
|
||||
return Value.NULL;
|
||||
});
|
||||
put("saturation", (e, a) -> {
|
||||
if(e instanceof PlayerEntity) return new NumericValue(((PlayerEntity) e).getHungerManager().getSaturationLevel());
|
||||
return Value.NULL;
|
||||
});
|
||||
|
||||
put("exhaustion",(e, a)->{
|
||||
if(e instanceof PlayerEntity) return new NumericValue(((HungerManagerInterface)((PlayerEntity) e).getHungerManager()).getExhaustionCM());
|
||||
return Value.NULL;
|
||||
});
|
||||
|
||||
put("jumping", (e, a) -> {
|
||||
if (e instanceof LivingEntity)
|
||||
{
|
||||
return ((LivingEntity) e).getJumping()?Value.TRUE:Value.FALSE;
|
||||
return ((LivingEntityInterface) e).isJumpingCM()?Value.TRUE:Value.FALSE;
|
||||
}
|
||||
return Value.NULL;
|
||||
});*/ //needs mixing
|
||||
});
|
||||
put("gamemode", (e, a) -> {
|
||||
if (e instanceof ServerPlayerEntity)
|
||||
{
|
||||
@@ -331,6 +357,8 @@ public class EntityValue extends Value
|
||||
return Value.NULL;
|
||||
});
|
||||
|
||||
put("team", (e, a) -> e.getScoreboardTeam()==null?Value.NULL:new StringValue(e.getScoreboardTeam().getName()));
|
||||
|
||||
put("ping", (e, a) -> {
|
||||
if (e instanceof ServerPlayerEntity)
|
||||
{
|
||||
@@ -370,6 +398,7 @@ public class EntityValue extends Value
|
||||
StatusEffectInstance pe = ((LivingEntity) e).getStatusEffect(potion);
|
||||
return ListValue.of( new NumericValue(pe.getAmplifier()), new NumericValue(pe.getDuration()) );
|
||||
});
|
||||
|
||||
put("health", (e, a) ->
|
||||
{
|
||||
if (e instanceof LivingEntity)
|
||||
@@ -475,6 +504,8 @@ public class EntityValue extends Value
|
||||
return new NBTSerializableValue(nbttagcompound);
|
||||
return new NBTSerializableValue(nbttagcompound).get(a);
|
||||
});
|
||||
|
||||
put("category",(e,a)->{return new StringValue(e.getType().getCategory().toString().toLowerCase(Locale.ROOT));});
|
||||
}};
|
||||
|
||||
public void set(String what, Value toWhat)
|
||||
@@ -523,12 +554,40 @@ public class EntityValue extends Value
|
||||
//((ServerWorld)e.getEntityWorld()).method_14178().sendToNearbyPlayers(e, new EntityVelocityUpdateS2CPacket(e));
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static final Map<String, BiConsumer<Entity, Value>> featureModifiers = new HashMap<String, BiConsumer<Entity, Value>>() {{
|
||||
put("remove", (entity, value) -> entity.remove());
|
||||
put("age", (e, v) -> e.age = Math.abs((int)NumericValue.asNumber(v).getLong()) );
|
||||
put("health", (e, v) -> { if (e instanceof LivingEntity) ((LivingEntity) e).setHealth((float) NumericValue.asNumber(v).getDouble()); });
|
||||
put("health", (e, v) -> {
|
||||
float health = (float) NumericValue.asNumber(v).getDouble();
|
||||
if (health <= 0f && e instanceof ServerPlayerEntity)
|
||||
{
|
||||
ServerPlayerEntity player = (ServerPlayerEntity) e;
|
||||
if (player.container != null)
|
||||
{
|
||||
// if player dies with open container, then that causes NPE on the client side
|
||||
// its a client side bug that may never surface unless vanilla gets into scripting at some point
|
||||
// bug: #228
|
||||
player.closeContainer();
|
||||
}
|
||||
((LivingEntity) e).setHealth(health);
|
||||
}
|
||||
if (e instanceof LivingEntity) ((LivingEntity) e).setHealth(health);
|
||||
});
|
||||
// todo add handling of the source for extra effects
|
||||
/*put("damage", (e, v) -> {
|
||||
float dmgPoints;
|
||||
DamageSource source;
|
||||
if (v instanceof ListValue && ((ListValue) v).getItems().size() > 1)
|
||||
{
|
||||
List<Value> vals = ((ListValue) v).getItems();
|
||||
dmgPoints = (float) NumericValue.asNumber(v).getDouble();
|
||||
source = DamageSource ... yeah...
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
});*/
|
||||
put("kill", (e, v) -> e.kill());
|
||||
put("location", (e, v) ->
|
||||
{
|
||||
@@ -751,26 +810,12 @@ public class EntityValue extends Value
|
||||
else if (v instanceof ListValue)
|
||||
{
|
||||
List<Value> lv = ((ListValue) v).getItems();
|
||||
if (lv.get(0) instanceof BlockValue)
|
||||
Vector3Argument locator = Vector3Argument.findIn(lv, 0, false);
|
||||
pos = new BlockPos(locator.vec.x, locator.vec.y, locator.vec.z);
|
||||
if (lv.size() > locator.offset)
|
||||
{
|
||||
pos = ((BlockValue) lv.get(0)).getPos();
|
||||
if (lv.size()>1)
|
||||
{
|
||||
distance = (int) NumericValue.asNumber(lv.get(1)).getLong();
|
||||
}
|
||||
distance = (int) NumericValue.asNumber(lv.get(locator.offset)).getLong();
|
||||
}
|
||||
else if (lv.size()>=3)
|
||||
{
|
||||
pos = new BlockPos(NumericValue.asNumber(lv.get(0)).getLong(),
|
||||
NumericValue.asNumber(lv.get(1)).getLong(),
|
||||
NumericValue.asNumber(lv.get(2)).getLong());
|
||||
if (lv.size()>3)
|
||||
{
|
||||
distance = (int) NumericValue.asNumber(lv.get(4)).getLong();
|
||||
}
|
||||
}
|
||||
else throw new InternalExpressionException("'home' requires at least one position argument, and optional distance");
|
||||
|
||||
}
|
||||
else throw new InternalExpressionException("'home' requires at least one position argument, and optional distance");
|
||||
|
||||
@@ -800,6 +845,20 @@ public class EntityValue extends Value
|
||||
}
|
||||
});
|
||||
|
||||
put("portal_cooldown", (e , v) ->
|
||||
{
|
||||
if (v==null)
|
||||
throw new InternalExpressionException("'portal_cooldown' requires a value to set");
|
||||
e.netherPortalCooldown = NumericValue.asNumber(v).getInt();
|
||||
});
|
||||
|
||||
put("portal_timer", (e , v) ->
|
||||
{
|
||||
if (v==null)
|
||||
throw new InternalExpressionException("'portal_timer' requires a value to set");
|
||||
((EntityInterface) e).setPortalTimer(NumericValue.asNumber(v).getInt());
|
||||
});
|
||||
|
||||
put("ai", (e, v) ->
|
||||
{
|
||||
if (e instanceof MobEntity)
|
||||
@@ -820,7 +879,10 @@ public class EntityValue extends Value
|
||||
if (!(e instanceof LivingEntity)) return;
|
||||
LivingEntity le = (LivingEntity)e;
|
||||
if (v == null)
|
||||
{
|
||||
le.clearStatusEffects();
|
||||
return;
|
||||
}
|
||||
else if (v instanceof ListValue)
|
||||
{
|
||||
List<Value> lv = ((ListValue) v).getItems();
|
||||
@@ -840,7 +902,7 @@ public class EntityValue extends Value
|
||||
{
|
||||
le.removeStatusEffect(effect);
|
||||
return;
|
||||
}
|
||||
}
|
||||
int amplifier = 0;
|
||||
if (lv.size() > 2)
|
||||
amplifier = (int)NumericValue.asNumber(lv.get(2)).getLong();
|
||||
@@ -854,24 +916,81 @@ public class EntityValue extends Value
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
String effectName = v.getString();
|
||||
StatusEffect effect = Registry.STATUS_EFFECT.get(new Identifier(effectName));
|
||||
if (effect == null)
|
||||
throw new InternalExpressionException("Wrong effect name: "+effectName);
|
||||
le.removeStatusEffect(effect);
|
||||
return;
|
||||
}
|
||||
throw new InternalExpressionException("'effect' needs either no arguments (clear) or effect name, duration, and optional amplifier, show particles and show icon");
|
||||
});
|
||||
|
||||
// gamemode
|
||||
// spectate
|
||||
// "fire"
|
||||
// "extinguish"
|
||||
// "silent"
|
||||
// "gravity"
|
||||
// "invulnerable"
|
||||
// "dimension"
|
||||
// "item"
|
||||
// "count",
|
||||
// "age",
|
||||
// "effect_"name
|
||||
// "hold"
|
||||
// "hold_offhand"
|
||||
// "jump"
|
||||
put("gamemode", (e,v)->{
|
||||
if(!(e instanceof ServerPlayerEntity)) return;
|
||||
GameMode toSet = v instanceof NumericValue ?
|
||||
GameMode.byId(((NumericValue) v).getInt(), null) :
|
||||
GameMode.byName(v.getString().toLowerCase(Locale.ROOT), null);
|
||||
if (toSet != null) ((ServerPlayerEntity) e).setGameMode(toSet);
|
||||
});
|
||||
|
||||
put("jumping",(e,v)->{
|
||||
if(!(e instanceof LivingEntity)) return;
|
||||
((LivingEntity) e).setJumping(v.getBoolean());
|
||||
});
|
||||
|
||||
put("jump",(e,v)->{
|
||||
if (e instanceof LivingEntity)
|
||||
{
|
||||
((LivingEntityInterface)e).doJumpCM();
|
||||
}
|
||||
else
|
||||
{
|
||||
genericJump(e);
|
||||
}
|
||||
});
|
||||
|
||||
put("silent",(e,v)-> e.setSilent(v.getBoolean()));
|
||||
|
||||
put("gravity",(e,v)-> e.setNoGravity(!v.getBoolean()));
|
||||
|
||||
put("invulnerable",(e,v)-> e.setInvulnerable(v.getBoolean()));
|
||||
|
||||
put("fire",(e,v)-> e.setFireTicks((int)NumericValue.asNumber(v).getLong()));
|
||||
|
||||
put("hunger", (e, v)-> {
|
||||
if(e instanceof PlayerEntity) ((PlayerEntity) e).getHungerManager().setFoodLevel((int) NumericValue.asNumber(v).getLong());
|
||||
});
|
||||
|
||||
put("exhaustion", (e, v)-> {
|
||||
if(e instanceof PlayerEntity) ((HungerManagerInterface) ((PlayerEntity) e).getHungerManager()).setExhaustionCM(NumericValue.asNumber(v).getFloat());
|
||||
});
|
||||
|
||||
put("add_exhaustion", (e, v)-> {
|
||||
if(e instanceof PlayerEntity) ((PlayerEntity) e).getHungerManager().addExhaustion((int) NumericValue.asNumber(v).getLong());
|
||||
});
|
||||
|
||||
put("saturation", (e, v)-> {
|
||||
if(e instanceof PlayerEntity) ((PlayerEntity) e).getHungerManager().setSaturationLevelClient((float)NumericValue.asNumber(v).getLong());
|
||||
});
|
||||
|
||||
// gamemode [check]
|
||||
// spectate [check]
|
||||
// "fire" [check]
|
||||
// "extinguish" [set fire ticks to 0]
|
||||
// "silent" [check]
|
||||
// "gravity" [check]
|
||||
// "invulnerable" [check]
|
||||
// "dimension" []
|
||||
// "item" []
|
||||
// "count", []
|
||||
// "age", [check]
|
||||
// "effect_"name []
|
||||
// "hold" [inventory_set?]
|
||||
// "hold_offhand" [inventory_set?]
|
||||
// "jump" [check]
|
||||
// "nbt" <-big one, for now use run('data merge entity ...
|
||||
}};
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package carpet.script.value;
|
||||
|
||||
import net.minecraft.text.BaseText;
|
||||
|
||||
public class FormattedTextValue extends StringValue
|
||||
{
|
||||
BaseText text;
|
||||
public FormattedTextValue(BaseText text)
|
||||
{
|
||||
super(null);
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString() {
|
||||
return text.getString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean() {
|
||||
return text.getSiblings().size() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value clone()
|
||||
{
|
||||
return new FormattedTextValue(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeString()
|
||||
{
|
||||
return "text";
|
||||
}
|
||||
|
||||
public BaseText getText()
|
||||
{
|
||||
return text;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import carpet.script.Expression;
|
||||
import carpet.script.Fluff;
|
||||
import carpet.script.LazyValue;
|
||||
import carpet.script.Tokenizer;
|
||||
import carpet.script.bundled.Module;
|
||||
import carpet.script.exception.BreakStatement;
|
||||
import carpet.script.exception.ContinueStatement;
|
||||
import carpet.script.exception.ExitStatement;
|
||||
@@ -58,6 +59,8 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
||||
return name;
|
||||
}
|
||||
|
||||
public Module getModule() {return expression.module;}
|
||||
|
||||
@Override
|
||||
public String getPrettyString()
|
||||
{
|
||||
|
||||
@@ -48,7 +48,7 @@ public abstract class LazyListValue extends AbstractListValue implements Iterato
|
||||
@Override
|
||||
public String getString()
|
||||
{
|
||||
return String.format(Locale.ROOT, "[%d, %d, ..., %d]",start, start+stepp, limit);
|
||||
return String.format(Locale.ROOT, "[%d, %d, ..., %d)",start, start+stepp, limit);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -75,6 +75,18 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
|
||||
);
|
||||
}
|
||||
|
||||
public static Value fromTriple(double a, double b, double c)
|
||||
{
|
||||
return ListValue.of(new NumericValue(a), new NumericValue(b), new NumericValue(c));
|
||||
}
|
||||
|
||||
public static Value fromTriple(int a, int b, int c)
|
||||
{
|
||||
return fromTriple((double) a, b, c);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static ListValue wrap(List<Value> list)
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MapValue extends AbstractListValue implements ContainerValueInterface
|
||||
@@ -27,6 +28,15 @@ public class MapValue extends AbstractListValue implements ContainerValueInterfa
|
||||
}
|
||||
}
|
||||
|
||||
public MapValue(Set<Value> keySet)
|
||||
{
|
||||
this();
|
||||
for (Value v : keySet)
|
||||
{
|
||||
map.put(v, Value.NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Value> iterator()
|
||||
{
|
||||
|
||||
@@ -27,6 +27,7 @@ import net.minecraft.nbt.StringNbtReader;
|
||||
import net.minecraft.nbt.StringTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.predicate.entity.EntityPredicates;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
@@ -35,6 +36,7 @@ import net.minecraft.util.math.Box;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -201,16 +203,30 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
|
||||
return null;
|
||||
return new InventoryLocator(pos, pos, inv, offset + 1);
|
||||
}
|
||||
else if (v1.getString().equalsIgnoreCase("enderchest"))
|
||||
else if (v1 instanceof StringValue)
|
||||
{
|
||||
Value v2 = params.get(1 + offset).evalValue(c);
|
||||
if (!(v2 instanceof EntityValue) || !(((EntityValue) v2).getEntity() instanceof PlayerEntity))
|
||||
String strVal = v1.getString().toLowerCase(Locale.ROOT);
|
||||
if (strVal.equals("enderchest"))
|
||||
{
|
||||
throw new InternalExpressionException("enderchest inventory requires player argument");
|
||||
Value v2 = params.get(1 + offset).evalValue(c);
|
||||
ServerPlayerEntity player = EntityValue.getPlayerByValue(c.s.getMinecraftServer(), v2);
|
||||
if (player == null) throw new InternalExpressionException("enderchest inventory requires player argument");
|
||||
return new InventoryLocator(player, player.getBlockPos(), player.getEnderChestInventory(), offset + 2, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
boolean isEnder = strVal.startsWith("enderchest_");
|
||||
if (isEnder) strVal = strVal.substring(11); // len("enderchest_")
|
||||
ServerPlayerEntity player = c.s.getMinecraftServer().getPlayerManager().getPlayer(strVal);
|
||||
if (player == null) throw new InternalExpressionException("String description of an inventory should either denote a player or player's enderchest");
|
||||
return new InventoryLocator(
|
||||
player,
|
||||
player.getBlockPos(),
|
||||
isEnder ? player.getEnderChestInventory() : player.inventory,
|
||||
offset + 1,
|
||||
isEnder
|
||||
);
|
||||
}
|
||||
PlayerEntity e = (PlayerEntity)((EntityValue) v2).getEntity();
|
||||
inv = e.getEnderChestInventory();
|
||||
return new InventoryLocator(e, e.getBlockPos(), inv, offset + 2, true);
|
||||
}
|
||||
BlockPos pos = new BlockPos(
|
||||
NumericValue.asNumber(v1).getDouble(),
|
||||
|
||||
@@ -13,6 +13,13 @@ public class NumericValue extends Value
|
||||
private Double value;
|
||||
final static double epsilon = 1024*Double.MIN_VALUE;
|
||||
|
||||
public static NumericValue asNumber(Value v1, String id)
|
||||
{
|
||||
if (!(v1 instanceof NumericValue))
|
||||
throw new InternalExpressionException("Argument "+id+" has to be of a numeric type");
|
||||
return ((NumericValue) v1);
|
||||
}
|
||||
|
||||
public static NumericValue asNumber(Value v1)
|
||||
{
|
||||
if (!(v1 instanceof NumericValue))
|
||||
@@ -56,6 +63,10 @@ public class NumericValue extends Value
|
||||
{
|
||||
return value;
|
||||
}
|
||||
public float getFloat()
|
||||
{
|
||||
return value.floatValue();
|
||||
}
|
||||
|
||||
public static long floor(double double_1) {
|
||||
long int_1 = (long)double_1;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package carpet.settings;
|
||||
|
||||
import carpet.CarpetServer;
|
||||
import carpet.utils.Translations;
|
||||
import carpet.utils.Messenger;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
@@ -12,6 +13,8 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static carpet.utils.Translations.tr;
|
||||
|
||||
public final class ParsedRule<T> implements Comparable<ParsedRule> {
|
||||
public final Field field;
|
||||
public final String name;
|
||||
@@ -225,4 +228,33 @@ public final class ParsedRule<T> implements Comparable<ParsedRule> {
|
||||
{
|
||||
return this.name + ": " + getAsString();
|
||||
}
|
||||
|
||||
private String translationKey()
|
||||
{
|
||||
return String.format("rule.%s.name", name);
|
||||
}
|
||||
|
||||
public String translatedName(){
|
||||
String key = translationKey();
|
||||
return Translations.hasTranslation(key) ? tr(key) + String.format(" (%s)", name): name;
|
||||
}
|
||||
|
||||
public String translatedDescription()
|
||||
{
|
||||
return tr(String.format("rule.%s.desc", (name)), description);
|
||||
}
|
||||
|
||||
public List<String> translatedExtras()
|
||||
{
|
||||
if (!Translations.hasTranslations()) return extraInfo;
|
||||
String keyBase = String.format("rule.%s.extra.", name);
|
||||
List<String> extras = new ArrayList<>();
|
||||
int i = 0;
|
||||
while (Translations.hasTranslation(keyBase+i))
|
||||
{
|
||||
extras.add(Translations.tr(keyBase+i));
|
||||
i++;
|
||||
}
|
||||
return (extras.isEmpty()) ? extraInfo : extras;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package carpet.settings;
|
||||
|
||||
import carpet.CarpetServer;
|
||||
import carpet.CarpetSettings;
|
||||
import carpet.network.ServerNetworkHandler;
|
||||
import carpet.utils.Translations;
|
||||
import carpet.utils.Messenger;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Sets;
|
||||
@@ -39,6 +41,7 @@ import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static carpet.utils.Translations.tr;
|
||||
import static net.minecraft.server.command.CommandManager.argument;
|
||||
import static net.minecraft.server.command.CommandManager.literal;
|
||||
import static net.minecraft.server.command.CommandSource.suggestMatching;
|
||||
@@ -78,7 +81,7 @@ public class SettingsManager
|
||||
|
||||
public void detachServer()
|
||||
{
|
||||
for (ParsedRule<?> rule : rules.values()) rule.resetToDefault(server.getCommandSource());
|
||||
for (ParsedRule<?> rule : rules.values()) rule.resetToDefault(null);
|
||||
server = null;
|
||||
}
|
||||
|
||||
@@ -101,6 +104,7 @@ public class SettingsManager
|
||||
void notifyRuleChanged(ServerCommandSource source, ParsedRule<?> rule, String userTypedValue)
|
||||
{
|
||||
observers.forEach(observer -> observer.accept(source, rule, userTypedValue));
|
||||
ServerNetworkHandler.updateRuleWithConnectedClients(rule);
|
||||
}
|
||||
|
||||
public Iterable<String> getCategories()
|
||||
@@ -350,7 +354,7 @@ public class SettingsManager
|
||||
String ruleName = StringArgumentType.getString(ctx, "rule");
|
||||
ParsedRule<?> rule = getRule(ruleName);
|
||||
if (rule == null)
|
||||
throw new SimpleCommandExceptionType(Messenger.c("rb Unknown rule: "+ruleName)).create();
|
||||
throw new SimpleCommandExceptionType(Messenger.c("rb "+ tr("ui.unknown_rule","Unknown rule")+": "+ruleName)).create();
|
||||
return rule;
|
||||
}
|
||||
|
||||
@@ -358,26 +362,25 @@ public class SettingsManager
|
||||
{
|
||||
if (dispatcher.getRoot().getChildren().stream().anyMatch(node -> node.getName().equalsIgnoreCase(identifier)))
|
||||
{
|
||||
Messenger.print_server_message(CarpetServer.minecraft_server,
|
||||
Messenger.c("rb Failed to add settings command for " + identifier + ". It is masking previous command."));
|
||||
CarpetSettings.LOG.error("Failed to add settings command for " + identifier + ". It is masking previous command.");
|
||||
return;
|
||||
}
|
||||
|
||||
LiteralArgumentBuilder<ServerCommandSource> literalargumentbuilder = literal(identifier).requires((player) ->
|
||||
player.hasPermissionLevel(2) && !locked);
|
||||
|
||||
literalargumentbuilder.executes((context)->listAllSettings(context.getSource())).
|
||||
literalargumentbuilder.executes((context)-> listAllSettings(context.getSource())).
|
||||
then(literal("list").
|
||||
executes( (c) -> listSettings(c.getSource(), "All "+fancyName+" Settings",
|
||||
executes( (c) -> listSettings(c.getSource(), String.format(tr("ui.all_%(mod)s_settings","All %s Settings"), fancyName),
|
||||
getRules())).
|
||||
then(literal("defaults").
|
||||
executes( (c)-> listSettings(c.getSource(),
|
||||
"Current "+fancyName+" Startup Settings from "+identifier+".conf",
|
||||
String.format(tr("ui.current_%(mod)s_startup_settings_from_%(conf)s","Current %s Startup Settings from %s"), fancyName, (identifier+".conf")),
|
||||
findStartupOverrides()))).
|
||||
then(argument("tag",StringArgumentType.word()).
|
||||
suggests( (c, b)->suggestMatching(getCategories(), b)).
|
||||
executes( (c) -> listSettings(c.getSource(),
|
||||
String.format(fancyName+" Settings matching \"%s\"", StringArgumentType.getString(c, "tag")),
|
||||
String.format(tr("ui.%(mod)s_settings_matching_'%(query)s'","%s Settings matching \"%s\""), fancyName, tr("category." + StringArgumentType.getString(c, "tag"),StringArgumentType.getString(c, "tag"))),
|
||||
getRulesMatching(StringArgumentType.getString(c, "tag")))))).
|
||||
then(literal("removeDefault").
|
||||
requires(s -> !locked).
|
||||
@@ -405,33 +408,35 @@ public class SettingsManager
|
||||
private int displayRuleMenu(ServerCommandSource source, ParsedRule<?> rule)
|
||||
{
|
||||
PlayerEntity player;
|
||||
String displayName = rule.translatedName();
|
||||
try
|
||||
{
|
||||
player = source.getPlayer();
|
||||
}
|
||||
catch (CommandSyntaxException e)
|
||||
{
|
||||
Messenger.m(source, "w "+rule.name +" is set to: ","wb "+rule.getAsString());
|
||||
Messenger.m(source, "w "+ displayName +" "+ tr( "ui.is_set_to","is set to")+": ","wb "+rule.getAsString());
|
||||
return 1;
|
||||
}
|
||||
|
||||
Messenger.m(player, "");
|
||||
Messenger.m(player, "wb "+rule.name,"!/"+identifier+" "+rule.name,"^g refresh");
|
||||
Messenger.m(player, "w "+rule.description);
|
||||
Messenger.m(player, "wb "+ displayName ,"!/"+identifier+" "+rule.name,"^g refresh");
|
||||
Messenger.m(player, "w "+ rule.translatedDescription());
|
||||
|
||||
rule.extraInfo.forEach(s -> Messenger.m(player, "g "+s));
|
||||
rule.translatedExtras().forEach(s -> Messenger.m(player, "g "+s));
|
||||
|
||||
List<BaseText> tags = new ArrayList<>();
|
||||
tags.add(Messenger.c("w Tags: "));
|
||||
tags.add(Messenger.c("w "+ tr("ui.tags", "Tags")+": "));
|
||||
for (String t: rule.categories)
|
||||
{
|
||||
tags.add(Messenger.c("c ["+t+"]", "^g list all "+t+" settings","!/"+identifier+" list "+t));
|
||||
String translated = tr("category." + t, t);
|
||||
tags.add(Messenger.c("c ["+ translated +"]", "^g "+ String.format(tr("list_all_%s_settings","list all %s settings"), translated),"!/"+identifier+" list "+t));
|
||||
tags.add(Messenger.c("w , "));
|
||||
}
|
||||
tags.remove(tags.size()-1);
|
||||
Messenger.m(player, tags.toArray(new Object[0]));
|
||||
|
||||
Messenger.m(player, "w Current value: ",String.format("%s %s (%s value)",rule.getBoolValue()?"lb":"nb", rule.getAsString(),rule.isDefault()?"default":"modified"));
|
||||
Messenger.m(player, "w "+ tr("ui.current_value", "Current value")+": ",String.format("%s %s (%s value)",rule.getBoolValue()?"lb":"nb", rule.getAsString(),rule.isDefault()?"default":"modified"));
|
||||
List<BaseText> options = new ArrayList<>();
|
||||
options.add(Messenger.c("w Options: ", "y [ "));
|
||||
for (String o: rule.options)
|
||||
@@ -449,8 +454,8 @@ public class SettingsManager
|
||||
private int setRule(ServerCommandSource source, ParsedRule<?> rule, String newValue)
|
||||
{
|
||||
if (rule.set(source, newValue) != null)
|
||||
Messenger.m(source, "w "+rule.toString()+", ", "c [change permanently?]",
|
||||
"^w Click to keep the settings in "+identifier+".conf to save across restarts",
|
||||
Messenger.m(source, "w "+rule.toString()+", ", "c ["+ tr("ui.change_permanently","change permanently")+"?]",
|
||||
"^w "+String.format(tr("ui.click_to_keep_the_settings_in_%(conf)s_to_save_across_restarts","Click to keep the settings in %s to save across restarts"), identifier+".conf"),
|
||||
"?/"+identifier+" setDefault "+rule.name+" "+rule.getAsString());
|
||||
return 1;
|
||||
}
|
||||
@@ -465,7 +470,7 @@ public class SettingsManager
|
||||
writeSettingsToConf(conf.getLeft()); // this may feels weird, but if conf
|
||||
// is locked, it will never reach this point.
|
||||
rule.set(source,stringValue);
|
||||
Messenger.m(source ,"gi rule "+ rule.name+" will now default to "+ stringValue);
|
||||
Messenger.m(source ,"gi "+String.format(tr("ui.rule_%(rule)s_will_now_default_to_%(value)s","rule %s will now default to %s"), rule.translatedName(), stringValue));
|
||||
return 1;
|
||||
}
|
||||
// removes overrides of the default values in the file
|
||||
@@ -482,10 +487,11 @@ public class SettingsManager
|
||||
|
||||
private BaseText displayInteractiveSetting(ParsedRule<?> rule)
|
||||
{
|
||||
String displayName = rule.translatedName();
|
||||
List<Object> args = new ArrayList<>();
|
||||
args.add("w - "+rule.name+" ");
|
||||
args.add("w - "+ displayName +" ");
|
||||
args.add("!/"+identifier+" "+rule.name);
|
||||
args.add("^y "+rule.description);
|
||||
args.add("^y "+rule.translatedDescription());
|
||||
for (String option: rule.options)
|
||||
{
|
||||
args.add(makeSetRuleButton(rule, option, true));
|
||||
@@ -511,10 +517,10 @@ public class SettingsManager
|
||||
}
|
||||
String baseText = style + (brackets ? " [" : " ") + option + (brackets ? "]" : "");
|
||||
if (locked)
|
||||
return Messenger.c(baseText, "^g "+fancyName+" settings are locked");
|
||||
return Messenger.c(baseText, "^g "+fancyName+" " + tr("ui.settings_are_locked","settings are locked"));
|
||||
if (option.equalsIgnoreCase(rule.getAsString()))
|
||||
return Messenger.c(baseText);
|
||||
return Messenger.c(baseText, "^g Switch to " + option+(option.equalsIgnoreCase(rule.defaultAsString)?" (default)":""), "?/"+identifier+" " + rule.name + " " + option);
|
||||
return Messenger.c(baseText, "^g "+ tr("ui.switch_to","Switch to") +" " + option+(option.equalsIgnoreCase(rule.defaultAsString)?" (default)":""), "?/"+identifier+" " + rule.name + " " + option);
|
||||
}
|
||||
|
||||
private int listSettings(ServerCommandSource source, String title, Collection<ParsedRule<?>> settings_list)
|
||||
@@ -535,19 +541,26 @@ public class SettingsManager
|
||||
}
|
||||
private int listAllSettings(ServerCommandSource source)
|
||||
{
|
||||
listSettings(source, "Current "+fancyName+" Settings", getNonDefault());
|
||||
//listSettings(source, "Current "+fancyName+" Settings", getNonDefault());
|
||||
listSettings(source, String.format(tr("ui.current_%(mod)s_settings","Current %s Settings"), fancyName), getNonDefault());
|
||||
|
||||
if (version != null)
|
||||
Messenger.m(source, "g "+fancyName+" version: "+ version);
|
||||
//Messenger.m(source, "g "+fancyName+" version: "+ version);
|
||||
Messenger.m(source, "g "+fancyName+" "+ tr("ui.version", "version") + ": "+ version);
|
||||
try
|
||||
{
|
||||
PlayerEntity player = source.getPlayer();
|
||||
List<Object> tags = new ArrayList<>();
|
||||
tags.add("w Browse Categories:\n");
|
||||
//tags.add("w Browse Categories:\n");
|
||||
tags.add("w " + tr("ui.browse_categories", "Browse Categories") + ":\n");
|
||||
for (String t : getCategories())
|
||||
{
|
||||
tags.add("c [" + t+"]");
|
||||
tags.add("^g list all " + t + " settings");
|
||||
String catKey = "category." + t;
|
||||
String translated = tr(catKey, t);
|
||||
String translatedPlus = Translations.hasTranslation(catKey) ? String.format("%s (%s)",tr(catKey, t), t) : t;
|
||||
tags.add("c [" + translated +"]");
|
||||
//tags.add("^g list all " + translated + " settings");
|
||||
tags.add("^g " + String.format(tr("ui.list_all_%(cat)s_settings","list all %s settings"), translatedPlus));
|
||||
tags.add("!/"+identifier+" list " + t);
|
||||
tags.add("w ");
|
||||
}
|
||||
@@ -558,7 +571,7 @@ public class SettingsManager
|
||||
return 1;
|
||||
}
|
||||
|
||||
public void inspectClientsideCommand(String string)
|
||||
public void inspectClientsideCommand(ServerCommandSource source, String string)
|
||||
{
|
||||
if (string.startsWith("/carpet "))
|
||||
{
|
||||
@@ -569,11 +582,9 @@ public class SettingsManager
|
||||
String strOption = res[2];
|
||||
if (rules.containsKey(setting) && rules.get(setting).isClient)
|
||||
{
|
||||
rules.get(setting).set(null, strOption);
|
||||
rules.get(setting).set(source, strOption);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,23 +17,12 @@ public abstract class Validator<T>
|
||||
public abstract T validate(ServerCommandSource source, ParsedRule<T> currentRule, T newValue, String string);
|
||||
public String description() {return null;}
|
||||
|
||||
public static class POSITIVE_NUMBER<T extends Number> extends Validator<T>
|
||||
{
|
||||
@Override
|
||||
public T validate(ServerCommandSource source, ParsedRule<T> currentRule, T newValue, String string)
|
||||
{
|
||||
return newValue.doubleValue() > 0 ? newValue : null;
|
||||
}
|
||||
@Override
|
||||
public String description() { return "Must be a positive number"; }
|
||||
}
|
||||
|
||||
public static class _COMMAND<T> extends Validator<T>
|
||||
{
|
||||
@Override
|
||||
public T validate(ServerCommandSource source, ParsedRule<T> currentRule, T newValue, String string)
|
||||
{
|
||||
if (CarpetServer.settingsManager != null)
|
||||
if (CarpetServer.settingsManager != null && source != null)
|
||||
CarpetServer.settingsManager.notifyPlayersCommandsChanged();
|
||||
return newValue;
|
||||
}
|
||||
@@ -119,4 +108,15 @@ public abstract class Validator<T>
|
||||
@Override
|
||||
public String description() { return "Must be a positive number";}
|
||||
}
|
||||
|
||||
public static class PROBABILITY <T extends Number> extends Validator<T>
|
||||
{
|
||||
@Override
|
||||
public T validate(ServerCommandSource source, ParsedRule<T> currentRule, T newValue, String string)
|
||||
{
|
||||
return (newValue.doubleValue() >= 0 && newValue.doubleValue() <= 1 )? newValue : null;
|
||||
}
|
||||
@Override
|
||||
public String description() { return "Must be between 0 and 1";}
|
||||
}
|
||||
}
|
||||
@@ -109,21 +109,21 @@ public class BlockInfo
|
||||
put(Material.CARPET , "carpet" );
|
||||
put(Material.PLANT , "plant" );
|
||||
put(Material.UNDERWATER_PLANT, "water_plant" );
|
||||
put(Material.REPLACEABLE_PLANT, "vine" );
|
||||
put(Material.SEAGRASS , "sea_grass" );
|
||||
put(Material.REPLACEABLE_PLANT, "vegetation" );
|
||||
put(Material.REPLACEABLE_UNDERWATER_PLANT , "sea_grass" );
|
||||
put(Material.WATER , "water" );
|
||||
put(Material.BUBBLE_COLUMN , "bubble_column");
|
||||
put(Material.LAVA , "lava" );
|
||||
put(Material.SNOW , "snow_layer" );
|
||||
put(Material.SNOW_LAYER , "snow_layer" );
|
||||
put(Material.FIRE , "fire" );
|
||||
put(Material.PART , "redstone_bits");
|
||||
put(Material.SUPPORTED , "decoration" );
|
||||
put(Material.COBWEB , "cobweb" );
|
||||
put(Material.REDSTONE_LAMP , "redstone_lamp");
|
||||
put(Material.CLAY , "clay" );
|
||||
put(Material.EARTH , "dirt" );
|
||||
put(Material.ORGANIC , "grass" );
|
||||
put(Material.PACKED_ICE , "packed_ice" );
|
||||
put(Material.SAND , "sand" );
|
||||
put(Material.ORGANIC_PRODUCT , "clay" );
|
||||
put(Material.SOIL , "dirt" );
|
||||
put(Material.SOLID_ORGANIC , "grass" );
|
||||
put(Material.DENSE_ICE , "packed_ice" );
|
||||
put(Material.AGGREGATE , "sand" );
|
||||
put(Material.SPONGE , "sponge" );
|
||||
put(Material.SHULKER_BOX , "shulker" );
|
||||
put(Material.WOOD , "wood" );
|
||||
@@ -138,11 +138,11 @@ public class BlockInfo
|
||||
put(Material.STONE , "stone" );
|
||||
put(Material.METAL , "metal" );
|
||||
put(Material.SNOW_BLOCK , "snow" );
|
||||
put(Material.ANVIL , "anvil" );
|
||||
put(Material.REPAIR_STATION , "anvil" );
|
||||
put(Material.BARRIER , "barrier" );
|
||||
put(Material.PISTON , "piston" );
|
||||
put(Material.UNUSED_PLANT , "coral" );
|
||||
put(Material.PUMPKIN , "gourd" );
|
||||
put(Material.GOURD , "gourd" );
|
||||
put(Material.EGG , "dragon_egg" );
|
||||
put(Material.CAKE , "cake" );
|
||||
}};
|
||||
|
||||
@@ -3,14 +3,15 @@ package carpet.utils;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.entity.EntityCategory;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.util.Formatting;
|
||||
import net.minecraft.text.BaseText;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.text.ClickEvent;
|
||||
import net.minecraft.text.HoverEvent;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.text.Style;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.Formatting;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -52,32 +53,33 @@ public class Messenger
|
||||
/ = action added to the previous component
|
||||
*/
|
||||
|
||||
private static BaseText _applyStyleToTextComponent(BaseText comp, String style)
|
||||
public static Style parseStyle(String style)
|
||||
{
|
||||
//could be rewritten to be more efficient
|
||||
comp.getStyle().setItalic(style.indexOf('i')>=0);
|
||||
comp.getStyle().setStrikethrough(style.indexOf('s')>=0);
|
||||
comp.getStyle().setUnderline(style.indexOf('u')>=0);
|
||||
comp.getStyle().setBold(style.indexOf('b')>=0);
|
||||
comp.getStyle().setObfuscated(style.indexOf('o')>=0);
|
||||
comp.getStyle().setColor(Formatting.WHITE);
|
||||
if (style.indexOf('w')>=0) comp.getStyle().setColor(Formatting.WHITE); // not needed
|
||||
if (style.indexOf('y')>=0) comp.getStyle().setColor(Formatting.YELLOW);
|
||||
if (style.indexOf('m')>=0) comp.getStyle().setColor(Formatting.LIGHT_PURPLE);
|
||||
if (style.indexOf('r')>=0) comp.getStyle().setColor(Formatting.RED);
|
||||
if (style.indexOf('c')>=0) comp.getStyle().setColor(Formatting.AQUA);
|
||||
if (style.indexOf('l')>=0) comp.getStyle().setColor(Formatting.GREEN);
|
||||
if (style.indexOf('t')>=0) comp.getStyle().setColor(Formatting.BLUE);
|
||||
if (style.indexOf('f')>=0) comp.getStyle().setColor(Formatting.DARK_GRAY);
|
||||
if (style.indexOf('g')>=0) comp.getStyle().setColor(Formatting.GRAY);
|
||||
if (style.indexOf('d')>=0) comp.getStyle().setColor(Formatting.GOLD);
|
||||
if (style.indexOf('p')>=0) comp.getStyle().setColor(Formatting.DARK_PURPLE);
|
||||
if (style.indexOf('n')>=0) comp.getStyle().setColor(Formatting.DARK_RED);
|
||||
if (style.indexOf('q')>=0) comp.getStyle().setColor(Formatting.DARK_AQUA);
|
||||
if (style.indexOf('e')>=0) comp.getStyle().setColor(Formatting.DARK_GREEN);
|
||||
if (style.indexOf('v')>=0) comp.getStyle().setColor(Formatting.DARK_BLUE);
|
||||
if (style.indexOf('k')>=0) comp.getStyle().setColor(Formatting.BLACK);
|
||||
return comp;
|
||||
Style styleInstance = new Style();
|
||||
styleInstance.setItalic(style.indexOf('i')>=0);
|
||||
styleInstance.setStrikethrough(style.indexOf('s')>=0);
|
||||
styleInstance.setUnderline(style.indexOf('u')>=0);
|
||||
styleInstance.setBold(style.indexOf('b')>=0);
|
||||
styleInstance.setObfuscated(style.indexOf('o')>=0);
|
||||
styleInstance.setColor(Formatting.WHITE);
|
||||
if (style.indexOf('w')>=0) styleInstance.setColor(Formatting.WHITE); // not needed
|
||||
if (style.indexOf('y')>=0) styleInstance.setColor(Formatting.YELLOW);
|
||||
if (style.indexOf('m')>=0) styleInstance.setColor(Formatting.LIGHT_PURPLE);
|
||||
if (style.indexOf('r')>=0) styleInstance.setColor(Formatting.RED);
|
||||
if (style.indexOf('c')>=0) styleInstance.setColor(Formatting.AQUA);
|
||||
if (style.indexOf('l')>=0) styleInstance.setColor(Formatting.GREEN);
|
||||
if (style.indexOf('t')>=0) styleInstance.setColor(Formatting.BLUE);
|
||||
if (style.indexOf('f')>=0) styleInstance.setColor(Formatting.DARK_GRAY);
|
||||
if (style.indexOf('g')>=0) styleInstance.setColor(Formatting.GRAY);
|
||||
if (style.indexOf('d')>=0) styleInstance.setColor(Formatting.GOLD);
|
||||
if (style.indexOf('p')>=0) styleInstance.setColor(Formatting.DARK_PURPLE);
|
||||
if (style.indexOf('n')>=0) styleInstance.setColor(Formatting.DARK_RED);
|
||||
if (style.indexOf('q')>=0) styleInstance.setColor(Formatting.DARK_AQUA);
|
||||
if (style.indexOf('e')>=0) styleInstance.setColor(Formatting.DARK_GREEN);
|
||||
if (style.indexOf('v')>=0) styleInstance.setColor(Formatting.DARK_BLUE);
|
||||
if (style.indexOf('k')>=0) styleInstance.setColor(Formatting.BLACK);
|
||||
return styleInstance;
|
||||
}
|
||||
public static String heatmap_color(double actual, double reference)
|
||||
{
|
||||
@@ -114,10 +116,14 @@ public class Messenger
|
||||
{
|
||||
message = "w"+message;
|
||||
}
|
||||
String[] parts = message.split("\\s", 2);
|
||||
String desc = parts[0];
|
||||
int limit = message.indexOf(' ');
|
||||
String desc = message;
|
||||
String str = "";
|
||||
if (parts.length > 1) str = parts[1];
|
||||
if (limit >= 0)
|
||||
{
|
||||
desc = message.substring(0, limit);
|
||||
str = message.substring(limit+1);
|
||||
}
|
||||
if (desc.charAt(0) == '/') // deprecated
|
||||
{
|
||||
if (previous_message != null)
|
||||
@@ -143,7 +149,8 @@ public class Messenger
|
||||
return previous_message;
|
||||
}
|
||||
BaseText txt = new LiteralText(str);
|
||||
return _applyStyleToTextComponent(txt, desc);
|
||||
txt.setStyle(parseStyle(desc));
|
||||
return txt;
|
||||
}
|
||||
public static BaseText tp(String desc, Vec3d pos) { return tp(desc, pos.x, pos.y, pos.z); }
|
||||
public static BaseText tp(String desc, BlockPos pos) { return tp(desc, pos.getX(), pos.getY(), pos.getZ()); }
|
||||
@@ -224,7 +231,8 @@ public class Messenger
|
||||
//message source
|
||||
public static void m(ServerCommandSource source, Object ... fields)
|
||||
{
|
||||
source.sendFeedback(Messenger.c(fields),source.getMinecraftServer().getWorld(DimensionType.OVERWORLD) != null);
|
||||
if (source != null)
|
||||
source.sendFeedback(Messenger.c(fields),source.getMinecraftServer() != null && source.getMinecraftServer().getWorld(DimensionType.OVERWORLD) != null);
|
||||
}
|
||||
public static void m(PlayerEntity player, Object ... fields)
|
||||
{
|
||||
@@ -263,7 +271,7 @@ public class Messenger
|
||||
public static BaseText s(String text, String style)
|
||||
{
|
||||
BaseText message = new LiteralText(text);
|
||||
_applyStyleToTextComponent(message, style);
|
||||
message.setStyle(parseStyle(style));
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,13 @@ import carpet.CarpetServer;
|
||||
import com.google.common.collect.Sets;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.effect.StatusEffects;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.tag.FluidTags;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -93,4 +99,25 @@ public class MobAI
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Not a replacement for living entity jump() - this barely is to allow other entities that can't jump in vanilla to 'jump'
|
||||
* @param e
|
||||
*/
|
||||
public static void genericJump(Entity e)
|
||||
{
|
||||
if (!e.onGround && !e.isInFluid(FluidTags.WATER) && !e.isInLava()) return;
|
||||
float m = e.world.getBlockState(new BlockPos(e)).getBlock().getJumpVelocityMultiplier();
|
||||
float g = e.world.getBlockState(new BlockPos(e.getX(), e.getBoundingBox().y1 - 0.5000001D, e.getZ())).getBlock().getJumpVelocityMultiplier();
|
||||
float jumpVelocityMultiplier = (double) m == 1.0D ? g : m;
|
||||
float jumpStrength = (0.42F * jumpVelocityMultiplier);
|
||||
Vec3d vec3d = e.getVelocity();
|
||||
e.setVelocity(vec3d.x, jumpStrength, vec3d.z);
|
||||
if (e.isSprinting())
|
||||
{
|
||||
float u = e.yaw * 0.017453292F;
|
||||
e.setVelocity(e.getVelocity().add((-MathHelper.sin(g) * 0.2F), 0.0D, (MathHelper.cos(u) * 0.2F)));
|
||||
}
|
||||
e.velocityDirty = true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package carpet.utils;
|
||||
|
||||
import carpet.fakes.ChunkTicketManagerInterface;
|
||||
import carpet.fakes.ServerChunkManagerInterface;
|
||||
import net.minecraft.server.world.ChunkTicketManager;
|
||||
import net.minecraft.server.world.ServerChunkManager;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
|
||||
public class SpawnChunks
|
||||
{
|
||||
public static void changeSpawnChunks(ServerChunkManager chunkManager, ChunkPos pos, int size)
|
||||
{
|
||||
ChunkTicketManager ticketManager = ((ServerChunkManagerInterface)chunkManager).getCMTicketManager();
|
||||
((ChunkTicketManagerInterface)ticketManager).changeSpawnChunks(pos, size);
|
||||
}
|
||||
}
|
||||
@@ -186,7 +186,7 @@ public class SpawnReporter
|
||||
}
|
||||
else
|
||||
{
|
||||
return printEntitiesByType(creature_type, worldIn);
|
||||
return printEntitiesByType(creature_type, worldIn, true);
|
||||
|
||||
}
|
||||
|
||||
@@ -250,22 +250,24 @@ public class SpawnReporter
|
||||
return get_type_string(get_creature_type_from_code(str));
|
||||
}
|
||||
|
||||
public static List<BaseText> printEntitiesByType(EntityCategory cat, World worldIn) //Class<?> entityType)
|
||||
public static List<BaseText> printEntitiesByType(EntityCategory cat, World worldIn, boolean all) //Class<?> entityType)
|
||||
{
|
||||
List<BaseText> lst = new ArrayList<>();
|
||||
lst.add( Messenger.s(String.format("Loaded entities for %s class:", get_type_string(cat))));
|
||||
for (Entity entity : ((ServerWorld)worldIn).getEntities(null, (e) -> e.getType().getCategory()==cat))
|
||||
{
|
||||
if (!(entity instanceof MobEntity) || !((MobEntity)entity).isPersistent())
|
||||
{
|
||||
EntityType type = entity.getType();
|
||||
BlockPos pos = entity.getBlockPos();
|
||||
lst.add( Messenger.c(
|
||||
"w - ",
|
||||
Messenger.tp("wb",pos),
|
||||
String.format("w : %s", type.getName().getString())
|
||||
));
|
||||
}
|
||||
boolean persistent = entity instanceof MobEntity && ( ((MobEntity) entity).isPersistent() || ((MobEntity) entity).cannotDespawn());
|
||||
if (!all && persistent)
|
||||
continue;
|
||||
|
||||
EntityType type = entity.getType();
|
||||
BlockPos pos = entity.getBlockPos();
|
||||
lst.add( Messenger.c(
|
||||
"w - ",
|
||||
Messenger.tp(persistent?"gb":"wb",pos),
|
||||
String.format(persistent?"g : %s":"w : %s", type.getName().getString())
|
||||
));
|
||||
|
||||
}
|
||||
if (lst.size()==1)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
package carpet.utils;
|
||||
|
||||
import carpet.CarpetExtension;
|
||||
import carpet.CarpetServer;
|
||||
import carpet.CarpetSettings;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Translations
|
||||
{
|
||||
private static Map<String, String> translationMap;
|
||||
|
||||
public static String tr(String key)
|
||||
{
|
||||
return translationMap == null ? key : translationMap.getOrDefault(key, key);
|
||||
}
|
||||
|
||||
public static String tr(String key, String str)
|
||||
{
|
||||
return translationMap == null ? str : translationMap.getOrDefault(key, str);
|
||||
}
|
||||
|
||||
public static boolean hasTranslations()
|
||||
{
|
||||
return translationMap != null;
|
||||
}
|
||||
|
||||
public static boolean hasTranslation(String key)
|
||||
{
|
||||
return translationMap != null && translationMap.containsKey(key);
|
||||
}
|
||||
|
||||
public static Map<String, String> getTranslationFromResourcePath(String path)
|
||||
{
|
||||
String dataJSON;
|
||||
try
|
||||
{
|
||||
dataJSON = IOUtils.toString(
|
||||
Objects.requireNonNull(Translations.class.getClassLoader().getResourceAsStream(String.format("assets/carpet/lang/%s.json", CarpetSettings.language))),
|
||||
StandardCharsets.UTF_8);
|
||||
} catch (NullPointerException | IOException e) {
|
||||
return null;
|
||||
}
|
||||
Gson gson = new GsonBuilder().enableComplexMapKeySerialization().create();
|
||||
return gson.fromJson(dataJSON, new TypeToken<Map<String, String>>() {}.getType());
|
||||
}
|
||||
|
||||
|
||||
public static void updateLanguage(ServerCommandSource source)
|
||||
{
|
||||
if (CarpetSettings.language.equalsIgnoreCase("none"))
|
||||
{
|
||||
translationMap = null;
|
||||
return;
|
||||
}
|
||||
Map<String, String> translations = new HashMap<>();
|
||||
Map<String, String> trans = getTranslationFromResourcePath(String.format("assets/carpet/lang/%s.json", CarpetSettings.language));
|
||||
if (trans != null) trans.forEach(translations::put);
|
||||
|
||||
for (CarpetExtension ext : CarpetServer.extensions)
|
||||
{
|
||||
Map<String, String> extMappings = ext.canHasTranslations(CarpetSettings.language);
|
||||
if (extMappings != null)
|
||||
{
|
||||
extMappings.forEach((key, value) ->
|
||||
{
|
||||
if (!translations.containsKey(key)) translations.put(key, value);
|
||||
});
|
||||
}
|
||||
}
|
||||
translations.entrySet().removeIf(e -> e.getKey().startsWith("//"));
|
||||
if (translations.isEmpty())
|
||||
{
|
||||
translationMap = null;
|
||||
return;
|
||||
}
|
||||
translationMap = translations;
|
||||
}
|
||||
|
||||
public static boolean isValidLanguage(String newValue)
|
||||
{
|
||||
// will put some validations for availble languages at some point
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// This file isn't necessary at all, because the language module would use the strings coded in the source if language "none" is selected.
|
||||
// So en_us is the default language and probably no change will be made after loading this file.
|
||||
// But it could be a good example for writing the language file for other languages.
|
||||
|
||||
{
|
||||
"// Rules:": "",
|
||||
"rule.portalSuffocationFix.name": "",
|
||||
"// the key is genetated as:" : "String.format('rule.%s.name', rule.name)",
|
||||
|
||||
|
||||
"rule.portalSuffocationFix.desc": "",
|
||||
"// the key is genetated as:" : "String.format('rule.%s.desc', rule.name)",
|
||||
|
||||
|
||||
"rule.portalSuffocationFix.extra.0": "",
|
||||
"rule.portalSuffocationFix.extra.1": "",
|
||||
"// the key is genetated as:" : "String.format('rule.%s.extra.%i', rule.name, index)",
|
||||
|
||||
|
||||
"// Categories:": "",
|
||||
|
||||
"category.bugfix": "bugfix",
|
||||
"category.survival": "survival",
|
||||
"category.creative": "creative",
|
||||
"category.experimental": "experimental",
|
||||
"category.optimization": "optimization",
|
||||
"category.feature": "feature",
|
||||
"category.command": "command",
|
||||
"category.tnt": "TNT",
|
||||
"category.dispenser": "dispenser",
|
||||
"category.scarpet": "scarpet",
|
||||
"category.client": "client",
|
||||
|
||||
"// Settings command UI elements": "",
|
||||
|
||||
"ui.browse_categories": "Browse categories",
|
||||
"ui.list_all_%(cat)s_settings": "list all %s settings",
|
||||
"ui.version": "Version",
|
||||
"ui.current_%(mod)s_settings": "Current %s settings",
|
||||
"ui.switch_to": "Switch to",
|
||||
"ui.settings_are_locked": "settings are locked",
|
||||
"ui.is_set_to": "is set to",
|
||||
"ui.unknown_rule": "Unknown rule",
|
||||
"ui.current_%(mod)s_startup_settings_from_%(conf)s": "Current %s Startup Settings from %s",
|
||||
"ui.%(mod)s_settings_matching_'%(query)s'": "%s settings matching \"%s\" ",
|
||||
"ui.all_%(mod)s_settings": "All %s settings",
|
||||
"ui.tags": "Tags",
|
||||
"ui.change_permanently": "Change permanently",
|
||||
"ui.click_to_keep_the_settings_in_%(conf)s_to_save_across_restarts": "click to keep the settings in %s to save across restarts",
|
||||
"ui.rule_%(rule)s_will_now_default_to_%(value)s": "rule %s will now default to %s",
|
||||
"ui.current_value": "current value"
|
||||
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
{
|
||||
"rule.antiCheatDisabled.name": "移动检测通杀",
|
||||
"rule.antiCheatDisabled.desc": "防止玩家因为“本服务器未启用飞行”,“移动过快”等原因被踢出",
|
||||
|
||||
"rule.carpets.name": "放置地毯执行功能",
|
||||
"rule.carpets.desc": "通过放置地毯方块快捷执行部分功能",
|
||||
|
||||
"rule.combineXPOrbs.name": "经验球合并",
|
||||
"rule.combineXPOrbs.desc": "会将多个小经验球合并为更大的经验球",
|
||||
|
||||
"rule.commandCameramode.name": "灵魂出窍模式",
|
||||
"rule.commandCameramode.desc": "启用/c和/s命令使得玩家可以在生存模式和观察者模式间切换",
|
||||
"rule.commandCameramode.extra.0": "/c和/s命令所有玩家(包括非OP玩家)都可以使用",
|
||||
|
||||
"rule.commandDistance.name": "距离测量",
|
||||
"rule.commandDistance.desc": "启用/distance命令以测量游戏中两点间距离",
|
||||
"rule.commandDistance.extra.0": "可以通过放置棕色地毯的方式使用本功能,前提是“放置地毯执行功能”已启用",
|
||||
|
||||
"rule.commandDraw.name": "画图",
|
||||
"rule.commandDraw.desc": "启用/draw命令以允许绘制一些简单图形",
|
||||
|
||||
"rule.commandInfo.name": "获取方块数据",
|
||||
"rule.commandInfo.desc": "启用/info命令以获取方块数据",
|
||||
"rule.commandInfo.extra.0": "可以通过放置灰色地毯的方式使用本功能,前提是“放置地毯执行功能”已启用",
|
||||
|
||||
"rule.commandLog.name": "游戏数据监视器",
|
||||
"rule.commandLog.desc": "启用/log命令以在聊天栏/Tab栏监视游戏部分数据",
|
||||
|
||||
"rule.commandPerimeterInfo.name": "刷怪区域搜寻器",
|
||||
"rule.commandPerimeterInfo.desc": "启用/perimeterinfo命令以搜寻周围的可刷怪区域",
|
||||
|
||||
"rule.commandPlayer.name": "假人控制",
|
||||
"rule.commandPlayer.desc": "启用/player命令以控制/召唤玩家",
|
||||
|
||||
"rule.commandScript.name": "地毯脚本控制器",
|
||||
"rule.commandScript.desc": "启用/script相关命令",
|
||||
"rule.commandScript.extra.0": "一个Scarpet语言的游戏内API",
|
||||
|
||||
"rule.commandSpawn.name": "刷怪追踪器",
|
||||
"rule.commandSpawn.desc": "启用/spawn命令用于怪物生成追踪",
|
||||
|
||||
"rule.commandTick.name": "游戏时钟控制器",
|
||||
"rule.commandTick.desc": "启用/tick命令以控制游戏时钟",
|
||||
|
||||
"rule.commandTrackAI.name": "AI追踪器",
|
||||
"rule.commandTrackAI.desc": "启用/track命令以追踪生物的AI",
|
||||
|
||||
"rule.ctrlQCraftingFix.name": "ctrlQ合成修复",
|
||||
"rule.ctrlQCraftingFix.desc": "在合成时允许使用ctrl+Q快捷键扔出结果格内所有物品",
|
||||
|
||||
"rule.customMOTD.name": "MOTD更改",
|
||||
"rule.customMOTD.desc": "设置一个不同的MOTD信息",
|
||||
"rule.customMOTD.extra.0": "使用'_'时将发送默认MOTD(从server.properties中读取)",
|
||||
|
||||
"rule.defaultLoggers.name": "默认游戏监视器",
|
||||
"rule.defaultLoggers.desc": "为所有新进入玩家设置部分监视器默认开启",
|
||||
"rule.defaultLoggers.extra.0": "比如设置'tps,mobcaps'作为默认监视器",
|
||||
|
||||
"rule.desertShrubs.name": "树苗在沙漠干枯",
|
||||
"rule.desertShrubs.desc": "树苗将在附近无水源的沙漠群系枯萎",
|
||||
|
||||
"rule.disableSpawnChunks.name": "允许出生点区块卸载",
|
||||
"rule.disableSpawnChunks.desc": "允许出生点区块卸载",
|
||||
|
||||
"rule.explosionNoBlockDamage.name": "防爆",
|
||||
"rule.explosionNoBlockDamage.desc": "任何形式的爆炸都不会摧毁方块",
|
||||
|
||||
"rule.extremeBehaviours.name": "随机极端情况",
|
||||
"rule.extremeBehaviours.desc": "大幅度提升极端情况出现概率,仅用于测试",
|
||||
"rule.extremeBehaviours.extra.0": "发射器和投掷器将使用最大随机刻",
|
||||
|
||||
"rule.fastRedstoneDust.name": "红石粉卡顿优化",
|
||||
"rule.fastRedstoneDust.desc": "红石粉卡顿优化 作者 Theosib",
|
||||
|
||||
"rule.fillLimit.name": "fill/clone上限更改",
|
||||
"rule.fillLimit.desc": "将fill/clone上限更改为自己需要的值",
|
||||
"rule.fillLimit.extra.0": "你必须在1-20M之间取一个值",
|
||||
|
||||
"rule.fillUpdates.name": "fill更新开关",
|
||||
"rule.fillUpdates.desc": "fill/clone/setblock命令以及结构方块执行时是否产生更新",
|
||||
"rule.fillUpdates.extra.0": "设置为true有更新 设置为false时为无更新",
|
||||
|
||||
"rule.flatWorldStructureSpawning.name": "结构怪在超平坦世界生成",
|
||||
"rule.flatWorldStructureSpawning.desc": "允许结构怪在超平坦世界生成",
|
||||
|
||||
"rule.flippinCactus.name": "仙人掌扳手",
|
||||
"rule.flippinCactus.desc": "允许使用仙人掌调整方块朝向,并且不会产生更新",
|
||||
|
||||
"rule.hardcodeTNTangle.name": "硬编码TNT角度",
|
||||
"rule.hardcodeTNTangle.desc": "把TNT水平随机角度设为固定值,可用于测试机器",
|
||||
"rule.hardcodeTNTangle.extra.0": "默认为-1,必须在0与360之间,或者-1",
|
||||
|
||||
"rule.hopperCounters.name": "漏斗计数器",
|
||||
"rule.hopperCounters.desc": "漏斗指向的羊毛会计算经过的物品",
|
||||
"rule.hopperCounters.extra.0": "在羊毛上放置红色或绿色地毯,使用/counter命令可启用",
|
||||
"rule.hopperCounters.extra.1": "使用 /counter <color?> reset重置计数器,使用/counter <color?>查询",
|
||||
"rule.hopperCounters.extra.2": "在生存模式,在同色羊毛上放绿地毯可以查询,放红地毯重置",
|
||||
"rule.hopperCounters.extra.3": "数据是全局性在玩家间共享的,并且有16颜色可用",
|
||||
"rule.hopperCounters.extra.4": "物品会被销毁,每个漏斗每tick销毁一组物品",
|
||||
|
||||
"rule.huskSpawningInTemples.name": "尸壳在神殿里生成",
|
||||
"rule.huskSpawningInTemples.desc": "只有尸壳会在沙漠神殿生成",
|
||||
|
||||
"rule.lagFreeSpawning.name": "延迟自然生成",
|
||||
"rule.lagFreeSpawning.desc": "生物生成需要更少的CPU和内存",
|
||||
|
||||
"rule.leadFix.name": "栓绳修复",
|
||||
"rule.leadFix.desc": "修复栓绳在未加载区块中,变得不可见的问题",
|
||||
|
||||
"rule.maxEntityCollisions.name": "最大实体挤压数",
|
||||
"rule.maxEntityCollisions.desc": "设定最大实体挤压限制,0表示无限大",
|
||||
|
||||
"rule.mergeTNT.name": "合并TNT",
|
||||
"rule.mergeTNT.desc": "合并静止的点燃的tnt实体",
|
||||
|
||||
"rule.missingTools.name": "工具缺失修复",
|
||||
"rule.missingTools.desc": "活塞,玻璃和海绵可以用合适的工具更快地破坏",
|
||||
|
||||
"rule.movableBlockEntities.name": "容器移动",
|
||||
"rule.movableBlockEntities.desc": "活塞可推动方块实体,比如箱子,漏斗",
|
||||
|
||||
"rule.onePlayerSleeping.name": "单个玩家睡觉",
|
||||
"rule.onePlayerSleeping.desc": "服务器里一个玩家睡觉可跳过夜晚",
|
||||
|
||||
"rule.optimizedTNT.name": "TNT优化",
|
||||
"rule.optimizedTNT.desc": "tnt在相同的地点或在流体里,爆炸造成更小的延迟",
|
||||
|
||||
"rule.persistentParrots.name": "鹦鹉停留",
|
||||
"rule.persistentParrots.desc": "鹦鹉不会离开你的肩膀,除非你收到伤害",
|
||||
|
||||
"rule.placementRotationFix.name": "放置旋转修复",
|
||||
"rule.placementRotationFix.desc": "修复了玩家放置方块时快速转身造成的问题",
|
||||
|
||||
"rule.pushLimit.name": "自定义推动上限",
|
||||
"rule.pushLimit.desc": "自定义活塞推动上限",
|
||||
"rule.pushLimit.extra.0": "你必须在1-1024中选取一个值",
|
||||
|
||||
"rule.quasiConnectivity.name": "qC激活开关",
|
||||
"rule.quasiConnectivity.desc": "活塞,发射器和投掷器在他们上方方块激活时是否响应",
|
||||
"rule.quasiConnectivity.extra.0": "设置为true为开启 设置为false为禁用",
|
||||
|
||||
"rule.railPowerLimit.name": "自定义动力铁轨激活距离",
|
||||
"rule.railPowerLimit.desc": "动力铁轨激活上限可自定义",
|
||||
"rule.railPowerLimit.extra.0": "你必须在1-1024中选取一个值",
|
||||
|
||||
"rule.renewableCoral.name": "珊瑚可再生",
|
||||
"rule.renewableCoral.desc": "使用骨粉可催熟珊瑚以生成珊瑚结构",
|
||||
|
||||
"rule.renewableSponges.name": "海绵可再生",
|
||||
"rule.renewableSponges.desc": "守卫者将在被雷击后会变为远古守卫者",
|
||||
|
||||
"rule.rotatorBlock.name": "仙人掌扳手发射器版",
|
||||
"rule.rotatorBlock.desc": "发射器中的仙人掌可以旋转方块(尽可能以逆时针)",
|
||||
|
||||
"rule.scriptsAutoload.name": "Scarpet脚本自动加载",
|
||||
"rule.scriptsAutoload.desc": "在服务器/世界加载的时候将会自动从世界文件中加载Scarpet脚本文件",
|
||||
"rule.scriptsAutoload.extra.0": "/script命令必须启用",
|
||||
|
||||
"rule.shulkerSpawningInEndCities.name": "潜影贝重生",
|
||||
"rule.shulkerSpawningInEndCities.desc": "潜影贝将会在末地城中重生",
|
||||
|
||||
"rule.silverFishDropGravel.name": "蠹虫钻出方块掉落沙砾",
|
||||
"rule.silverFishDropGravel.desc": "蠹虫钻出方块时会掉落沙砾",
|
||||
|
||||
"rule.smoothClientAnimations.name": "平滑客户端动画",
|
||||
"rule.smoothClientAnimations.desc": "低TPS设置时可以使客户端动画更加平滑",
|
||||
"rule.smoothClientAnimations.extra.0": "仅在单人游戏中生效,并且会降低客户端运行速度",
|
||||
|
||||
"rule.stackableShulkerBoxes.name": "潜影盒堆叠",
|
||||
"rule.stackableShulkerBoxes.desc": "空潜影盒仍在地上时将自动堆叠,直至堆叠为1组",
|
||||
"rule.stackableShulkerBoxes.extra.0": "在物品GUI中,请使用shift键+单击以移动整组潜影盒",
|
||||
|
||||
"rule.summonNaturalLightning.name": "召唤闪电自然化",
|
||||
"rule.summonNaturalLightning.desc": "召唤的闪电将拥有所有自然生成闪电拥有的特性",
|
||||
|
||||
"rule.tntDoNotUpdate.name": "TNT放置时不产生更新",
|
||||
"rule.tntDoNotUpdate.desc": "TNT在放置时不会产生任何方块更新(不会激活)",
|
||||
|
||||
"rule.tntPrimerMomentumRemoved.name": "移除TNT点燃时随机动量",
|
||||
"rule.tntPrimerMomentumRemoved.desc": "TNT点燃时的随机动量将被移除",
|
||||
|
||||
"rule.tntRandomRange.name": "TNT爆炸范围设置",
|
||||
"rule.tntRandomRange.desc": "设置TNT随机爆炸范围为一个固定的值,设为-1以禁用",
|
||||
"rule.tntRandomRange.extra.0": "必须启用optimizedTNT功能",
|
||||
"rule.tntRandomRange.extra.1": "不能为负值,除了-1",
|
||||
|
||||
"rule.unloadedEntityFix.name": "未加载实体修复",
|
||||
"rule.unloadedEntityFix.desc": "进入或者被推入未加载区块的实体不会消失",
|
||||
|
||||
"rule.viewDistance.name": "自定义视距",
|
||||
"rule.viewDistance.desc": "改变服务器视距,设为0以使用默认值",
|
||||
"rule.viewDistance.extra.0": "你必须在0(使用服务器默认设置)-32取一个整数",
|
||||
|
||||
"rule.xpNoCooldown.name": "经验吸收无冷却",
|
||||
"rule.xpNoCooldown.desc": "玩家吸收经验球时不会有冷却时间",
|
||||
|
||||
"rule.portalSuffocationFix.name": "传送门窒息修复",
|
||||
"rule.portalSuffocationFix.desc": "使下界传送门正确地传送实体",
|
||||
"rule.portalSuffocationFix.extra.0": "传送的实体将不再卡在黑曜石里面",
|
||||
|
||||
"rule.portalCreativeDelay.name": "创造玩家不被地狱门传送",
|
||||
"rule.portalCreativeDelay.desc": "创造模式的玩家将不会立即被地狱门传送",
|
||||
|
||||
|
||||
"category.bugfix": "BUG修复",
|
||||
"category.survival": "生存",
|
||||
"category.creative": "创造",
|
||||
"category.experimental": "试验性",
|
||||
"category.optimization": "优化",
|
||||
"category.feature": "特性",
|
||||
"category.command": "指令",
|
||||
"category.tnt": "TNT",
|
||||
"category.dispenser": "发射器",
|
||||
"category.scarpet": "scarpet脚本语言",
|
||||
"category.client": "客户端",
|
||||
|
||||
"ui.browse_categories": "浏览分类",
|
||||
"ui.list_all_%(cat)s_settings": "列出所有 %s 选项",
|
||||
"ui.version": "版本",
|
||||
"ui.current_%(mod)s_settings": "目前启用的 %s 选项",
|
||||
"ui.switch_to": "切换至",
|
||||
"ui.settings_are_locked": "选项被锁定",
|
||||
"ui.is_set_to": "被设置为",
|
||||
"ui.unknown_rule": "未知的规则选项",
|
||||
"ui.current_%(mod)s_startup_settings_from_%(conf)s": "目前启用的%s选项,从%s中读取得",
|
||||
"ui.%(mod)s_settings_matching_'%(query)s'": "%s中符合\"%s\"的选项:",
|
||||
"ui.all_%(mod)s_settings": "所有的%s选项",
|
||||
"ui.tags": "分类",
|
||||
"ui.change_permanently": "永久更改",
|
||||
"ui.click_to_keep_the_settings_in_%(conf)s_to_save_across_restarts": "点击此按钮以使此选项保存于%s,重启后依旧生效",
|
||||
"ui.rule_%(rule)s_will_now_default_to_%(value)s": "规则%s将会被默认设置为%s",
|
||||
"ui.current_value": "当前的值"
|
||||
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
{
|
||||
"rule.antiCheatDisabled.name": "關閉伺服器作弊檢測",
|
||||
"rule.antiCheatDisabled.desc": "防止玩家因為“本伺服器不允許飛行”,“移動速度過快”等原因被請出伺服器",
|
||||
|
||||
"rule.carpets.name": "放置地毯顯示進階數據",
|
||||
"rule.carpets.desc": "通過把地毯放置在地上取得更進階信息",
|
||||
|
||||
"rule.combineXPOrbs.name": "合併小經驗球",
|
||||
"rule.combineXPOrbs.desc": "會將大量的小經驗球合併成等效的大經驗球",
|
||||
|
||||
"rule.commandCameramode.name": "旁觀者模式",
|
||||
"rule.commandCameramode.desc": "允許玩家使用/c切換成旁觀者模式,利用/s切換回生存模式",
|
||||
"rule.commandCameramode.extra.0": "/c及/s不需要op權限也可使用",
|
||||
|
||||
"rule.commandDistance.name": "距離測定",
|
||||
"rule.commandDistance.desc": "使用/distance指令測定兩點的距離",
|
||||
"rule.commandDistance.extra.0": "可以使用放置棕色地毯來使用此功能,前提是“放置地毯顯示進階數據”已啟用",
|
||||
|
||||
"rule.commandDraw.name": "繪製圖形",
|
||||
"rule.commandDraw.desc": "使用/draw指令以允許繪製一些簡易圖形",
|
||||
|
||||
"rule.commandInfo.name": "獲取方塊進階資訊",
|
||||
"rule.commandInfo.desc": "允許使用/info指令以獲得方塊進階資訊",
|
||||
"rule.commandInfo.extra.0": "可以使用放置灰色地毯來使用此功能,前提是“放置地毯顯示進階數據”已啟用",
|
||||
|
||||
"rule.commandLog.name": "遊戲數據追蹤器",
|
||||
"rule.commandLog.desc": "允許使用/log指令使在Tab欄位追蹤遊戲部分數據",
|
||||
|
||||
"rule.commandPerimeterInfo.name": "刷怪區域追蹤器",
|
||||
"rule.commandPerimeterInfo.desc": "允許使用/perimeterinfo指令以探查周圍可生怪區域",
|
||||
|
||||
"rule.commandPlayer.name": "機器人控制",
|
||||
"rule.commandPlayer.desc": "允許使用/player指令以控制/召喚已存在的玩家id作為機器人",
|
||||
|
||||
"rule.commandScript.name": "地毯腳本控制器",
|
||||
"rule.commandScript.desc": "允許使用/script相關指令",
|
||||
"rule.commandScript.extra.0": "一個Scarpet程式語言的遊戲內API",
|
||||
|
||||
"rule.commandSpawn.name": "刷怪追蹤器",
|
||||
"rule.commandSpawn.desc": "允許使用/spawn指令用於怪物生成追蹤",
|
||||
|
||||
"rule.commandTick.name": "遊戲時鐘控制器",
|
||||
"rule.commandTick.desc": "允許使用/tick指令控制遊戲內的伺服器端運行速度",
|
||||
|
||||
"rule.commandTrackAI.name": "AI追蹤器",
|
||||
"rule.commandTrackAI.desc": "允許使用/track指令以追蹤生物的AI",
|
||||
|
||||
"rule.ctrlQCraftingFix.name": "ctrlQ合成修復",
|
||||
"rule.ctrlQCraftingFix.desc": "在合成時允許使用ctrl+Q快捷鍵扔出結果格內所有物品",
|
||||
|
||||
"rule.customMOTD.name": "MOTD更改",
|
||||
"rule.customMOTD.desc": "設置一個不同的MOTD信息",
|
||||
"rule.customMOTD.extra.0": "設置成'_'時將採用默認的MOTD(從server.properties中讀取的)",
|
||||
|
||||
"rule.defaultLoggers.name": "默認開啟的遊戲數據追蹤器",
|
||||
"rule.defaultLoggers.desc": "為所有新加入的玩家設置部分遊戲數據追蹤器默認為開啟狀態",
|
||||
"rule.defaultLoggers.extra.0": "比如設置'tps,mobcaps'最為默認遊戲數據追蹤",
|
||||
|
||||
"rule.desertShrubs.name": "樹苗在沙漠中乾枯",
|
||||
"rule.desertShrubs.desc": "樹苗將在附近無水源狀態的沙漠生態群系變成枯灌木",
|
||||
|
||||
"rule.disableSpawnChunks.name": "允許出生點區塊被卸載",
|
||||
"rule.disableSpawnChunks.desc": "允許出生點區塊被卸載",
|
||||
|
||||
"rule.explosionNoBlockDamage.name": "爆炸不破壞方塊",
|
||||
"rule.explosionNoBlockDamage.desc": "任何形式的爆炸都無法摧毀方塊",
|
||||
|
||||
"rule.extremeBehaviours.name": "隨機參數極端化",
|
||||
"rule.extremeBehaviours.desc": "大幅度提升極端情況出現的概率,僅用於測試",
|
||||
"rule.extremeBehaviours.extra.0": "發射器和投擲器將使用最大隨機刻",
|
||||
|
||||
"rule.fastRedstoneDust.name": "紅石粉卡頓優化",
|
||||
"rule.fastRedstoneDust.desc": "紅石粉卡頓優化 作者 Theosib",
|
||||
|
||||
"rule.fillLimit.name": "fill/clone上限更改",
|
||||
"rule.fillLimit.desc": "將fill/clone上限更改為自己設定的值",
|
||||
"rule.fillLimit.extra.0": "你必須在1-2千萬之間取一個整數值",
|
||||
|
||||
"rule.fillUpdates.name": "fill更新設置",
|
||||
"rule.fillUpdates.desc": "fill/clone/setblock指令以及結構方塊執行時是否產生更新",
|
||||
"rule.fillUpdates.extra.0": "設置為true時有更新 設置為false時為無更新",
|
||||
|
||||
"rule.flatWorldStructureSpawning.name": "特定建築怪在超平坦世界生成",
|
||||
"rule.flatWorldStructureSpawning.desc": "允許特定建築的怪物在超平坦世界生成",
|
||||
|
||||
"rule.flippinCactus.name": "仙人掌扳手",
|
||||
"rule.flippinCactus.desc": "允許使用仙人掌調整方塊朝向,並且不會造成更新",
|
||||
|
||||
"rule.hardcodeTNTangle.name": "強制TNT角度",
|
||||
"rule.hardcodeTNTangle.desc": "把TNT水平隨機角度設定為固定值,可用於測試機器",
|
||||
"rule.hardcodeTNTangle.extra.0": "默認為-1,必須在0與360之間,或者-1",
|
||||
|
||||
"rule.hopperCounters.name": "漏斗計數器",
|
||||
"rule.hopperCounters.desc": "漏斗指向的羊毛方塊會計算吸收的物品並清除",
|
||||
"rule.hopperCounters.extra.0": "在羊毛方塊上放置紅色或綠色地毯,使用/counter指令可啟用",
|
||||
"rule.hopperCounters.extra.1": "使用 /counter <color?> reset重置計數器,使用/counter <color?>查詢資訊",
|
||||
"rule.hopperCounters.extra.2": "在生存模式,在同色羊毛上放置綠色地毯可以查詢,放紅色地毯重置",
|
||||
"rule.hopperCounters.extra.3": "數據是全伺服器玩家共享的,並且有16色可以使用",
|
||||
"rule.hopperCounters.extra.4": "物品會被銷毀,每個漏斗每tick銷毀一組物品",
|
||||
|
||||
"rule.huskSpawningInTemples.name": "屍殼在沙漠神殿裡生成",
|
||||
"rule.huskSpawningInTemples.desc": "只有屍殼會在沙漠神殿生成",
|
||||
|
||||
"rule.lagFreeSpawning.name": "延遲自然生成",
|
||||
"rule.lagFreeSpawning.desc": "生物生成需要更少的CPU和RAM",
|
||||
|
||||
"rule.leadFix.name": "栓繩修復",
|
||||
"rule.leadFix.desc": "修復栓繩在未加載區塊中,變得不可見的問題",
|
||||
|
||||
"rule.maxEntityCollisions.name": "最大實體擠壓數量",
|
||||
"rule.maxEntityCollisions.desc": "設定最大實體擠壓限制,0表示無限大",
|
||||
|
||||
"rule.mergeTNT.name": "合併TNT",
|
||||
"rule.mergeTNT.desc": "合併靜止的點燃的tnt實體",
|
||||
|
||||
"rule.missingTools.name": "工具缺失修復",
|
||||
"rule.missingTools.desc": "活塞,玻璃和海綿可以使用合適的工具更快地破壞",
|
||||
|
||||
"rule.movableBlockEntities.name": "容器方塊移動",
|
||||
"rule.movableBlockEntities.desc": "活塞可以推動具有容器標籤的方塊,比如箱子,漏斗",
|
||||
|
||||
"rule.onePlayerSleeping.name": "單個玩家睡覺跳過夜晚",
|
||||
"rule.onePlayerSleeping.desc": "只要伺服器中其中一人睡覺即可跳過全伺服器夜晚",
|
||||
|
||||
"rule.optimizedTNT.name": "TNT優化",
|
||||
"rule.optimizedTNT.desc": "tnt在相同位置或者在流體裡,爆炸將造成更低延遲",
|
||||
|
||||
"rule.persistentParrots.name": "鸚鵡停留",
|
||||
"rule.persistentParrots.desc": "鸚鵡不會離開你的肩膀,除非你受到傷害",
|
||||
|
||||
"rule.placementRotationFix.name": "放置旋轉問題修復",
|
||||
"rule.placementRotationFix.desc": "修復玩家放置方塊時快速轉身造成的問題",
|
||||
|
||||
"rule.pushLimit.name": "自訂義推動上限",
|
||||
"rule.pushLimit.desc": "自訂義活塞推動上限",
|
||||
"rule.pushLimit.extra.0": "你必須在1-1024中選取一個值,預設是12",
|
||||
|
||||
"rule.quasiConnectivity.name": "半連接激活開關",
|
||||
"rule.quasiConnectivity.desc": "活塞,發射器和投擲器在他們上方方塊激活時是否響應",
|
||||
"rule.quasiConnectivity.extra.0": "設置為true為開啟 設置為false為禁用",
|
||||
|
||||
"rule.railPowerLimit.name": "自訂義動力鐵軌激活距離",
|
||||
"rule.railPowerLimit.desc": "動力鐵軌激活距離能在此更改",
|
||||
"rule.railPowerLimit.extra.0": "你必須在1-1024中選取一個數值",
|
||||
|
||||
"rule.renewableCoral.name": "可再生珊瑚",
|
||||
"rule.renewableCoral.desc": "使用骨粉可催熟珊瑚以長成珊瑚方塊結構",
|
||||
|
||||
"rule.renewableSponges.name": "可再生海綿",
|
||||
"rule.renewableSponges.desc": "深海守衛將在被雷擊後變成遠古深海守衛",
|
||||
|
||||
"rule.rotatorBlock.name": "仙人掌扳手發射器版",
|
||||
"rule.rotatorBlock.desc": "發射器中的仙人掌可以旋轉方塊(盡可能以逆時針)",
|
||||
|
||||
"rule.scriptsAutoload.name": "Scarpet腳本自動加載",
|
||||
"rule.scriptsAutoload.desc": "在伺服器/世界加載的時候將會自動從世界文件中加載Scarpet腳本文件",
|
||||
"rule.scriptsAutoload.extra.0": "/script指令必須為啟用狀態",
|
||||
|
||||
"rule.shulkerSpawningInEndCities.name": "可重生界伏蚌",
|
||||
"rule.shulkerSpawningInEndCities.desc": "界伏蚌將會在終界城市中重生",
|
||||
|
||||
"rule.silverFishDropGravel.name": "蠹魚鑽出放塊掉落礫石",
|
||||
"rule.silverFishDropGravel.desc": "蠹魚鑽出放塊時會掉落礫石",
|
||||
|
||||
"rule.smoothClientAnimations.name": "更平暢玩家端動畫",
|
||||
"rule.smoothClientAnimations.desc": "降低TPS設置時可以使玩家端動畫更加平暢",
|
||||
"rule.smoothClientAnimations.extra.0": "僅在單人模式中生效,並且會降低玩家端運行速度",
|
||||
|
||||
"rule.stackableShulkerBoxes.name": "可堆疊界伏盒",
|
||||
"rule.stackableShulkerBoxes.desc": "空的界伏盒扔在地上時將會自動堆疊,直到堆疊為1組",
|
||||
"rule.stackableShulkerBoxes.extra.0": "在物品GUI中,請使用shift鍵+單擊以移動整組界伏盒",
|
||||
|
||||
"rule.summonNaturalLightning.name": "召喚閃電自然化",
|
||||
"rule.summonNaturalLightning.desc": "召喚的閃電將具有自然生成時的特性",
|
||||
|
||||
"rule.tntDoNotUpdate.name": "TNT放置時不會被更新",
|
||||
"rule.tntDoNotUpdate.desc": "TNT在放置時不會產生任何方塊更新(不會激活)",
|
||||
|
||||
"rule.tntPrimerMomentumRemoved.name": "移除TNT點燃時隨機動量",
|
||||
"rule.tntPrimerMomentumRemoved.desc": "TNT點燃時的隨機動量將被移除",
|
||||
|
||||
"rule.tntRandomRange.name": "TNT爆炸範圍設置",
|
||||
"rule.tntRandomRange.desc": "設置TNT隨機爆炸範圍為一個固定的值,設為-1以禁用",
|
||||
"rule.tntRandomRange.extra.0": "必須啟用optimizedTNT功能",
|
||||
"rule.tntRandomRange.extra.1": "不能設置為負數,除了-1",
|
||||
|
||||
"rule.unloadedEntityFix.name": "未加載實體修復",
|
||||
"rule.unloadedEntityFix.desc": "進入或者被推入未加載區塊的實體不會消失",
|
||||
|
||||
"rule.viewDistance.name": "自訂義視野",
|
||||
"rule.viewDistance.desc": "改變伺服器端視野距離,設置為0以使用默認值",
|
||||
"rule.viewDistance.extra.0": "你必須在0(使用伺服器默認設置)-32取一個整數",
|
||||
|
||||
"rule.xpNoCooldown.name": "經驗球吸收無冷卻",
|
||||
"rule.xpNoCooldown.desc": "玩家吸收經驗球不會有冷卻時間",
|
||||
|
||||
"rule.portalSuffocationFix.name": "傳送門窒息修復",
|
||||
"rule.portalSuffocationFix.desc": "使地獄傳送門正確地傳送實體",
|
||||
"rule.portalSuffocationFix.extra.0": "傳送的實體將不再卡在黑曜石裡",
|
||||
|
||||
"rule.portalCreativeDelay.name": "創造模式玩家地獄門傳送延遲",
|
||||
"rule.portalCreativeDelay.desc": "創造模式下使用地獄傳送門將同生存時產生延遲",
|
||||
|
||||
|
||||
"category.bugfix": "BUG修復",
|
||||
"category.survival": "生存用",
|
||||
"category.creative": "創造用",
|
||||
"category.experimental": "實驗用",
|
||||
"category.optimization": "優化",
|
||||
"category.feature": "特性",
|
||||
"category.command": "指令",
|
||||
"category.tnt": "TNT",
|
||||
"category.dispenser": "發射器",
|
||||
"category.scarpet": "scarpet腳本程式語言",
|
||||
"category.client": "玩家端",
|
||||
|
||||
"ui.browse_categories": "瀏覽分類",
|
||||
"ui.list_all_%(cat)s_settings": "列出所有 %s 選項",
|
||||
"ui.version": "版本",
|
||||
"ui.current_%(mod)s_settings": "目前啟用的 %s 選項",
|
||||
"ui.switch_to": "切換至",
|
||||
"ui.settings_are_locked": "選項被鎖定",
|
||||
"ui.is_set_to": "被設置為",
|
||||
"ui.unknown_rule": "未知的規則選項",
|
||||
"ui.current_%(mod)s_startup_settings_from_%(conf)s": "目前啟用的%s選項,從%s中讀取得",
|
||||
"ui.%(mod)s_settings_matching_'%(query)s'": "%s中符合\"%s\"的選項:",
|
||||
"ui.all_%(mod)s_settings": "所有的%s選項",
|
||||
"ui.tags": "分類",
|
||||
"ui.change_permanently": "設為預設",
|
||||
"ui.click_to_keep_the_settings_in_%(conf)s_to_save_across_restarts": "點擊此按鈕以使此選項保存於%s,重啟後依舊生效",
|
||||
"ui.rule_%(rule)s_will_now_default_to_%(value)s": "規則%s將會被默認設置為%s",
|
||||
"ui.current_value": "當前的值"
|
||||
|
||||
}
|
||||
@@ -49,6 +49,11 @@ __command() ->
|
||||
print(' "/camera show": Show current path particles');
|
||||
print(' color of particles used is different for different players');
|
||||
print(' "/camera hide": Hide path display');
|
||||
print(' "/camera prefer_smooth_play": ');
|
||||
print(' Eat CPU spikes and continue as usual');
|
||||
print(' "/camera prefer_synced_play": ');
|
||||
print(' After CPU spikes jump to where you should be');
|
||||
|
||||
print('');
|
||||
''
|
||||
);
|
||||
@@ -483,6 +488,11 @@ hide() ->
|
||||
);
|
||||
|
||||
// runs the player on the path
|
||||
global_prefer_sync = false;
|
||||
|
||||
prefer_smooth_play() -> (global_prefer_sync = false; 'Smooth path play');
|
||||
prefer_synced_play() -> (global_prefer_sync = true; 'Synchronized path play');
|
||||
|
||||
play() ->
|
||||
(
|
||||
if (err = __is_not_valid_for_motion(), exit(err));
|
||||
@@ -501,6 +511,7 @@ play() ->
|
||||
global_playing_path = true;
|
||||
mspt = 1000 / 60;
|
||||
start_time = time();
|
||||
very_start = start_time;
|
||||
point = 0;
|
||||
p = __get_player();
|
||||
try (
|
||||
@@ -514,9 +525,14 @@ play() ->
|
||||
modify(p, 'location', v);
|
||||
point += 1;
|
||||
end_time = time();
|
||||
took = end_time - start_time;
|
||||
if (took < mspt, sleep(mspt-took));
|
||||
start_time = time()
|
||||
if (global_prefer_sync,
|
||||
should_be = very_start + mspt*point;
|
||||
if (end_time < should_be, sleep(should_be-end_time) )
|
||||
,
|
||||
took = end_time - start_time;
|
||||
if (took < mspt, sleep(mspt-took));
|
||||
start_time = time()
|
||||
)
|
||||
)
|
||||
);
|
||||
);
|
||||
|
||||
Loaded 100 of 122 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user