Merge branch 'master' of https://github.com/gnembon/fabric-carpet
This commit is contained in:
commit
1aeb07556a
39 files changed
+1339
-312
No files matched your search
+71
-12
@@ -3154,25 +3154,23 @@ Optional shared shape attributes:
|
||||
in the form of `0xRRGGBBAA`, with the default of `-1`, so white opaque, or `0xFFFFFFFF`.
|
||||
* `player` - name or player entity to send the shape to. If specified, the shapes will appear only for the specified
|
||||
player, otherwise it will be send to all players in the dimension.
|
||||
* `width` - line thickness, defaults to 2.0pt
|
||||
* `fill` - color for the faces, defaults to no fill. Use `color` attribute format
|
||||
* `follow` - entity, or player name. Shape will follow an entity instead of being static.
|
||||
Follow attribute requires all positional arguments to be relative to the entity and disallow
|
||||
of using entity or block as position markers. You must specify positions as a triple.
|
||||
|
||||
Available shapes:
|
||||
* `'line'` - draws a straight line between two points
|
||||
* Required attributes:
|
||||
* `from` - triple coordinates, entity, or block value indicating one end of the line
|
||||
* `to` - other end of the line, same format as `from`
|
||||
* Optional attributes:
|
||||
* `width` - line thickness, defaults to 2.0pt
|
||||
* `follow` - entity, or player name. Shape will follow an entity instead of being static.
|
||||
Follow attribute requires all positional arguments to be relative to the entity and disallow
|
||||
of using entity or block as position markers. You must specify positions as a triple.
|
||||
|
||||
* `'box'` - draws a box with corners in specified points
|
||||
* Required attributes:
|
||||
* `from` - triple coordinates, entity, or block value indicating one corner of the box
|
||||
* `to` - other corner, same format as `from`
|
||||
* Optional attributes:
|
||||
* `width` - mesh line thickness, defaults to 2.0pt
|
||||
* `fill` - color for the box faces, defaults to no fill, use shared color attribute format
|
||||
|
||||
* `'sphere'` - draws a sphere
|
||||
* Required attributes:
|
||||
* `center` - center of the sphere
|
||||
@@ -3180,7 +3178,6 @@ Available shapes:
|
||||
* Optional attributes:
|
||||
* `level` - level of details, or grid size. The more the denser your sphere. Default level of 0, means that the
|
||||
level of detail will be selected automatically based on radius.
|
||||
* `width` - line thickness
|
||||
|
||||
### `create_marker(text, pos, rotation?, block?)`
|
||||
|
||||
@@ -3269,6 +3266,63 @@ Example usages:
|
||||
|
||||
Prints the message to system logs, and not to chat.
|
||||
|
||||
### read_file(resource, type)
|
||||
### delete_file(resource, type)
|
||||
### write_file(resource, type, data, ...)
|
||||
|
||||
With the specified `resource` in the scripts folder, of a specific `type`, writes/appends `data` to it, reads its
|
||||
content, or deletes the resource.
|
||||
|
||||
Resource is identified by a path to the file.
|
||||
A path can contain letters, numbers and folder separator: `'/'`. Any other characters are stripped
|
||||
from the name. Empty descriptors are invalid. Do not add file extensions to the descriptor - extensions are inferred
|
||||
based on the `type` of the file.
|
||||
|
||||
Resources can be located in the app specific space, or a shared space for all the apps. Accessing of app-specific
|
||||
resources is guaranteed to be isolated from other apps. Shared resources are... well, shared across all apes, meaning
|
||||
they can eat of each others file, however all access to files is synchronized, and files are never left open, so
|
||||
this should not lead to any access problems.
|
||||
|
||||
If the app's name is `'foo'`, the script location would
|
||||
be `world/scripts/foo.sc`, app
|
||||
specific data directory is under `world/scripts/foo.data/...`, and shared data space is under
|
||||
`world/scripts/shared/...`.
|
||||
|
||||
The default no-name app, via `/script run` command can only save/load/read files from the shared space.
|
||||
|
||||
Functions return `null` if an error is encounter or no file is present (for read and delete operations). Returns `true`
|
||||
for success writes and deletes, and requested data, based on the file type, for read operations.
|
||||
|
||||
NBT files can be written once as they an store one tag at a time. Consecutive writes will overwrite previous data.
|
||||
|
||||
Write operations to text files always result in appending to the existing file, so consecutive writes will increase
|
||||
the size of the file and add data to it. Since files are closed after each write, sending multiple lines of data to
|
||||
write is beneficial for writing speed. To send multiple packs of data, either provide them flat or as a list in the
|
||||
third argument.
|
||||
* `write_file('temp', 'text', 'foo', 'bar', 'baz')` or
|
||||
* write_file('temp', 'text', l('foo', 'bar', 'baz'))
|
||||
|
||||
To log a single line of string
|
||||
|
||||
Supported values for resource `type` is:
|
||||
* `nbt` - NBT tag
|
||||
* `text` - text resource with automatic newlines added
|
||||
* `raw` - text resource without implied newlines
|
||||
* `shared_nbt`, `shared_text`, `shared_raw` - shared versions of the above
|
||||
|
||||
NBT files have extension `.nbt`, store one NBT tag, and return a NBT type value. Text files have `.txt` extension,
|
||||
stores multiple lines of text and returns lists of all lines from the file. With `write_file`, multiple lines can be
|
||||
sent to the file at once. The only difference between `raw` and `text` types are automatic newlines added after each
|
||||
record to the file.
|
||||
|
||||
<pre>
|
||||
write_file('foo', 'shared_text, l('one', 'two'));
|
||||
write_file('foo', 'shared_text', 'three\n', 'four\n');
|
||||
write_file('foo', 'shared_raw', 'five\n', 'six\n');
|
||||
|
||||
read_file('foo', 'shared_text') => ['one', 'two', 'three', '', 'four', '', 'five', 'six']
|
||||
</pre>
|
||||
|
||||
### `run(expr)`
|
||||
|
||||
Runs a vanilla command from the string result of the `expr` and returns its success count
|
||||
@@ -3283,7 +3337,10 @@ run('give @s stone 4') -> 1 // this operation was successful once
|
||||
Performs autosave, saves all chunks, player data, etc. Useful for programs where autosave is disabled due to
|
||||
performance reasons and saves the world only on demand.
|
||||
|
||||
### `load_app_data(), load_app_data(file), load_app_data(file, shared?)`
|
||||
### `load_app_data()`
|
||||
|
||||
NOTE: usages with arguments, so `load_app_data(file)` and `load_app_data(file, shared?)` are deprecated.
|
||||
Use `read_file` instead.
|
||||
|
||||
Loads the app data associated with the app from the world /scripts folder. Without argument returns the memory
|
||||
managed and buffered / throttled NBT tag. With a file name, reads explicitly a file with that name from the
|
||||
@@ -3291,7 +3348,7 @@ scripts folder that belongs exclusively to the app. if `shared` is true, the fil
|
||||
to the app anymore, but located in a shared app space.
|
||||
|
||||
File descriptor can contain letters, numbers and folder separator: `'/'`. Any other characters are stripped
|
||||
from the name before saving/loading. Empty descriptors are invalid.
|
||||
from the name before saving/loading. Empty descriptors are invalid. Do not add file extensions to the descriptor
|
||||
|
||||
Function returns nbt value with the file content, or `null` if the file is missing or there were problems
|
||||
with retrieving the data.
|
||||
@@ -3305,7 +3362,9 @@ specific data directory is under `world/scripts/foo.data/bar/../baz.nbt`, and sh
|
||||
|
||||
You can use app data to save non-vanilla information separately from the world and other scripts.
|
||||
|
||||
### `store_app_data(tag), store_app_data(tag, file), store_app_data(tag, file, shared?)`
|
||||
### `store_app_data(tag)`
|
||||
|
||||
Note: `store_app_data(tag, file)` and `store_app_data(tag, file, shared?)` usages deprecated. Use `write_file` instead.
|
||||
|
||||
Stores the app data associated with the app from the world `/scripts` folder. With the `file` parameter saves
|
||||
immediately and with every call to a specific file defined by the `file`, either in app space, or in the scripts
|
||||
|
||||
@@ -172,6 +172,63 @@ Example usages:
|
||||
|
||||
Prints the message to system logs, and not to chat.
|
||||
|
||||
### read_file(resource, type)
|
||||
### delete_file(resource, type)
|
||||
### write_file(resource, type, data, ...)
|
||||
|
||||
With the specified `resource` in the scripts folder, of a specific `type`, writes/appends `data` to it, reads its
|
||||
content, or deletes the resource.
|
||||
|
||||
Resource is identified by a path to the file.
|
||||
A path can contain letters, numbers and folder separator: `'/'`. Any other characters are stripped
|
||||
from the name. Empty descriptors are invalid. Do not add file extensions to the descriptor - extensions are inferred
|
||||
based on the `type` of the file.
|
||||
|
||||
Resources can be located in the app specific space, or a shared space for all the apps. Accessing of app-specific
|
||||
resources is guaranteed to be isolated from other apps. Shared resources are... well, shared across all apes, meaning
|
||||
they can eat of each others file, however all access to files is synchronized, and files are never left open, so
|
||||
this should not lead to any access problems.
|
||||
|
||||
If the app's name is `'foo'`, the script location would
|
||||
be `world/scripts/foo.sc`, app
|
||||
specific data directory is under `world/scripts/foo.data/...`, and shared data space is under
|
||||
`world/scripts/shared/...`.
|
||||
|
||||
The default no-name app, via `/script run` command can only save/load/read files from the shared space.
|
||||
|
||||
Functions return `null` if an error is encounter or no file is present (for read and delete operations). Returns `true`
|
||||
for success writes and deletes, and requested data, based on the file type, for read operations.
|
||||
|
||||
NBT files can be written once as they an store one tag at a time. Consecutive writes will overwrite previous data.
|
||||
|
||||
Write operations to text files always result in appending to the existing file, so consecutive writes will increase
|
||||
the size of the file and add data to it. Since files are closed after each write, sending multiple lines of data to
|
||||
write is beneficial for writing speed. To send multiple packs of data, either provide them flat or as a list in the
|
||||
third argument.
|
||||
* `write_file('temp', 'text', 'foo', 'bar', 'baz')` or
|
||||
* write_file('temp', 'text', l('foo', 'bar', 'baz'))
|
||||
|
||||
To log a single line of string
|
||||
|
||||
Supported values for resource `type` is:
|
||||
* `nbt` - NBT tag
|
||||
* `text` - text resource with automatic newlines added
|
||||
* `raw` - text resource without implied newlines
|
||||
* `shared_nbt`, `shared_text`, `shared_raw` - shared versions of the above
|
||||
|
||||
NBT files have extension `.nbt`, store one NBT tag, and return a NBT type value. Text files have `.txt` extension,
|
||||
stores multiple lines of text and returns lists of all lines from the file. With `write_file`, multiple lines can be
|
||||
sent to the file at once. The only difference between `raw` and `text` types are automatic newlines added after each
|
||||
record to the file.
|
||||
|
||||
<pre>
|
||||
write_file('foo', 'shared_text, l('one', 'two'));
|
||||
write_file('foo', 'shared_text', 'three\n', 'four\n');
|
||||
write_file('foo', 'shared_raw', 'five\n', 'six\n');
|
||||
|
||||
read_file('foo', 'shared_text') => ['one', 'two', 'three', '', 'four', '', 'five', 'six']
|
||||
</pre>
|
||||
|
||||
### `run(expr)`
|
||||
|
||||
Runs a vanilla command from the string result of the `expr` and returns its success count
|
||||
@@ -186,7 +243,10 @@ run('give @s stone 4') -> 1 // this operation was successful once
|
||||
Performs autosave, saves all chunks, player data, etc. Useful for programs where autosave is disabled due to
|
||||
performance reasons and saves the world only on demand.
|
||||
|
||||
### `load_app_data(), load_app_data(file), load_app_data(file, shared?)`
|
||||
### `load_app_data()`
|
||||
|
||||
NOTE: usages with arguments, so `load_app_data(file)` and `load_app_data(file, shared?)` are deprecated.
|
||||
Use `read_file` instead.
|
||||
|
||||
Loads the app data associated with the app from the world /scripts folder. Without argument returns the memory
|
||||
managed and buffered / throttled NBT tag. With a file name, reads explicitly a file with that name from the
|
||||
@@ -194,7 +254,7 @@ scripts folder that belongs exclusively to the app. if `shared` is true, the fil
|
||||
to the app anymore, but located in a shared app space.
|
||||
|
||||
File descriptor can contain letters, numbers and folder separator: `'/'`. Any other characters are stripped
|
||||
from the name before saving/loading. Empty descriptors are invalid.
|
||||
from the name before saving/loading. Empty descriptors are invalid. Do not add file extensions to the descriptor
|
||||
|
||||
Function returns nbt value with the file content, or `null` if the file is missing or there were problems
|
||||
with retrieving the data.
|
||||
@@ -208,7 +268,9 @@ specific data directory is under `world/scripts/foo.data/bar/../baz.nbt`, and sh
|
||||
|
||||
You can use app data to save non-vanilla information separately from the world and other scripts.
|
||||
|
||||
### `store_app_data(tag), store_app_data(tag, file), store_app_data(tag, file, shared?)`
|
||||
### `store_app_data(tag)`
|
||||
|
||||
Note: `store_app_data(tag, file)` and `store_app_data(tag, file, shared?)` usages deprecated. Use `write_file` instead.
|
||||
|
||||
Stores the app data associated with the app from the world `/scripts` folder. With the `file` parameter saves
|
||||
immediately and with every call to a specific file defined by the `file`, either in app space, or in the scripts
|
||||
|
||||
@@ -314,6 +314,13 @@ query(p,'effect','resistance') => null
|
||||
|
||||
Number indicating remaining entity health, or `null` if not applicable.
|
||||
|
||||
### `query(e, 'hunger')`
|
||||
### `query(e, 'saturation')`
|
||||
### `query(e, 'exhaustion')`
|
||||
|
||||
Retrieves player hunger related information. For non-players, returns `null`.
|
||||
|
||||
|
||||
### `query(e, 'holds', slot?)`
|
||||
|
||||
Returns triple of short name, stack count, and NBT of item held in `slot`, or `null` if nothing or not applicable. Available options for `slot` are:
|
||||
@@ -514,6 +521,17 @@ Toggles gravity for the entity.
|
||||
|
||||
Will set entity on fire for `ticks` ticks. Set to 0 to extinguish.
|
||||
|
||||
### `modify(e, 'hunger', value)`
|
||||
### `modify(e, 'saturation', value)`
|
||||
### `modify(e, 'exhaustion', value)`
|
||||
|
||||
Modifies directly player raw hunger components. Has no effect on non-players
|
||||
|
||||
### `modify(e, 'add_exhaustion', value)`
|
||||
|
||||
adds exhaustion value to the current player exhaustion level - that's the method you probably want to use
|
||||
to manipulate how much 'food' some action cost.
|
||||
|
||||
## Entity Events
|
||||
|
||||
There is a number of events that happen to entities that you can attach your own code to in the form of event handlers.
|
||||
|
||||
@@ -4,7 +4,12 @@
|
||||
|
||||
Most functions in this category require inventory as the first argument. Inventory could be specified by an entity,
|
||||
or a block, or position (three coordinates) of a potential block with inventory. Player enderchest inventory require
|
||||
two arguments, keyword `'enderchest'`, followed by the player entity argument. If the entity or a block doesn't have
|
||||
two arguments, keyword `'enderchest'`, followed by the player entity argument, or a single argument as a string of a
|
||||
form: `'enderchest_steve'`. If your player name starts with enderchest, it can be always accessed by passing a player
|
||||
entity value. If all else fails, it will try to identify first three arguments as coordinates of a block position of
|
||||
a block inventory. Player inventories can also be called by their name.
|
||||
|
||||
If the entity or a block doesn't have
|
||||
an inventory, they typically do nothing and return null.
|
||||
|
||||
Most items returned are in the form of a triple of item name, count, and nbt or the extra data associated with an item.
|
||||
|
||||
+3
-3
@@ -5,11 +5,11 @@ org.gradle.jvmargs=-Xmx1G
|
||||
# check these on https://fabricmc.net/use
|
||||
# or better: https://modmuss50.me/fabric.html
|
||||
minecraft_version=1.15.2
|
||||
yarn_mappings=1.15.2+build.15
|
||||
loader_version=0.8.3+build.196
|
||||
yarn_mappings=1.15.2+build.17
|
||||
loader_version=0.8.7+build.201
|
||||
|
||||
# Mod Properties
|
||||
mod_version = 1.3.26+v200604
|
||||
mod_version = 1.3.27+v200605
|
||||
maven_group = carpet
|
||||
archives_base_name = fabric-carpet
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ 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();
|
||||
|
||||
@@ -34,7 +34,7 @@ import static carpet.settings.RuleCategory.CLIENT;
|
||||
@SuppressWarnings("CanBeFinal")
|
||||
public class CarpetSettings
|
||||
{
|
||||
public static final String carpetVersion = "1.3.26+v200604";
|
||||
public static final String carpetVersion = "1.3.27+v200605";
|
||||
public static final Logger LOG = LogManager.getLogger();
|
||||
public static boolean skipGenerationChecks = false;
|
||||
public static boolean impendingFillSkipUpdates = false;
|
||||
@@ -501,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
|
||||
@@ -549,6 +549,7 @@ public class CarpetSettings
|
||||
//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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
@@ -195,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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -80,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();
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package carpet.fakes;
|
||||
|
||||
public interface HungerManagerInterface {
|
||||
float getExhaustionCM();
|
||||
void setExhaustionCM(float exhaust);
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -7,10 +7,10 @@ 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
|
||||
@@ -21,7 +21,7 @@ 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;
|
||||
@@ -68,13 +68,14 @@ public class TickSpeed
|
||||
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)
|
||||
|
||||
@@ -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,156 @@
|
||||
package carpet.logging.logHelpers;
|
||||
|
||||
import carpet.logging.LoggerRegistry;
|
||||
import carpet.utils.Messenger;
|
||||
import com.google.common.collect.Lists;
|
||||
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.List;
|
||||
|
||||
public class ExplosionLogHelper
|
||||
{
|
||||
private final boolean createFire;
|
||||
private final Explosion.DestructionType blockDestructionType;
|
||||
public final double x;
|
||||
public final double y;
|
||||
public final double z;
|
||||
public final Entity entity;
|
||||
private final float power;
|
||||
private boolean affectBlocks = false;
|
||||
private List<EntityChangedStatusWithCount> entityChangedStatusWithCount = Lists.newArrayList();
|
||||
|
||||
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.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.createFire = createFire;
|
||||
this.blockDestructionType = blockDestructionType;
|
||||
}
|
||||
|
||||
public void setAffectBlocks(boolean b)
|
||||
{
|
||||
affectBlocks = b;
|
||||
}
|
||||
|
||||
public void onExplosionDone(long gametime)
|
||||
{
|
||||
BaseText timeDisplay;
|
||||
if (!(lastGametime == gametime)){
|
||||
explosionCountInCurretGT = 0;
|
||||
lastGametime = gametime;
|
||||
timeDisplay = Messenger.c("wb " + ">>>>>> CURRENT GAME TIME : ", "d " + gametime, "wb >>>>>>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
timeDisplay = Messenger.s("");
|
||||
}
|
||||
explosionCountInCurretGT++;
|
||||
LoggerRegistry.getLogger("explosions").log( (option) -> {
|
||||
switch (option)
|
||||
{
|
||||
case "brief":
|
||||
return new BaseText[]{Messenger.c(
|
||||
timeDisplay, "gb EXPLOSION", "d #" + explosionCountInCurretGT,"gb -> ",
|
||||
"w P: ", "d ",Messenger.dblt("l",x ,y ,z),
|
||||
"w affectBlocks: ", "m " + this.affectBlocks
|
||||
)};
|
||||
case "full":
|
||||
return new BaseText[]{Messenger.c(
|
||||
timeDisplay, "gb EXPLOSION", "d #" + explosionCountInCurretGT,"gb -> ",
|
||||
"w P: ", "d ",Messenger.dblt("l",x ,y ,z),
|
||||
"w createFire: ", "m " + this.createFire,
|
||||
"w power: ", "c " + this.power,
|
||||
"w destructionType: ", "c " + this.blockDestructionType.name(),
|
||||
"w affectBlocks: ", "m " + this.affectBlocks,
|
||||
"b \n", ListToText()
|
||||
)};
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public void onEntityImpacted(Entity entity, Vec3d deltaVelocity)
|
||||
{
|
||||
for (EntityChangedStatusWithCount e : entityChangedStatusWithCount)
|
||||
{
|
||||
if (e.checkIfEquals(entity, deltaVelocity))
|
||||
{
|
||||
e.count++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
entityChangedStatusWithCount.add(new EntityChangedStatusWithCount(entity.getPos(), entity.getType(), deltaVelocity));
|
||||
}
|
||||
|
||||
public BaseText ListToText()
|
||||
{
|
||||
BaseText s = Messenger.s("Entities Impacted:\n");
|
||||
for (EntityChangedStatusWithCount entityChanges : entityChangedStatusWithCount)
|
||||
{
|
||||
s.append(entityChanges.asText());
|
||||
s.append("\n");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
public static class EntityChangedStatusWithCount
|
||||
{
|
||||
public final Vec3d entityPos;
|
||||
public final EntityType entityType;
|
||||
public final Vec3d deltaSpeed;
|
||||
public int count;
|
||||
public EntityChangedStatusWithCount(Vec3d entityPos, EntityType entityType, Vec3d deltaSpeed)
|
||||
{
|
||||
this.entityPos = entityPos;
|
||||
this.entityType = entityType;
|
||||
this.deltaSpeed = deltaSpeed;
|
||||
this.count = 1;
|
||||
}
|
||||
|
||||
public boolean equals(EntityChangedStatusWithCount e)
|
||||
{
|
||||
return (
|
||||
e.entityType == this.entityType &&
|
||||
e.deltaSpeed.equals(this.deltaSpeed) &&
|
||||
e.entityPos.equals(this.entityPos)
|
||||
);
|
||||
}
|
||||
|
||||
public boolean checkIfEquals(Entity e, Vec3d deltaSpeed)
|
||||
{
|
||||
return (
|
||||
e.getType() == this.entityType &&
|
||||
deltaSpeed.equals(this.deltaSpeed) &&
|
||||
e.getPos().equals(this.entityPos)
|
||||
);
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return String.format("{EntityType: %s, EntityPos: %s ,DeltaSpeed: %s}", entityType.getName().asString(), entityPos.toString(), deltaSpeed.toString());
|
||||
}
|
||||
|
||||
public BaseText asText()
|
||||
{
|
||||
return Messenger.c(
|
||||
"m Entity(count="+ this.count +") of",
|
||||
"l " + Registry.ENTITY_TYPE.getId(entityType), "g {",
|
||||
"w P: ", "y ", Messenger.dblt("t", entityPos.x, entityPos.y, entityPos.z),
|
||||
"w dV: ", "gbi " + (deltaSpeed.equals(new Vec3d(0,-0.9923437498509884d, 0)) ? "<TNTs-AT-SAME-SPOT>":""),"y ", Messenger.dblt("d", deltaSpeed.x, deltaSpeed.y, deltaSpeed.z),
|
||||
"g }"
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,7 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.network.CarpetClient;
|
||||
import carpet.script.utils.ShapesRenderer;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.render.debug.DebugRenderer;
|
||||
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;
|
||||
@@ -14,25 +10,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
@Mixin(DebugRenderer.class)
|
||||
public class DebugRenderer_scarpetRenderMixin
|
||||
{
|
||||
private ShapesRenderer shapes;
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void addRenderers(MinecraftClient client, CallbackInfo ci)
|
||||
{
|
||||
shapes = new ShapesRenderer(client);
|
||||
CarpetClient.shapes = shapes;
|
||||
}
|
||||
|
||||
@Inject(method = "reset", at = @At("HEAD"))
|
||||
private void resetScarpetRenderes(CallbackInfo ci)
|
||||
{
|
||||
shapes.reset();
|
||||
if (CarpetClient.shapes != null)
|
||||
CarpetClient.shapes.reset();
|
||||
}
|
||||
|
||||
@Inject(method = "render", at = @At("HEAD"))
|
||||
private void renderScarpetThings(MatrixStack matrices, VertexConsumerProvider.Immediate vertexConsumers, double cameraX, double cameraY, double cameraZ, CallbackInfo ci)
|
||||
{
|
||||
shapes.render(matrices, vertexConsumers, cameraX, cameraY, cameraZ);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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,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);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ 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;
|
||||
@@ -35,10 +36,14 @@ public class ClientNetworkHandler
|
||||
}
|
||||
});
|
||||
put("TickRate", (p, t) -> TickSpeed.tickrate(((AbstractNumberTag)t).getFloat(), false));
|
||||
put("scShape", (p, t) -> {
|
||||
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);
|
||||
});
|
||||
}};
|
||||
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ 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;
|
||||
@@ -51,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
|
||||
{
|
||||
@@ -652,8 +654,9 @@ public class CarpetEventServer
|
||||
}
|
||||
|
||||
|
||||
public CarpetEventServer()
|
||||
public CarpetEventServer(MinecraftServer server)
|
||||
{
|
||||
this.server = server;
|
||||
for (Event e: Event.values())
|
||||
e.handler.callList.clear();
|
||||
}
|
||||
|
||||
@@ -2476,6 +2476,18 @@ public class CarpetExpression
|
||||
|
||||
}
|
||||
|
||||
public static String recognizeResource(Value value)
|
||||
{
|
||||
String origfile = value.getString();
|
||||
String file = origfile.toLowerCase(Locale.ROOT).replaceAll("[^A-Za-z0-9/]", "");
|
||||
file = Arrays.stream(file.split("/+")).filter(s -> !s.isEmpty()).collect(Collectors.joining("/"));
|
||||
if (file.isEmpty())
|
||||
{
|
||||
throw new InternalExpressionException("Cannot use "+origfile+" as resource name - must have some letters and numbers");
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
private void API_AuxiliaryAspects()
|
||||
{
|
||||
this.expr.addLazyFunction("sound", -1, (c, t, lv) -> {
|
||||
@@ -2650,47 +2662,28 @@ public class CarpetExpression
|
||||
this.expr.addLazyFunction("draw_shape", -1, (c, t, lv) ->
|
||||
{
|
||||
CarpetContext cc = (CarpetContext)c;
|
||||
if (lv.size() < 3) throw new InternalExpressionException("'draw_shape' takes at least three parameters, shape name, duration, and its params");
|
||||
String shapeType = lv.get(0).evalValue(c).getString();
|
||||
Value duration = NumericValue.asNumber(lv.get(1).evalValue(c));
|
||||
Map<String, Value> params;
|
||||
if (lv.size() == 3)
|
||||
ServerPlayerEntity player[] = {null};
|
||||
List<Pair<ShapeDispatcher.ExpiringShape, Map<String,Value>>> shapes = new ArrayList<>();
|
||||
if (lv.size() == 1) // bulk
|
||||
{
|
||||
Value paramValue = lv.get(2).evalValue(c);
|
||||
if (paramValue instanceof MapValue)
|
||||
Value specLoad = lv.get(0).evalValue(c);
|
||||
if (!(specLoad instanceof ListValue)) throw new InternalExpressionException("In bulk mode - shapes need to be provided as a list of shape specs");
|
||||
for (Value list : ((ListValue) specLoad).getItems())
|
||||
{
|
||||
params = new HashMap<>();
|
||||
((MapValue) paramValue).getMap().entrySet().forEach(e -> params.put(e.getKey().getString(),e.getValue()));
|
||||
if (!(list instanceof ListValue)) throw new InternalExpressionException("In bulk mode - shapes need to be provided as a list of shape specs");
|
||||
shapes.add( ShapeDispatcher.fromFunctionArgs(cc, ((ListValue) list).getItems(), player));
|
||||
}
|
||||
else if (paramValue instanceof ListValue)
|
||||
{
|
||||
params = ShapeDispatcher.parseParams(((ListValue) paramValue).getItems());
|
||||
}
|
||||
else throw new InternalExpressionException("Parameters for 'draw_shape' need to be defined either in a list or a map");
|
||||
}
|
||||
else
|
||||
{
|
||||
List<Value> paramList = new ArrayList<>();
|
||||
for (int i=2; i < lv.size(); i++) paramList.add(lv.get(i).evalValue(c));
|
||||
params = ShapeDispatcher.parseParams(paramList);
|
||||
List<Value> params = new ArrayList<>();
|
||||
for (LazyValue v : lv) params.add(v.evalValue(c));
|
||||
shapes.add(ShapeDispatcher.fromFunctionArgs(cc, params, player));
|
||||
}
|
||||
params.putIfAbsent("dim", new StringValue(cc.s.getWorld().getDimension().getType().toString()));
|
||||
params.putIfAbsent("duration", duration);
|
||||
ServerPlayerEntity player = null;
|
||||
if (params.containsKey("player"))
|
||||
{
|
||||
player = EntityValue.getPlayerByValue(cc.s.getMinecraftServer(), params.get("player"));
|
||||
if (player == null)
|
||||
throw new InternalExpressionException("'player' parameter needs to represent an existing player");
|
||||
params.remove("player");
|
||||
}
|
||||
|
||||
ShapeDispatcher.ExpiringShape shape = ShapeDispatcher.create(cc, shapeType, params);
|
||||
|
||||
ShapeDispatcher.sendShape(
|
||||
(player==null)?cc.s.getWorld().getPlayers():Collections.singletonList(player),
|
||||
shape,
|
||||
params
|
||||
(player[0]==null)?cc.s.getWorld().getPlayers():Collections.singletonList(player[0]),
|
||||
shapes
|
||||
);
|
||||
return LazyValue.TRUE;
|
||||
});
|
||||
@@ -2864,13 +2857,6 @@ public class CarpetExpression
|
||||
// implmenetation should dock the task on the main thread.
|
||||
});
|
||||
|
||||
this.expr.addLazyFunction("logger", 1, (c, t, lv) ->
|
||||
{
|
||||
Value res = lv.get(0).evalValue(c);
|
||||
CarpetSettings.LOG.error(res.getString());
|
||||
return (_c, _t) -> res; // pass through for variables
|
||||
});
|
||||
|
||||
this.expr.addLazyFunction("run", 1, (c, t, lv) -> {
|
||||
BlockPos target = ((CarpetContext)c).origin;
|
||||
Vec3d posf = new Vec3d((double)target.getX()+0.5D,(double)target.getY(),(double)target.getZ()+0.5D);
|
||||
@@ -3057,25 +3043,108 @@ public class CarpetExpression
|
||||
return (c_, t_) -> Value.TRUE;
|
||||
});
|
||||
|
||||
this.expr.addLazyFunction("logger", 1, (c, t, lv) ->
|
||||
{
|
||||
Value res = lv.get(0).evalValue(c);
|
||||
CarpetSettings.LOG.error(res.getString());
|
||||
return (_c, _t) -> res; // pass through for variables
|
||||
});
|
||||
|
||||
this.expr.addLazyFunction("read_file", 2, (c, t, lv) -> {
|
||||
String resource = recognizeResource(lv.get(0).evalValue(c));
|
||||
String origtype = lv.get(1).evalValue(c).getString().toLowerCase(Locale.ROOT);
|
||||
boolean shared = origtype.startsWith("shared_");
|
||||
String type = shared ? origtype.substring(7) : origtype; //len(shared_)
|
||||
if (!type.equals("raw") && !type.equals("text") && !type.equals("nbt"))
|
||||
throw new InternalExpressionException("Unsupported file type: "+origtype);
|
||||
Value retVal;
|
||||
if (type.equals("nbt"))
|
||||
{
|
||||
Tag state = ((CarpetScriptHost)((CarpetContext)c).host).readFileTag(resource, shared);
|
||||
if (state == null) return LazyValue.NULL;
|
||||
retVal = new NBTSerializableValue(state);
|
||||
}
|
||||
else
|
||||
{
|
||||
List<String> content = ((CarpetScriptHost) ((CarpetContext) c).host).readTextResource(resource, shared);
|
||||
if (content == null) return LazyValue.NULL;
|
||||
retVal = ListValue.wrap(content.stream().map(StringValue::new).collect(Collectors.toList()));
|
||||
}
|
||||
return (cc, tt) -> retVal;
|
||||
});
|
||||
|
||||
this.expr.addLazyFunction("delete_file", 2, (c, t, lv) -> {
|
||||
String resource = recognizeResource(lv.get(0).evalValue(c));
|
||||
String origtype = lv.get(1).evalValue(c).getString().toLowerCase(Locale.ROOT);
|
||||
boolean shared = origtype.startsWith("shared_");
|
||||
String type = shared ? origtype.substring(7) : origtype; //len(shared_)
|
||||
if (!type.equals("raw") && !type.equals("text") && !type.equals("nbt"))
|
||||
throw new InternalExpressionException("Unsupported file type: "+origtype);
|
||||
boolean success = ((CarpetScriptHost)((CarpetContext)c).host).removeResourceFile(resource, shared, type);
|
||||
return success?LazyValue.TRUE:LazyValue.FALSE;
|
||||
});
|
||||
|
||||
this.expr.addLazyFunction("write_file", -1, (c, t, lv) -> {
|
||||
if (lv.size() < 3) throw new InternalExpressionException("'write_file' requires three or more arguments");
|
||||
String resource = recognizeResource(lv.get(0).evalValue(c));
|
||||
String origtype = lv.get(1).evalValue(c).getString().toLowerCase(Locale.ROOT);
|
||||
boolean shared = origtype.startsWith("shared_");
|
||||
String type = shared ? origtype.substring(7) : origtype; //len(shared_)
|
||||
if (!type.equals("raw") && !type.equals("text") && !type.equals("nbt"))
|
||||
throw new InternalExpressionException("Unsupported file type: "+origtype);
|
||||
boolean success;
|
||||
if (type.equals("nbt"))
|
||||
{
|
||||
Value val = lv.get(2).evalValue(c);
|
||||
NBTSerializableValue tagValue = (val instanceof NBTSerializableValue)
|
||||
? (NBTSerializableValue) val
|
||||
: new NBTSerializableValue(val.getString());
|
||||
Tag tag = tagValue.getTag();
|
||||
success = ((CarpetScriptHost)((CarpetContext)c).host).writeTagFile(tag, resource, shared);
|
||||
}
|
||||
else
|
||||
{
|
||||
List<String> data = new ArrayList<>();
|
||||
if (lv.size()==3)
|
||||
{
|
||||
Value val = lv.get(2).evalValue(c);
|
||||
if (val instanceof ListValue)
|
||||
{
|
||||
List<Value> lval = ((ListValue) val).getItems();
|
||||
lval.forEach(v -> data.add(v.getString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
data.add(val.getString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i = 2; i < lv.size(); i++)
|
||||
{
|
||||
data.add(lv.get(i).evalValue(c).getString());
|
||||
}
|
||||
}
|
||||
success = ((CarpetScriptHost) ((CarpetContext) c).host).appendLogFile(resource, shared, type, data);
|
||||
}
|
||||
return success?LazyValue.TRUE:LazyValue.FALSE;
|
||||
});
|
||||
|
||||
//write_file
|
||||
|
||||
this.expr.addLazyFunction("load_app_data", -1, (c, t, lv) ->
|
||||
{
|
||||
String file = null;
|
||||
boolean shared = false;
|
||||
if (lv.size()>0)
|
||||
{
|
||||
String origfile = lv.get(0).evalValue(c).getString();
|
||||
file = origfile.toLowerCase(Locale.ROOT).replaceAll("[^A-Za-z0-9/]", "");
|
||||
file = Arrays.stream(file.split("/+")).filter(s -> !s.isEmpty()).collect(Collectors.joining("/"));
|
||||
if (file.isEmpty())
|
||||
{
|
||||
throw new InternalExpressionException("Cannot use "+origfile+" as resource name - must have at least some letters and numbers");
|
||||
}
|
||||
file = recognizeResource(lv.get(0).evalValue(c));
|
||||
if (lv.size() > 1)
|
||||
{
|
||||
shared = lv.get(1).evalValue(c).getBoolean();
|
||||
}
|
||||
}
|
||||
Tag state = ((CarpetScriptHost)((CarpetContext)c).host).getGlobalState(file, shared);
|
||||
Tag state = ((CarpetScriptHost)((CarpetContext)c).host).readFileTag(file, shared);
|
||||
if (state == null)
|
||||
return (cc, tt) -> Value.NULL;
|
||||
Value retVal = new NBTSerializableValue(state);
|
||||
@@ -3091,13 +3160,7 @@ public class CarpetExpression
|
||||
boolean shared = false;
|
||||
if (lv.size()>1)
|
||||
{
|
||||
String origfile = lv.get(1).evalValue(c).getString();
|
||||
file = origfile.toLowerCase(Locale.ROOT).replaceAll("[^A-Za-z0-9/]", "");
|
||||
file = Arrays.stream(file.split("/+")).filter(s -> !s.isEmpty()).collect(Collectors.joining("/"));
|
||||
if (file.isEmpty())
|
||||
{
|
||||
throw new InternalExpressionException("Cannot use "+origfile+" as resource name - must have some letters and numbers");
|
||||
}
|
||||
file = recognizeResource(lv.get(1).evalValue(c));
|
||||
if (lv.size() > 2)
|
||||
{
|
||||
shared = lv.get(2).evalValue(c).getBoolean();
|
||||
@@ -3107,7 +3170,7 @@ public class CarpetExpression
|
||||
? (NBTSerializableValue) val
|
||||
: new NBTSerializableValue(val.getString());
|
||||
Tag tag = tagValue.getTag();
|
||||
boolean success = ((CarpetScriptHost)((CarpetContext)c).host).setGlobalState(tag, file, shared);
|
||||
boolean success = ((CarpetScriptHost)((CarpetContext)c).host).writeTagFile(tag, file, shared);
|
||||
return success?LazyValue.TRUE:LazyValue.FALSE;
|
||||
});
|
||||
|
||||
|
||||
@@ -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)))
|
||||
{
|
||||
@@ -369,7 +369,7 @@ public class CarpetScriptHost extends ScriptHost
|
||||
return Module.getData(main, null, false);
|
||||
}
|
||||
|
||||
public Tag getGlobalState(String file, boolean isShared)
|
||||
public Tag readFileTag(String file, boolean isShared)
|
||||
{
|
||||
if (getName() == null && !isShared) return null;
|
||||
if (file != null)
|
||||
@@ -379,7 +379,7 @@ public class CarpetScriptHost extends ScriptHost
|
||||
return ((CarpetScriptHost)parent).globalState;
|
||||
}
|
||||
|
||||
public boolean setGlobalState(Tag tag, String file, boolean isShared)
|
||||
public boolean writeTagFile(Tag tag, String file, boolean isShared)
|
||||
{
|
||||
if (getName() == null && !isShared) return false; // if belongs to an app, cannot be default host.
|
||||
|
||||
@@ -398,6 +398,25 @@ public class CarpetScriptHost extends ScriptHost
|
||||
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)
|
||||
|
||||
@@ -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;
|
||||
@@ -49,14 +51,15 @@ public class CarpetScriptServer
|
||||
add(new BundledModule("math", true));
|
||||
}};
|
||||
|
||||
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 +67,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 +78,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 +113,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 +226,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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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')
|
||||
{
|
||||
|
||||
@@ -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
|
||||
@@ -96,4 +103,44 @@ public class FileModule extends Module
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,15 +5,14 @@ import net.minecraft.nbt.Tag;
|
||||
|
||||
import java.io.File;
|
||||
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();
|
||||
|
||||
private static String getDescriptor(Module module, String file, boolean isShared)
|
||||
{
|
||||
@@ -33,20 +32,48 @@ public abstract class Module
|
||||
|
||||
public static Tag getData(Module module, String file, boolean isShared)
|
||||
{
|
||||
if (!isShared && (module == null || module.getName() == null)) return null;
|
||||
File dataFile = CarpetServer.minecraft_server.getLevelStorage().resolveFile(
|
||||
CarpetServer.minecraft_server.getLevelName(), "scripts/"+getDescriptor(module, file, isShared)+".nbt");
|
||||
File dataFile = resolveResource(module, file, "nbt", isShared);
|
||||
if (dataFile == null) return null;
|
||||
if (!Files.exists(dataFile.toPath()) || !(dataFile.isFile())) return null;
|
||||
return read(dataFile);
|
||||
synchronized (writeIOSync) { return FileModule.read(dataFile); }
|
||||
}
|
||||
|
||||
public static boolean saveData(Module module, String file, Tag globalState, boolean isShared)
|
||||
{
|
||||
if (!isShared && (module == null || module.getName() == null)) return false;
|
||||
File dataFile =CarpetServer.minecraft_server.getLevelStorage().resolveFile(
|
||||
CarpetServer.minecraft_server.getLevelName(), "scripts/"+getDescriptor(module, file, isShared)+".nbt");
|
||||
File dataFile = resolveResource(module, file, "nbt", isShared);
|
||||
if (dataFile == null) return false;
|
||||
if (!Files.exists(dataFile.toPath().getParent()) && !dataFile.getParentFile().mkdirs()) return false;
|
||||
return write(globalState, dataFile);
|
||||
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
|
||||
|
||||
@@ -8,6 +8,7 @@ import carpet.script.exception.InternalExpressionException;
|
||||
import carpet.script.value.BlockValue;
|
||||
import carpet.script.value.EntityValue;
|
||||
import carpet.script.value.ListValue;
|
||||
import carpet.script.value.MapValue;
|
||||
import carpet.script.value.NumericValue;
|
||||
import carpet.script.value.StringValue;
|
||||
import carpet.script.value.Value;
|
||||
@@ -19,8 +20,10 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import net.minecraft.command.arguments.ParticleArgumentType;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.DoubleTag;
|
||||
import net.minecraft.nbt.FloatTag;
|
||||
import net.minecraft.nbt.IntTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.StringTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.particle.ParticleEffect;
|
||||
@@ -32,7 +35,9 @@ import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -49,23 +54,90 @@ public class ShapeDispatcher
|
||||
{
|
||||
private static final Map<String, ParticleEffect> particleCache = new HashMap<>();
|
||||
|
||||
public static void sendShape(List<ServerPlayerEntity> players, ExpiringShape shape, Map<String, Value> params)
|
||||
public static Pair<ExpiringShape,Map<String, Value>> fromFunctionArgs(
|
||||
CarpetContext cc,
|
||||
List<Value> lv,
|
||||
ServerPlayerEntity[] playerRef
|
||||
)
|
||||
{
|
||||
Consumer<ServerPlayerEntity> alternative = null;
|
||||
CompoundTag tag = null;
|
||||
if (lv.size() < 3) throw new InternalExpressionException("'draw_shape' takes at least three parameters, shape name, duration, and its params");
|
||||
String shapeType = lv.get(0).getString();
|
||||
Value duration = NumericValue.asNumber(lv.get(1));
|
||||
Map<String, Value> params;
|
||||
if (lv.size() == 3)
|
||||
{
|
||||
Value paramValue = lv.get(2);
|
||||
if (paramValue instanceof MapValue)
|
||||
{
|
||||
params = new HashMap<>();
|
||||
((MapValue) paramValue).getMap().entrySet().forEach(e -> params.put(e.getKey().getString(),e.getValue()));
|
||||
}
|
||||
else if (paramValue instanceof ListValue)
|
||||
{
|
||||
params = parseParams(((ListValue) paramValue).getItems());
|
||||
}
|
||||
else throw new InternalExpressionException("Parameters for 'draw_shape' need to be defined either in a list or a map");
|
||||
}
|
||||
else
|
||||
{
|
||||
List<Value> paramList = new ArrayList<>();
|
||||
for (int i=2; i < lv.size(); i++) paramList.add(lv.get(i));
|
||||
params = ShapeDispatcher.parseParams(paramList);
|
||||
}
|
||||
params.putIfAbsent("dim", new StringValue(cc.s.getWorld().getDimension().getType().toString()));
|
||||
params.putIfAbsent("duration", duration);
|
||||
|
||||
if (params.containsKey("player"))
|
||||
{
|
||||
ServerPlayerEntity player = EntityValue.getPlayerByValue(cc.s.getMinecraftServer(), params.get("player"));
|
||||
if (player == null)
|
||||
throw new InternalExpressionException("'player' parameter needs to represent an existing player");
|
||||
params.remove("player");
|
||||
playerRef[0] = player;
|
||||
}
|
||||
return Pair.of(ShapeDispatcher.create(cc, shapeType, params), params);
|
||||
}
|
||||
|
||||
public static void sendShape(List<ServerPlayerEntity> players, List<Pair<ExpiringShape,Map<String, Value>>> shapes)
|
||||
{
|
||||
List<ServerPlayerEntity> clientPlayers = new ArrayList<>();
|
||||
List<ServerPlayerEntity> alternativePlayers = new ArrayList<>();
|
||||
for (ServerPlayerEntity player : players)
|
||||
{
|
||||
if (ServerNetworkHandler.validCarpetPlayers.contains(player))
|
||||
{
|
||||
if (tag == null) tag = ExpiringShape.toTag(params);
|
||||
ServerNetworkHandler.sendCustomCommand(player,"scShape", tag);
|
||||
clientPlayers.add(player);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (alternative == null) alternative = shape.alternative();
|
||||
alternative.accept(player);
|
||||
alternativePlayers.add(player);
|
||||
}
|
||||
}
|
||||
if (!clientPlayers.isEmpty())
|
||||
{
|
||||
|
||||
ListTag tag = new ListTag();
|
||||
int tagcount = 0;
|
||||
for (Pair<ExpiringShape, Map<String, Value>> s : shapes)
|
||||
{
|
||||
tag.add(ExpiringShape.toTag(s.getRight())); // 4000 shapes limit boxes
|
||||
if (tagcount++>1000)
|
||||
{
|
||||
tagcount = 0;
|
||||
Tag finalTag = tag;
|
||||
clientPlayers.forEach( p -> ServerNetworkHandler.sendCustomCommand(p, "scShapes", finalTag));
|
||||
tag = new ListTag();
|
||||
}
|
||||
}
|
||||
Tag finalTag = tag;
|
||||
if (tag.size() > 0) clientPlayers.forEach( p -> ServerNetworkHandler.sendCustomCommand(p, "scShapes", finalTag));
|
||||
}
|
||||
if (!alternativePlayers.isEmpty())
|
||||
{
|
||||
List<Consumer<ServerPlayerEntity>> alternatives = new ArrayList<>();
|
||||
shapes.forEach(s -> alternatives.add(s.getLeft().alternative()));
|
||||
alternativePlayers.forEach(p -> alternatives.forEach( a -> a.accept(p)));
|
||||
}
|
||||
}
|
||||
|
||||
public static ParticleEffect getParticleData(String name)
|
||||
@@ -174,7 +246,7 @@ public class ShapeDispatcher
|
||||
protected float fr, fg, fb, fa;
|
||||
protected int fillColor;
|
||||
protected int duration = 0;
|
||||
private int key;
|
||||
private long key;
|
||||
protected int followEntity;
|
||||
protected DimensionType entityDimension;
|
||||
|
||||
@@ -214,7 +286,7 @@ public class ShapeDispatcher
|
||||
|
||||
duration = NumericValue.asNumber(options.get("duration")).getInt();
|
||||
|
||||
lineWidth = NumericValue.asNumber(options.getOrDefault("width", optional.get("width"))).getFloat();
|
||||
lineWidth = NumericValue.asNumber(options.getOrDefault("line", optional.get("line"))).getFloat();
|
||||
|
||||
fillColor = NumericValue.asNumber(options.getOrDefault("fill", optional.get("fill"))).getInt();
|
||||
this.fr = (float)(fillColor >> 24 & 0xFF) / 255.0F;
|
||||
@@ -254,19 +326,19 @@ public class ShapeDispatcher
|
||||
}
|
||||
|
||||
public abstract Consumer<ServerPlayerEntity> alternative();
|
||||
public int key()
|
||||
public long key()
|
||||
{
|
||||
if (key!=0) return key;
|
||||
key = calcKey();
|
||||
return key;
|
||||
}
|
||||
protected int calcKey()
|
||||
{
|
||||
int hash = 17;
|
||||
hash = 31*hash + color;
|
||||
hash = 31*hash + followEntity;
|
||||
hash = 31*hash + Float.hashCode(lineWidth);
|
||||
if (fa != 0.0) hash = 31*hash + fillColor;
|
||||
protected long calcKey()
|
||||
{ // using FNV-1a algorithm
|
||||
long hash = -3750763034362895579L;
|
||||
hash ^= color; hash *= 1099511628211L;
|
||||
hash ^= followEntity; hash *= 1099511628211L;
|
||||
hash ^= Float.hashCode(lineWidth); hash *= 1099511628211L;
|
||||
if (fa != 0.0) { hash = 31*hash + fillColor; hash *= 1099511628211L; }
|
||||
return hash;
|
||||
}
|
||||
// list of params that need to be there
|
||||
@@ -274,7 +346,7 @@ public class ShapeDispatcher
|
||||
private final Map<String, Value> optional = ImmutableMap.of(
|
||||
"color", new NumericValue(-1),
|
||||
"follow", new NumericValue(-1),
|
||||
"width", new NumericValue(2.0),
|
||||
"line", new NumericValue(2.0),
|
||||
"fill", new NumericValue(0xffffff00)
|
||||
);
|
||||
protected Set<String> requiredParams() {return required;}
|
||||
@@ -306,6 +378,7 @@ public class ShapeDispatcher
|
||||
super.init(options);
|
||||
from = vecFromValue(options.get("from"));
|
||||
to = vecFromValue(options.get("to"));
|
||||
if (from.equals(to)) throw new InternalExpressionException("Box dimensions are invalid - cannot draw a zero-size boxes");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -330,12 +403,12 @@ public class ShapeDispatcher
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calcKey()
|
||||
public long calcKey()
|
||||
{
|
||||
int hash = super.calcKey();
|
||||
hash = 31*hash + 1;
|
||||
hash = 31*hash + from.hashCode();
|
||||
hash = 31*hash + to.hashCode();
|
||||
long hash = super.calcKey();
|
||||
hash ^= 1; hash *= 1099511628211L;
|
||||
hash ^= from.hashCode(); hash *= 1099511628211L;
|
||||
hash ^= to.hashCode(); hash *= 1099511628211L;
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -389,6 +462,7 @@ public class ShapeDispatcher
|
||||
super.init(options);
|
||||
from = vecFromValue(options.get("from"));
|
||||
to = vecFromValue(options.get("to"));
|
||||
if (from.equals(to)) throw new InternalExpressionException("Line dimensions are invalid - cannot draw a zero-length lines");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -414,12 +488,12 @@ public class ShapeDispatcher
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calcKey()
|
||||
public long calcKey()
|
||||
{
|
||||
int hash = super.calcKey();
|
||||
hash = 31*hash + 2;
|
||||
hash = 31*hash + from.hashCode();
|
||||
hash = 31*hash + to.hashCode();
|
||||
long hash = super.calcKey();
|
||||
hash ^= 2; hash *= 1099511628211L;
|
||||
hash ^= from.hashCode(); hash *= 1099511628211L;
|
||||
hash ^= to.hashCode(); hash *= 1099511628211L;
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
@@ -494,13 +568,13 @@ public class ShapeDispatcher
|
||||
};}
|
||||
|
||||
@Override
|
||||
public int calcKey()
|
||||
public long calcKey()
|
||||
{
|
||||
int hash = super.calcKey();
|
||||
hash = 31*hash + 3;
|
||||
hash = 31*hash + center.hashCode();
|
||||
hash = 31*hash + Double.hashCode(radius);
|
||||
hash = 31*hash + level;
|
||||
long hash = super.calcKey();
|
||||
hash ^= 3; hash *= 1099511628211L;
|
||||
hash ^= center.hashCode(); hash *= 1099511628211L;
|
||||
hash ^= Double.hashCode(radius); hash *= 1099511628211L;
|
||||
hash ^= level; hash *= 1099511628211L;
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
@@ -514,7 +588,7 @@ public class ShapeDispatcher
|
||||
put("duration", new PositiveIntParam("duration"));
|
||||
put("color", new ColorParam("color"));
|
||||
put("follow", new EntityParam("follow"));
|
||||
put("width", new PositiveFloatParam("width"));
|
||||
put("line", new PositiveFloatParam("line"));
|
||||
put("fill", new ColorParam("fill"));
|
||||
|
||||
put("from", new Vec3Param("from", false));
|
||||
@@ -522,6 +596,9 @@ public class ShapeDispatcher
|
||||
put("center", new Vec3Param("center", false));
|
||||
put("radius", new PositiveFloatParam("radius"));
|
||||
put("level", new PositiveIntParam("level"));
|
||||
put("height", new PositiveFloatParam("height"));
|
||||
put("axis", new StringChoiceParam("axis", "x", "y", "z"));
|
||||
put("points", new PointsParam("points"));
|
||||
}};
|
||||
protected String id;
|
||||
protected Param(String id)
|
||||
@@ -543,6 +620,24 @@ public class ShapeDispatcher
|
||||
public Value decode(Tag tag) { return new StringValue(tag.asString()); }
|
||||
}
|
||||
|
||||
public static class StringChoiceParam extends StringParam
|
||||
{
|
||||
private Set<String> options;
|
||||
public StringChoiceParam(String id, String ... options)
|
||||
{
|
||||
super(id);
|
||||
this.options = Sets.newHashSet(options);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Value validate(Map<String, Value> options, CarpetContext cc, Value value)
|
||||
{
|
||||
if (this.options.contains(value.getString())) return value;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class DimensionParam extends StringParam
|
||||
{
|
||||
protected DimensionParam() { super("dim"); }
|
||||
@@ -620,13 +715,17 @@ public class ShapeDispatcher
|
||||
}
|
||||
@Override
|
||||
public Value validate(Map<String, Value> options, CarpetContext cc, Value value)
|
||||
{
|
||||
return validate(this, options, cc, value, roundsUpForBlocks);
|
||||
}
|
||||
public static Value validate(Param p, Map<String, Value> options, CarpetContext cc, Value value, boolean roundsUp)
|
||||
{
|
||||
if (value instanceof BlockValue)
|
||||
{
|
||||
if (options.containsKey("follow"))
|
||||
throw new InternalExpressionException(id+" parameter cannot use blocks as positions for relative positioning due to 'follow' attribute being present");
|
||||
throw new InternalExpressionException(p.id+" parameter cannot use blocks as positions for relative positioning due to 'follow' attribute being present");
|
||||
BlockPos pos = ((BlockValue) value).getPos();
|
||||
int offset = roundsUpForBlocks?1:0;
|
||||
int offset = roundsUp?1:0;
|
||||
return ListValue.of(
|
||||
new NumericValue(pos.getX()+offset),
|
||||
new NumericValue(pos.getY()+offset),
|
||||
@@ -636,18 +735,18 @@ public class ShapeDispatcher
|
||||
if (value instanceof ListValue)
|
||||
{
|
||||
List<Value> values = ((ListValue) value).getItems();
|
||||
if (values.size()!=3) throw new InternalExpressionException("'"+id+"' requires 3 numerical values");
|
||||
if (values.size()!=3) throw new InternalExpressionException("'"+p.id+"' requires 3 numerical values");
|
||||
for (Value component : values)
|
||||
{
|
||||
if (!(component instanceof NumericValue))
|
||||
throw new InternalExpressionException("'"+id+"' requires 3 numerical values");
|
||||
throw new InternalExpressionException("'"+p.id+"' requires 3 numerical values");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
if (value instanceof EntityValue)
|
||||
{
|
||||
if (options.containsKey("follow"))
|
||||
throw new InternalExpressionException(id+" parameter cannot use entity as positions for relative positioning due to 'follow' attribute being present");
|
||||
throw new InternalExpressionException(p.id+" parameter cannot use entity as positions for relative positioning due to 'follow' attribute being present");
|
||||
Entity e = ((EntityValue) value).getEntity();
|
||||
return ListValue.of(
|
||||
new NumericValue(e.getX()),
|
||||
@@ -656,29 +755,81 @@ public class ShapeDispatcher
|
||||
);
|
||||
}
|
||||
CarpetSettings.LOG.error("Value: "+value.getString());
|
||||
throw new InternalExpressionException("'"+id+"' requires a triple, block or entity to indicate position");
|
||||
throw new InternalExpressionException("'"+p.id+"' requires a triple, block or entity to indicate position");
|
||||
}
|
||||
|
||||
public Value decode(Tag tag)
|
||||
{
|
||||
CompoundTag ctag = (CompoundTag)tag;
|
||||
ListTag ctag = (ListTag)tag;
|
||||
return ListValue.of(
|
||||
new NumericValue(ctag.getDouble("x")),
|
||||
new NumericValue(ctag.getDouble("y")),
|
||||
new NumericValue(ctag.getDouble("z"))
|
||||
new NumericValue(ctag.getDouble(0)),
|
||||
new NumericValue(ctag.getDouble(1)),
|
||||
new NumericValue(ctag.getDouble(2))
|
||||
);
|
||||
}
|
||||
@Override
|
||||
public Tag toTag(Value value)
|
||||
{
|
||||
List<Value> lv = ((ListValue)value).getItems();
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putDouble("x", NumericValue.asNumber(lv.get(0)).getDouble());
|
||||
tag.putDouble("y", NumericValue.asNumber(lv.get(1)).getDouble());
|
||||
tag.putDouble("z", NumericValue.asNumber(lv.get(2)).getDouble());
|
||||
ListTag tag = new ListTag();
|
||||
tag.add(DoubleTag.of(NumericValue.asNumber(lv.get(0)).getDouble()));
|
||||
tag.add(DoubleTag.of(NumericValue.asNumber(lv.get(1)).getDouble()));
|
||||
tag.add(DoubleTag.of(NumericValue.asNumber(lv.get(2)).getDouble()));
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PointsParam extends Param
|
||||
{
|
||||
public PointsParam(String id)
|
||||
{
|
||||
super(id);
|
||||
}
|
||||
@Override
|
||||
public Value validate(Map<String, Value> options, CarpetContext cc, Value value)
|
||||
{
|
||||
if (!(value instanceof ListValue))
|
||||
throw new InternalExpressionException(id+ " parameter should be a list");
|
||||
List<Value> points = new ArrayList<>();
|
||||
for (Value point: ((ListValue) value).getItems())
|
||||
points.add(Vec3Param.validate(this, options, cc, point, false));
|
||||
return ListValue.wrap(points);
|
||||
}
|
||||
|
||||
public Value decode(Tag tag)
|
||||
{
|
||||
ListTag ltag = (ListTag)tag;
|
||||
List<Value> points = new ArrayList<>();
|
||||
for (int i=0, ll = ltag.size(); i<ll; i++)
|
||||
{
|
||||
ListTag ptag = ltag.getList(i);
|
||||
points.add(ListValue.of(
|
||||
new NumericValue(ptag.getDouble(0)),
|
||||
new NumericValue(ptag.getDouble(1)),
|
||||
new NumericValue(ptag.getDouble(2))
|
||||
));
|
||||
}
|
||||
return ListValue.wrap(points);
|
||||
}
|
||||
@Override
|
||||
public Tag toTag(Value pointsValue)
|
||||
{
|
||||
List<Value> lv = ((ListValue)pointsValue).getItems();
|
||||
ListTag ltag = new ListTag();
|
||||
for (Value value : lv)
|
||||
{
|
||||
List<Value> coords = ((ListValue)value).getItems();
|
||||
ListTag tag = new ListTag();
|
||||
tag.add(DoubleTag.of(NumericValue.asNumber(lv.get(0)).getDouble()));
|
||||
tag.add(DoubleTag.of(NumericValue.asNumber(lv.get(1)).getDouble()));
|
||||
tag.add(DoubleTag.of(NumericValue.asNumber(lv.get(2)).getDouble()));
|
||||
ltag.add(tag);
|
||||
}
|
||||
return ltag;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ColorParam extends NumericParam
|
||||
{
|
||||
protected ColorParam(String id)
|
||||
|
||||
@@ -2,15 +2,15 @@ package carpet.script.utils;
|
||||
|
||||
import carpet.CarpetSettings;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
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.VertexConsumerProvider;
|
||||
import net.minecraft.client.render.VertexFormats;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
@@ -25,7 +25,7 @@ import java.util.function.BiFunction;
|
||||
|
||||
public class ShapesRenderer
|
||||
{
|
||||
private final Map<DimensionType, Int2ObjectOpenHashMap<RenderedShape<? extends ShapeDispatcher.ExpiringShape>>> shapes;
|
||||
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
|
||||
@@ -40,12 +40,12 @@ public class ShapesRenderer
|
||||
{
|
||||
this.client = minecraftClient;
|
||||
shapes = new HashMap<>();
|
||||
shapes.put(DimensionType.OVERWORLD, new Int2ObjectOpenHashMap<>());
|
||||
shapes.put(DimensionType.THE_NETHER, new Int2ObjectOpenHashMap<>());
|
||||
shapes.put(DimensionType.THE_END, new Int2ObjectOpenHashMap<>());
|
||||
shapes.put(DimensionType.OVERWORLD, new Long2ObjectOpenHashMap<>());
|
||||
shapes.put(DimensionType.THE_NETHER, new Long2ObjectOpenHashMap<>());
|
||||
shapes.put(DimensionType.THE_END, new Long2ObjectOpenHashMap<>());
|
||||
}
|
||||
|
||||
public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, double cameraX, double cameraY, double cameraZ)
|
||||
public void render(Camera camera, float partialTick)
|
||||
{
|
||||
IWorld iWorld = this.client.world;
|
||||
DimensionType dimensionType = iWorld.getDimension().getType();
|
||||
@@ -68,20 +68,25 @@ public class ShapesRenderer
|
||||
//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).int2ObjectEntrySet().removeIf(
|
||||
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);
|
||||
s.renderFaces(tessellator, bufferBuilder, cameraX, cameraY, cameraZ, partialTick);
|
||||
}
|
||||
);
|
||||
//lines
|
||||
@@ -89,7 +94,7 @@ public class ShapesRenderer
|
||||
|
||||
s -> {
|
||||
if ( s.shouldRender(dimensionType))
|
||||
s.renderLines(tessellator, bufferBuilder, cameraX, cameraY, cameraZ);
|
||||
s.renderLines(tessellator, bufferBuilder, cameraX, cameraY, cameraZ, partialTick);
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -102,6 +107,14 @@ public class ShapesRenderer
|
||||
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);
|
||||
@@ -116,7 +129,7 @@ public class ShapesRenderer
|
||||
{
|
||||
RenderedShape<?> rshape = shapeFactory.apply(client, shape);
|
||||
DimensionType dim = Registry.DIMENSION_TYPE.get(new Identifier(tag.getString("dim")));
|
||||
int key = rshape.key();
|
||||
long key = rshape.key();
|
||||
synchronized (shapes)
|
||||
{
|
||||
RenderedShape<?> existing = shapes.get(dim).get(key);
|
||||
@@ -135,7 +148,7 @@ public class ShapesRenderer
|
||||
{
|
||||
synchronized (shapes)
|
||||
{
|
||||
shapes.values().forEach(Int2ObjectOpenHashMap::clear);
|
||||
shapes.values().forEach(Long2ObjectOpenHashMap::clear);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,13 +159,13 @@ public class ShapesRenderer
|
||||
protected MinecraftClient client;
|
||||
long expiryTick;
|
||||
double renderEpsilon = 0;
|
||||
public abstract void renderLines(Tessellator tessellator, BufferBuilder builder, double cx, double cy, double cz );
|
||||
public void renderFaces(Tessellator tessellator, BufferBuilder builder, double cx, double cy, double cz ) {}
|
||||
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 = (2+((double)shape.key())/Integer.MAX_VALUE)/1000;
|
||||
renderEpsilon = (3+((double)shape.key())/Long.MAX_VALUE)/1000;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@@ -160,7 +173,7 @@ public class ShapesRenderer
|
||||
{
|
||||
return expiryTick < currentTick;
|
||||
}
|
||||
public int key()
|
||||
public long key()
|
||||
{
|
||||
return shape.key();
|
||||
};
|
||||
@@ -172,11 +185,15 @@ public class ShapesRenderer
|
||||
if (client.world.getEntityById(shape.followEntity) == null) return false;
|
||||
return true;
|
||||
}
|
||||
protected Vec3d relativiseRender(Vec3d vec)
|
||||
protected Vec3d relativiseRender(Vec3d vec, float partialTick)
|
||||
{
|
||||
if (shape.followEntity <= 0) return vec;
|
||||
Entity e = client.world.getEntityById(shape.followEntity);
|
||||
return shape.toAbsolute(e, vec);
|
||||
return vec.add(
|
||||
MathHelper.lerp(partialTick, e.prevX, e.getX()),
|
||||
MathHelper.lerp(partialTick, e.prevY, e.getY()),
|
||||
MathHelper.lerp(partialTick, e.prevZ, e.getZ())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,28 +206,30 @@ public class ShapesRenderer
|
||||
|
||||
}
|
||||
@Override
|
||||
public void renderLines(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz)
|
||||
public void renderLines(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz, float partialTick)
|
||||
{
|
||||
if (shape.a == 0.0) return;
|
||||
Vec3d v1 = relativiseRender(shape.from);
|
||||
Vec3d v2 = relativiseRender(shape.to);
|
||||
Vec3d v1 = relativiseRender(shape.from, partialTick);
|
||||
Vec3d v2 = relativiseRender(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)
|
||||
public void renderFaces(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz, float partialTick)
|
||||
{
|
||||
if (shape.fa == 0.0) return;
|
||||
Vec3d v1 = relativiseRender(shape.from);
|
||||
Vec3d v2 = relativiseRender(shape.to);
|
||||
Vec3d v1 = relativiseRender(shape.from, partialTick);
|
||||
Vec3d v2 = relativiseRender(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
|
||||
);
|
||||
}
|
||||
@@ -224,10 +243,10 @@ public class ShapesRenderer
|
||||
super(client, (ShapeDispatcher.Line)shape);
|
||||
}
|
||||
@Override
|
||||
public void renderLines(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz)
|
||||
public void renderLines(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz, float partialTick)
|
||||
{
|
||||
Vec3d v1 = relativiseRender(shape.from);
|
||||
Vec3d v2 = relativiseRender(shape.to);
|
||||
Vec3d v1 = relativiseRender(shape.from, partialTick);
|
||||
Vec3d v2 = relativiseRender(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),
|
||||
@@ -244,10 +263,10 @@ public class ShapesRenderer
|
||||
super(client, (ShapeDispatcher.Sphere)shape);
|
||||
}
|
||||
@Override
|
||||
public void renderLines(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz)
|
||||
public void renderLines(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz, float partialTick)
|
||||
{
|
||||
if (shape.a == 0.0) return;
|
||||
Vec3d vc = relativiseRender(shape.center);
|
||||
Vec3d vc = relativiseRender(shape.center, partialTick);
|
||||
RenderSystem.lineWidth(shape.lineWidth);
|
||||
drawSphereWireframe(tessellator, bufferBuilder,
|
||||
(float)(vc.x-cx-renderEpsilon), (float)(vc.y-cy-renderEpsilon), (float)(vc.z-cz-renderEpsilon),
|
||||
@@ -255,10 +274,10 @@ public class ShapesRenderer
|
||||
shape.r, shape.g, shape.b, shape.a);
|
||||
}
|
||||
@Override
|
||||
public void renderFaces(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz)
|
||||
public void renderFaces(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz, float partialTick)
|
||||
{
|
||||
if (shape.fa == 0.0) return;
|
||||
Vec3d vc = relativiseRender(shape.center);
|
||||
Vec3d vc = relativiseRender(shape.center, partialTick);
|
||||
RenderSystem.lineWidth(1.0f);
|
||||
drawSphereFaces(tessellator, bufferBuilder,
|
||||
(float)(vc.x-cx-renderEpsilon), (float)(vc.y-cy-renderEpsilon), (float)(vc.z-cz-renderEpsilon),
|
||||
@@ -276,68 +295,117 @@ public class ShapesRenderer
|
||||
tessellator.draw();
|
||||
}
|
||||
|
||||
public static void drawBoxWireGLLines(Tessellator tessellator, BufferBuilder builder, float x1, float y1, float z1, float x2, float y2, float z2, float red1, float grn1, float blu1, float alpha, float red2, float grn2, float blu2)
|
||||
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
|
||||
builder.vertex(x1, y1, z1).color(red1, grn2, blu2, alpha).next();
|
||||
builder.vertex(x2, y1, z1).color(red1, grn2, blu2, alpha).next();
|
||||
builder.vertex(x1, y1, z1).color(red2, grn1, blu2, alpha).next();
|
||||
builder.vertex(x1, y2, z1).color(red2, grn1, blu2, alpha).next();
|
||||
builder.vertex(x1, y1, z1).color(red2, grn2, blu1, alpha).next();
|
||||
builder.vertex(x1, y1, z2).color(red2, grn2, 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, z1).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x1, y2, 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, y2, z2).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x1, y1, 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, y1, z2).color(red1, grn1, blu1, alpha).next();
|
||||
builder.vertex(x2, y1, z1).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();
|
||||
builder.vertex(x2, y2, z2).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();
|
||||
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, float red1, float grn1, float blu1, float alpha)
|
||||
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);
|
||||
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();
|
||||
|
||||
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 (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();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
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();
|
||||
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();
|
||||
|
||||
builder.vertex(x1, y1, 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(x2, y1, z1).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();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +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;
|
||||
@@ -285,6 +289,20 @@ 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("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)
|
||||
{
|
||||
@@ -934,20 +952,28 @@ public class EntityValue extends Value
|
||||
}
|
||||
});
|
||||
|
||||
put("silent",(e,v)->{
|
||||
e.setSilent(v.getBoolean());
|
||||
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("gravity",(e,v)->{
|
||||
e.setNoGravity(!v.getBoolean());
|
||||
put("exhaustion", (e, v)-> {
|
||||
if(e instanceof PlayerEntity) ((HungerManagerInterface) ((PlayerEntity) e).getHungerManager()).setExhaustionCM(NumericValue.asNumber(v).getFloat());
|
||||
});
|
||||
|
||||
put("invulnerable",(e,v)->{
|
||||
e.setInvulnerable(v.getBoolean());
|
||||
put("add_exhaustion", (e, v)-> {
|
||||
if(e instanceof PlayerEntity) ((PlayerEntity) e).getHungerManager().addExhaustion((int) NumericValue.asNumber(v).getLong());
|
||||
});
|
||||
|
||||
put("fire",(e,v)->{
|
||||
e.setFireTicks((int)NumericValue.asNumber(v).getLong());
|
||||
put("saturation", (e, v)-> {
|
||||
if(e instanceof PlayerEntity) ((PlayerEntity) e).getHungerManager().setSaturationLevelClient((float)NumericValue.asNumber(v).getLong());
|
||||
});
|
||||
|
||||
// gamemode [check]
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -362,8 +362,7 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -110,20 +110,20 @@ public class BlockInfo
|
||||
put(Material.PLANT , "plant" );
|
||||
put(Material.UNDERWATER_PLANT, "water_plant" );
|
||||
put(Material.REPLACEABLE_PLANT, "vegetation" );
|
||||
put(Material.SEAGRASS , "sea_grass" );
|
||||
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 , "decoration" );
|
||||
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" );
|
||||
}};
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
)
|
||||
);
|
||||
);
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
global_chunk_colors = m(
|
||||
// loaded ticking
|
||||
l(3, l(0xBBFF0000, 0x88bb0000)), // lime, green
|
||||
l(2, l(0xFF000000, 0x88000000)), // red
|
||||
l(1, l(0xFFFF0000, 0xbbbb0000)), // yellow
|
||||
// 'unloaded' (in memory, so rather 'inaccessible')
|
||||
l(0, l(0xcccccc00, 0x11111100)), // gray / hi constast
|
||||
// stable full generation (for '0's, all 1,2,3 are always 'full')
|
||||
l('full', l(0xbbbbbb00, 0x88888800)), // gray
|
||||
// unstable final bits
|
||||
l('heightmaps', l(0xFFFFFF00, 0x00000000)), // check
|
||||
l('spawn', l(0xFFFFFF00, 0x00000000)), // check
|
||||
l('light_gen', l(0xFFFFFF00, 0x00000000)), // check
|
||||
// stable features
|
||||
l('features', l(0x88bb2200, 0x66882200)), // green muddled
|
||||
//stable terrain
|
||||
l('liquid_carvers', l(0x65432100, 0x54321000)), // browns
|
||||
//unstable terrain - not generated yet
|
||||
l('carvers', l(0xFFFFFF00, 0x00000000)), // check
|
||||
l('surface', l(0xFFFFFF00, 0x00000000)), // check
|
||||
l('noise', l(0xFFFFFF00, 0x00000000)), // check
|
||||
l('biomes', l(0xFFFFFF00, 0x00000000)), // check
|
||||
l('structure_references', l(0xFFFFFF00, 0x00000000)), // check
|
||||
// stable
|
||||
l('structure_starts', l(0x66666600, 0x22222200)), // darkgrey
|
||||
// not stated yet
|
||||
l('empty', l(0xFF88888800, 0xDD444400)), // pink
|
||||
// proper not in memory
|
||||
l(null , l(0xFFFFFF00, 0xFFFFFF00)), // hwite
|
||||
|
||||
// ticket types
|
||||
l('player', l(0x0000DD00, 0x00008800)), // blue
|
||||
l('portal', l(0xAA00AA00, 0xAA00AA00)), // purple
|
||||
l('dragon', l(0xAA008800, 0xAA008800)), // purple
|
||||
l('forced', l(0xAABBFF00, 0x8899AA00)), // blue
|
||||
l('light', l(0xFFFF0000, 0xBBBB0000)), // yellow
|
||||
l('post_teleport', l(0xAA00AA00, 0xAA00AA00)), // purple
|
||||
l('start', l(0xDDFF0000, 0xDDFF0000)), // lime, green
|
||||
// recent chunk requests
|
||||
l('unknown', l(0xFFFFFF00, 0x00000000)) // check
|
||||
);
|
||||
|
||||
// map representing current displayed chunkloading setup
|
||||
global_current_setup = null;
|
||||
|
||||
// which blocks in the inventory represent which dimension
|
||||
global_block_markers = m(
|
||||
l('netherrack', 'the_nether'),
|
||||
l('grass_block', 'overworld'),
|
||||
l('end_stone', 'the_end')
|
||||
);
|
||||
|
||||
__on_player_uses_item(player, item_tuple, hand) ->
|
||||
(
|
||||
if (hand != 'mainhand', return());
|
||||
if (!has(global_block_markers, item_tuple:0), return());
|
||||
if (item_tuple:1%16 != 0, return());
|
||||
new_setup = true;
|
||||
if (global_current_setup,
|
||||
new_setup = __remove_previous_setup(player)
|
||||
);
|
||||
if (!new_setup, return());
|
||||
tag = nbt('{}');
|
||||
put(tag:'Enchantments','[]');
|
||||
put(tag:'Enchantments', '{lvl:1s,id:"minecraft:protection"}', 0);
|
||||
inventory_set(player, player~'selected_slot', item_tuple:1, item_tuple:0, tag);
|
||||
__setup_tracker(player, item_tuple);
|
||||
);
|
||||
|
||||
//__on_tick() -> null;
|
||||
|
||||
__remove_previous_setup(new_player) ->
|
||||
(
|
||||
if (!global_current_setup, return());
|
||||
global_running = false;
|
||||
p = player();
|
||||
if (p &&
|
||||
global_block_markers:((item = inventory_get(p, global_current_setup:'inventory_slot')):0)==global_current_setup:'source_dimension' &&
|
||||
item:1 == global_current_setup:'radius' &&
|
||||
item:2,
|
||||
inventory_set(p, global_current_setup:'inventory_slot', item:1, item:0, null); // disenchant
|
||||
if( new_player == p && new_player~'selected_slot' == global_current_setup:'inventory_slot',
|
||||
disabled = true
|
||||
);
|
||||
);
|
||||
global_current_setup = null;
|
||||
!disabled
|
||||
);
|
||||
|
||||
__setup_tracker(player, item) ->
|
||||
(
|
||||
setup = m();
|
||||
setup:'player_name' = str(player);
|
||||
setup:'inventory_slot' = player ~ 'selected_slot';
|
||||
setup:'plot_dimension' = player ~ 'dimension';
|
||||
setup:'plot_center' = map(pos(player), floor(_))-l(0,1,0);
|
||||
setup:'radius' = item:1;
|
||||
setup:'source_dimension' = global_block_markers:(item:0);
|
||||
multiplier = 1;
|
||||
if (setup:'source_dimension' != setup:'plot_dimension',
|
||||
multiplier = if (
|
||||
setup:'source_dimension' == 'the_nether', 1/8,
|
||||
setup:'source_dimension' == 'the_end', 0,
|
||||
8);
|
||||
);
|
||||
setup:'source_center' = setup:'plot_center' * multiplier;
|
||||
print(setup:'source_dimension'+' around '+setup:'source_center'+' with '+setup:'radius'+' radius ('+ (2*setup:'radius'+1)^2 +' chunks)');
|
||||
|
||||
l(sx, sy, sz) = setup:'source_center';
|
||||
global_status_cache = m();
|
||||
loop( 2*setup:'radius'+1, dx = _ - setup:'radius';
|
||||
loop( 2*setup:'radius'+1, dz = _ - setup:'radius';
|
||||
source_pos = l(sx+16*dx,sy,sz+16*dz);
|
||||
global_status_cache:source_pos = null
|
||||
)
|
||||
);
|
||||
global_current_setup = setup;
|
||||
global_running = true;
|
||||
schedule(0, '__chunk_visualizer_tick', player);
|
||||
);
|
||||
|
||||
global_status_cache = m();
|
||||
|
||||
__chunk_visualizer_tick(p) ->
|
||||
(
|
||||
setup = global_current_setup;
|
||||
if(!setup, return());
|
||||
if (!global_running, return());
|
||||
show_activity = (p~'holds':0 == 'redstone_torch');
|
||||
in_dimension( setup:'plot_dimension',
|
||||
l(sx, sy, sz) = setup:'source_center';
|
||||
l(px, py, pz) = setup:'plot_center';
|
||||
source_center = setup:'source_center';
|
||||
radius = setup:'radius';
|
||||
source_dimension = setup:'source_dimension';
|
||||
|
||||
shapes = l();
|
||||
|
||||
loop( 2*radius+1, dx = _ - radius;
|
||||
loop( 2*radius+1, dz = _ - radius;
|
||||
changed = false;
|
||||
source_pos = l(sx+16*dx,sy,sz+16*dz);
|
||||
status = in_dimension( source_dimension,
|
||||
loaded_status = loaded_status(source_pos);
|
||||
if (loaded_status > 0, loaded_status, generation_status(source_pos))
|
||||
);
|
||||
// will mix with light ticket
|
||||
if (status=='light', status = 'light_gen');
|
||||
|
||||
if ( status != global_status_cache:source_pos,
|
||||
global_status_cache:source_pos = status;
|
||||
changed = true;
|
||||
);
|
||||
if (loaded_status > 0,
|
||||
tickets = in_dimension( source_dimension, chunk_tickets(source_pos));
|
||||
for(tickets,
|
||||
l(type, level) = _;
|
||||
if (show_activity || type != 'unknown',
|
||||
global_status_cache:source_pos = type;
|
||||
changed = true;
|
||||
);
|
||||
);
|
||||
);
|
||||
//if (changed,
|
||||
//to = global_status_cache:source_pos;
|
||||
//if(!has(global_chunk_colors:to), print('problem with '+to));
|
||||
//set(px+dx,py,pz+dz, global_chunk_colors:to:((dx+dz)%2));
|
||||
//set(px+dx,py,pz+dz, global_chunk_colors:(global_status_cache:source_pos):((dx+dz)%2));
|
||||
//bpos = l(px+dx/2, py, pz+dz/2);
|
||||
bpos = l(dx/2, -10, dz/2);
|
||||
bcol = global_chunk_colors:(global_status_cache:source_pos):((dx+dz)%2);
|
||||
shapes += l('box', 10, 'from', bpos, 'to', bpos + l(0.5,0,0.5), 'color', bcol, 'fill', bcol+128,
|
||||
'follow', p)
|
||||
;
|
||||
//);
|
||||
);
|
||||
);
|
||||
draw_shape(shapes);
|
||||
);
|
||||
schedule(5, '__chunk_visualizer_tick', p)
|
||||
)
|
||||
@@ -94,7 +94,7 @@ __structure_renderer(player_name) ->
|
||||
l(from, to) = structure_data;
|
||||
total_size = _euclidean(from, to);
|
||||
density = max(10, total_size/10);
|
||||
draw_shape('box', 15, 'from', from, 'to', to+1, 'color', 0x00FFFFFF, 'width', 3, 'fill', 0x00FFFF22);
|
||||
draw_shape('box', 15, 'from', from, 'to', to+1, 'color', 0x00FFFFFF, 'line', 3, 'fill', 0x00FFFF22);
|
||||
structure_pieces = slice(sort_key(structure_pieces, _euclidean_sq((_:2+_:3)/2,ppos)), 0, config:'max_pieces');
|
||||
for (structure_pieces, l(piece, direction, from, to) = _;
|
||||
r = 255 - floor(128 * _i/config:'max_pieces');
|
||||
@@ -133,12 +133,14 @@ __chunk_renderer(player_name) ->
|
||||
b = 30;
|
||||
a = max(0, 255-player_distance);
|
||||
color = a+256*(b+256*(g+256*r));
|
||||
draw_shape('line', 15, 'from', top_00, 'to', top_10, 'color', color, 'width', 3);
|
||||
draw_shape('line', 15, 'from', top_10, 'to', top_11, 'color', color, 'width', 3);
|
||||
draw_shape('line', 15, 'from', top_11, 'to', top_01, 'color', color, 'width', 3);
|
||||
draw_shape('line', 15, 'from', top_01, 'to', top_00, 'color', color, 'width', 3);
|
||||
draw_shape('line', 15, 'from', top_00, 'to', top_11, 'color', color, 'width', 3);
|
||||
draw_shape('line', 15, 'from', top_01, 'to', top_10, 'color', color, 'width', 3);
|
||||
draw_shape(l(
|
||||
l('line', 15, 'from', top_00, 'to', top_10, 'color', color, 'line', 3),
|
||||
l('line', 15, 'from', top_10, 'to', top_11, 'color', color, 'line', 3),
|
||||
l('line', 15, 'from', top_11, 'to', top_01, 'color', color, 'line', 3),
|
||||
l('line', 15, 'from', top_01, 'to', top_00, 'color', color, 'line', 3),
|
||||
l('line', 15, 'from', top_00, 'to', top_11, 'color', color, 'line', 3),
|
||||
l('line', 15, 'from', top_01, 'to', top_10, 'color', color, 'line', 3)
|
||||
));
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -155,7 +155,7 @@
|
||||
"StatType_scarpetMixin",
|
||||
"PointOfInterest_scarpetMixin",
|
||||
"ServerWorld_scarpetEventMixin",
|
||||
|
||||
"HungerManagerMixin_scarpetEventsMixin",
|
||||
|
||||
"PistonBlock_movableTEMixin",
|
||||
"PistonBlockEntity_movableTEMixin",
|
||||
@@ -182,7 +182,8 @@
|
||||
"WorldRenderer_fogOffMixin",
|
||||
"WorldRenderer_creativeNoClipMixin",
|
||||
"ClientPlayNetworkHandlerMixin",
|
||||
"DebugRenderer_scarpetRenderMixin"
|
||||
"DebugRenderer_scarpetRenderMixin",
|
||||
"WorldRenderer_scarpetRenderMixin"
|
||||
],
|
||||
"server": [
|
||||
"MinecraftDedicatedServerMixin"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "carpet",
|
||||
"version": "1.3.26",
|
||||
"version": "1.3.27",
|
||||
|
||||
"name": "Carpet Mod in Fabric",
|
||||
"description": "Carpet made out of fabric",
|
||||
|
||||
Reference in new issue
Block a user