diff --git a/docs/scarpet/Full.md b/docs/scarpet/Full.md
index 17c6b3d3..1fb28263 100644
--- a/docs/scarpet/Full.md
+++ b/docs/scarpet/Full.md
@@ -2483,6 +2483,9 @@ is only effective if you set it at y=0, and affects the entire column of. In the
specific Y coordinate of the biome you want to change, and it affects roughly 4x4x4 area (give or take some random
noise).
+This changed again in 1.18. The overworld behaves like the nether now, the biome must be set
+for individual y coordinates.
+
Throws `unknown_biome` if the `biome_name` doesn't exist.
### `update(pos)`
@@ -2675,8 +2678,8 @@ With block, or name, returns the name of the biome in that position, or throws `
Note: Have to pass all 6 of the mentioned noise types and only these noise types for it to evaluate a biome.
With an optional feature, it returns value for the specified attribute for that biome. Available and queryable features include:
-* `'top_material'`: unlocalized block representing the top surface material
-* `'under_material'`: unlocalized block representing what sits below topsoil
+* `'top_material'`: unlocalized block representing the top surface material (1.17.1 and below only)
+* `'under_material'`: unlocalized block representing what sits below topsoil (1.17.1 and below only)
* `'category'`: the parent biome this biome is derived from. Possible values include:
`'none'`, `'taiga'`, `'extreme_hills'`, `'jungle'`, `'mesa'`, `'plains'`, `'savanna'`,
`'icy'`, `'the_end'`, `'beach'`, `'forest'`, `'ocean'`, `'desert'`, `'river'`,
diff --git a/docs/scarpet/api/Auxiliary.md b/docs/scarpet/api/Auxiliary.md
index 072f401e..408d103e 100644
--- a/docs/scarpet/api/Auxiliary.md
+++ b/docs/scarpet/api/Auxiliary.md
@@ -252,6 +252,8 @@ Decorators (listed as extra argument after the component they would affect):
* `'^ '` - hover over tooltip text, appearing when hovering with your mouse over the text below.
* `'?` - command suggestion - a message that will be pasted to chat when text below it is clicked.
* `'!'` - a chat message that will be executed when the text below it is clicked.
+ * `'@'` - a URL that will be opened when the text below it is clicked.
+ * `'&'` - a text that will be copied to clipboard when the text below it is clicked.
Both suggestions and messages can contain a command, which will be executed as a player that clicks it.
@@ -681,13 +683,13 @@ Fetches the value of a system property or returns all inforation as a map when c
fetch various information, mostly not changing, or only available via low level
system calls. In all circumstances, these are only provided as read-only.
-Available options in the scarpet app space:
+##### Available options in the scarpet app space:
* `app_name` - current app name or `null` if its a default app
* `app_list` - list of all loaded apps excluding default commandline app
* `app_scope` - scope of the global variables and function. Available options is `player` and `global`
- * `app_player` - returns a player list that have app run under them. For `global` apps, the list is always empty
+ * `app_players` - returns a player list that have app run under them. For `global` apps, the list is always empty
- Relevant world related properties
+##### Relevant world related properties
* `world_name` - name of the world
* `world_seed` - a numeric seed of the world
* `world_dimensions` - a list of dimensions in the world
@@ -700,9 +702,10 @@ Available options in the scarpet app space:
* `world_top` - Returns current dimensions' topmost Y value where one can place blocks.
* `world_bottom` - Returns current dimensions' bottommost Y value where one can place blocks.
* `world_center` - Returns coordinates of the center of the world with respect of the world border
- * `world_size` - Returns size of the world where at this distance from `world_center` world border appears.
+ * `world_size` - Returns radius of world border for current dimension.
+ * `world_max_size` - Returns maximum possible radius of world border for current dimension.
*
- Relevant gameplay related properties
+##### Relevant gameplay related properties
* `game_difficulty` - current difficulty of the game: `'peaceful'`, `'easy'`, `'normal'`, or `'hard'`
* `game_hardcore` - boolean whether the game is in hardcore mode
* `game_storage_format` - format of the world save files, either `'McRegion'` or `'Anvil'`
@@ -713,13 +716,13 @@ Available options in the scarpet app space:
* `game_version` - base version of the game
* `game_target` - target release version
* `game_major_target` - major release target. For 1.12.2, that would be 12
- * `game_minor_reease` - minor release target. For 1.12.2, that woudl be 2
+ * `game_minor_release` - minor release target. For 1.12.2, that would be 2
* `game_protocol` - protocol version number
* `game_pack_version` - datapack version number
* `game_data_version` - data version of the game. Returns an integer, so it can be compared.
* `game_stable` - indicating if its a production release or a snapshot
- Server related properties
+##### Server related properties
* `server_motd` - the motd of the server visible when joining
* `server_ip` - IP adress of the game hosted
* `server_whitelisted` - boolean indicating whether the access to the server is only for whitelisted players
@@ -734,7 +737,21 @@ list may refer to the previous tick performance. In this case the last entry (ti
tick. For all intent and purpose, `system_info('last_tick_times'):0` should be used as last tick execution time, but
individual tick times may vary greatly, and these need to be taken with the little grain of averaging.
- System related properties
+##### Source related properties
+
+ The source is what is the cause of the code running, with Carpet using it same way as Minecraft commands use to run. Those are used in
+ some API functions that interact with the game or with commands, and can be manipulated if the execution is caused by an `execute` command, modified
+ by some functions or ran in non-standard ways. This section provides useful information from these cases (like running from a command
+ block, right clicking a sign, etc)
+ * `source_entity` - The entity associated with the execution. This is usually a player (in which case `player()` would get the entity from this),
+ but it may also be a different entity or `null` if the execution comes from the server console or a command block.
+ * `source_position` - The position associated with the execution. This is usually the position of the entity, but it may have been manipulated or
+ it could come from a command block (no entity then). If this call comes from the server console, it will be the world spawn.
+ * `source_dimension` - The dimension associated with the execution. Execution from the server console provides `overworld` as the dimension.
+ This can be manipulated by running code inside `in_dimension()`.
+ * `source_rotation` - The rotation associated with the execution. Usually `[0, 0]` in non-standard situations, the rotation of the entity otherwise.
+
+##### System related properties
* `java_max_memory` - maximum allowed memory accessible by JVM
* `java_allocated_memory` - currently allocated memory by JVM
* `java_used_memory` - currently used memory by JVM
@@ -744,7 +761,7 @@ individual tick times may vary greatly, and these need to be taken with the litt
* `java_system_cpu_load` - current percentage of CPU used by the system
* `java_process_cpu_load` - current percentage of CPU used by JVM
- Scarpet related properties
+##### Scarpet related properties
* `scarpet_version` - returns the version of the carpet your scarpet comes with.
## NBT Storage
diff --git a/docs/scarpet/api/BlocksAndWorldAccess.md b/docs/scarpet/api/BlocksAndWorldAccess.md
index a74970f7..7a8c3445 100644
--- a/docs/scarpet/api/BlocksAndWorldAccess.md
+++ b/docs/scarpet/api/BlocksAndWorldAccess.md
@@ -157,12 +157,11 @@ Throws `unknown_poi` if the provided point of interest doesn't exist
### `set_biome(pos, biome_name, update=true)`
Changes the biome at that block position. if update is specified and false, then chunk will not be refreshed
-on the clients. Biome changes can only be send to clients with the entire data from the chunk.
+on the clients. Biome changes can only be sent to clients with the entire data from the chunk.
-Setting a biome is now (as of 1.16) dimension specific. In the overworld and the end changing the biome
-is only effective if you set it at y=0, and affects the entire column of. In the nether - you have to use the
-specific Y coordinate of the biome you want to change, and it affects roughly 4x4x4 area (give or take some random
-noise).
+Be aware that depending on the MC version and dimension settings biome can be set either in a 1x1x256
+column or 4x4x4 hyperblock, so for some versions Y will be ignored and for some precision of biome
+setting is less than 1x1x1 block.
Throws `unknown_biome` if the `biome_name` doesn't exist.
@@ -356,8 +355,8 @@ With block, or name, returns the name of the biome in that position, or throws `
Note: Have to pass all 6 of the mentioned noise types and only these noise types for it to evaluate a biome.
With an optional feature, it returns value for the specified attribute for that biome. Available and queryable features include:
-* `'top_material'`: unlocalized block representing the top surface material
-* `'under_material'`: unlocalized block representing what sits below topsoil
+* `'top_material'`: unlocalized block representing the top surface material (1.17.1 and below only)
+* `'under_material'`: unlocalized block representing what sits below topsoil (1.17.1 and below only)
* `'category'`: the parent biome this biome is derived from. Possible values include:
`'none'`, `'taiga'`, `'extreme_hills'`, `'jungle'`, `'mesa'`, `'plains'`, `'savanna'`,
`'icy'`, `'the_end'`, `'beach'`, `'forest'`, `'ocean'`, `'desert'`, `'river'`,
diff --git a/docs/scarpet/api/Entities.md b/docs/scarpet/api/Entities.md
index af0dbc52..044e1837 100644
--- a/docs/scarpet/api/Entities.md
+++ b/docs/scarpet/api/Entities.md
@@ -202,13 +202,19 @@ List of entities riding the entity.
Entity that `e` rides.
-### `query(e, 'scoreboard_tags')` and
-### `query(e, 'tags')`(deprecated)
+### `(deprecated) query(e, 'tags')`
+
+Deprecated by `query(e, 'scoreboard_tags')`
+
+### `query(e, 'scoreboard_tags')`
List of entity's scoreboard tags.
-### `query(e, 'has_scoreboard_tag',tag)` and
-### `query(e, 'has_tag',tag)`(deprecated)
+### `(deprecated) query(e, 'has_tag',tag)`
+
+Deprecated by `query(e, 'has_scoreboard_tag',tag)`
+
+### `query(e, 'has_scoreboard_tag',tag)`
Boolean, true if the entity is marked with a `tag` scoreboad tag.
diff --git a/docs/scarpet/api/Overview.md b/docs/scarpet/api/Overview.md
index bde44cff..a92da2af 100644
--- a/docs/scarpet/api/Overview.md
+++ b/docs/scarpet/api/Overview.md
@@ -128,7 +128,7 @@ in a list and contain of map-like resources descriptors, looking like
or a relative location in the same folder as the app in question (the relative location directly).
`'target'` points to the path in app data, or shared app data folder. If not specified it will place the app into the main data folder with the name it has.
if `'shared'` is specified and `true`. When re-downloading the app, all resources will be re-downloaded as well.
-Currently, app resources are only downloaded when using `/carpet download` command.
+Currently, app resources are only downloaded when using `/script download` command.
* `libraries` - list of libraries or apps to be downloaded when installing the app from the app store. It needs to be a list of map-like resource
descriptors, like the above `resources` field.
```
diff --git a/docs/scarpet/language/Operators.md b/docs/scarpet/language/Operators.md
index cc5b8d0a..c0e8dd5a 100644
--- a/docs/scarpet/language/Operators.md
+++ b/docs/scarpet/language/Operators.md
@@ -110,7 +110,7 @@ Or an example to find if a player has specific enchantment on a held axe (either
global_get_enchantment(p, ench) -> (
-$ for(['main','offhand'],
+$ for(['mainhand','offhand'],
$ holds = query(p, 'holds', _);
$ if( holds,
$ [what, count, nbt] = holds;
diff --git a/docs/scarpet/resources/media/idea_customize.png b/docs/scarpet/resources/media/idea_customize.png
index 5e50aa2d..26cbc2ce 100644
Binary files a/docs/scarpet/resources/media/idea_customize.png and b/docs/scarpet/resources/media/idea_customize.png differ
diff --git a/docs/scarpet/resources/media/idea_settings.png b/docs/scarpet/resources/media/idea_settings.png
index 99fb8f8c..255f8f4c 100644
Binary files a/docs/scarpet/resources/media/idea_settings.png and b/docs/scarpet/resources/media/idea_settings.png differ
diff --git a/gradle.properties b/gradle.properties
index d8d175bd..e8740202 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -6,7 +6,7 @@ org.gradle.jvmargs=-Xmx1G
# or better: https://modmuss50.me/fabric.html
minecraft_version=1.18
yarn_mappings=1.18+build.1
- loader_version=0.12.6
+ loader_version=0.12.12
fabric_version=0.43.1+1.18
# Mod Properties
diff --git a/src/main/java/carpet/commands/PlayerCommand.java b/src/main/java/carpet/commands/PlayerCommand.java
index 69dcce4b..b4255503 100644
--- a/src/main/java/carpet/commands/PlayerCommand.java
+++ b/src/main/java/carpet/commands/PlayerCommand.java
@@ -299,6 +299,9 @@ public class PlayerCommand
{
// Force override flying to true for spectator players, or they will fell out of the world.
flying = true;
+ } else if(mode.isSurvivalLike()){
+ // Force override flying to false for survival-like players, or they will fly too
+ flying = false;
}
String playerName = StringArgumentType.getString(context, "player");
if (playerName.length()>maxPlayerLength(source.getServer()))
diff --git a/src/main/java/carpet/commands/TickCommand.java b/src/main/java/carpet/commands/TickCommand.java
index b4ada51e..78a8af5d 100644
--- a/src/main/java/carpet/commands/TickCommand.java
+++ b/src/main/java/carpet/commands/TickCommand.java
@@ -51,10 +51,10 @@ public class TickCommand
then(literal("deep").executes( (c)-> setFreeze(c.getSource(), true, true)))).
then(literal("off").executes( (c) -> setFreeze(c.getSource(), false, false)))).
then(literal("step").
- executes((c) -> step(1)).
+ executes((c) -> step(c.getSource(), 1)).
then(argument("ticks", integer(1,72000)).
suggests( (c, b) -> suggestMatching(new String[]{"20"},b)).
- executes((c) -> step(getInteger(c,"ticks"))))).
+ executes((c) -> step(c.getSource(), getInteger(c,"ticks"))))).
then(literal("superHot").executes( (c)-> toggleSuperHot(c.getSource()))).
then(literal("health").
executes( (c) -> healthReport(c.getSource(), 100)).
@@ -130,9 +130,10 @@ public class TickCommand
return setFreeze(source, isDeep, !TickSpeed.isPaused());
}
- private static int step(int advance)
+ private static int step(ServerCommandSource source, int advance)
{
TickSpeed.add_ticks_to_run_in_pause(advance);
+ Messenger.m(source, "gi Stepping " + advance + " tick" + (advance != 1 ? "s" : ""));
return 1;
}
diff --git a/src/main/java/carpet/fakes/BiomeEffectsInterface.java b/src/main/java/carpet/fakes/BiomeEffectsInterface.java
deleted file mode 100644
index c3a5acc1..00000000
--- a/src/main/java/carpet/fakes/BiomeEffectsInterface.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package carpet.fakes;
-
-import java.util.Optional;
-
-public interface BiomeEffectsInterface
-{
- int getCMFogColor();
- Optional getCMFoliageColor();
- int getCMSkyColor();
- int getCMWaterColor();
- int getCMWaterFogColor();
-}
diff --git a/src/main/java/carpet/fakes/BrainInterface.java b/src/main/java/carpet/fakes/BrainInterface.java
deleted file mode 100644
index b45b9778..00000000
--- a/src/main/java/carpet/fakes/BrainInterface.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package carpet.fakes;
-
-import net.minecraft.entity.ai.brain.Memory;
-import net.minecraft.entity.ai.brain.MemoryModuleType;
-
-import java.util.Map;
-import java.util.Optional;
-
-public interface BrainInterface
-{
- Map, Optional extends Memory>>> getMobMemories();
-}
diff --git a/src/main/java/carpet/fakes/ItemEntityInterface.java b/src/main/java/carpet/fakes/ItemEntityInterface.java
index 5faa1f74..4534bbfe 100644
--- a/src/main/java/carpet/fakes/ItemEntityInterface.java
+++ b/src/main/java/carpet/fakes/ItemEntityInterface.java
@@ -2,6 +2,5 @@ package carpet.fakes;
public interface ItemEntityInterface
{
- int getAgeCM();
int getPickupDelayCM();
}
diff --git a/src/main/java/carpet/fakes/MemoryInterface.java b/src/main/java/carpet/fakes/MemoryInterface.java
deleted file mode 100644
index 8447433c..00000000
--- a/src/main/java/carpet/fakes/MemoryInterface.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package carpet.fakes;
-
-public interface MemoryInterface
-{
- long getScarpetExpiry();
-}
diff --git a/src/main/java/carpet/mixins/BiomeEffects_scarpetMixin.java b/src/main/java/carpet/mixins/BiomeEffects_scarpetMixin.java
deleted file mode 100644
index e8291304..00000000
--- a/src/main/java/carpet/mixins/BiomeEffects_scarpetMixin.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package carpet.mixins;
-
-import carpet.fakes.BiomeEffectsInterface;
-import net.minecraft.world.biome.BiomeEffects;
-import org.spongepowered.asm.mixin.Final;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Shadow;
-
-import java.util.Optional;
-
-@Mixin(BiomeEffects.class)
-public class BiomeEffects_scarpetMixin implements BiomeEffectsInterface
-{
- @Shadow @Final private int fogColor;
-
- @Shadow @Final private Optional foliageColor;
-
- @Shadow @Final private int skyColor;
-
- @Shadow @Final private int waterColor;
-
- @Shadow @Final private int waterFogColor;
-
- @Override
- public int getCMFogColor()
- {
- return fogColor;
- }
-
- @Override
- public Optional getCMFoliageColor()
- {
- return foliageColor;
- }
-
- @Override
- public int getCMSkyColor()
- {
- return skyColor;
- }
-
- @Override
- public int getCMWaterColor()
- {
- return waterColor;
- }
-
- @Override
- public int getCMWaterFogColor()
- {
- return waterFogColor;
- }
-}
diff --git a/src/main/java/carpet/mixins/Brain_Mixin.java b/src/main/java/carpet/mixins/Brain_Mixin.java
deleted file mode 100644
index 161a1e9d..00000000
--- a/src/main/java/carpet/mixins/Brain_Mixin.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package carpet.mixins;
-
-import carpet.fakes.BrainInterface;
-import net.minecraft.entity.ai.brain.Brain;
-import net.minecraft.entity.ai.brain.Memory;
-import net.minecraft.entity.ai.brain.MemoryModuleType;
-import org.spongepowered.asm.mixin.Final;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Shadow;
-
-import java.util.Map;
-import java.util.Optional;
-
-@Mixin(Brain.class)
-public class Brain_Mixin implements BrainInterface
-{
-
- @Shadow @Final private Map, Optional extends Memory>>> memories;
-
- @Override
- public Map, Optional extends Memory>>> getMobMemories()
- {
- return memories;
- }
-}
diff --git a/src/main/java/carpet/mixins/ItemEntityMixin.java b/src/main/java/carpet/mixins/ItemEntityMixin.java
index 4a58ac11..56204178 100644
--- a/src/main/java/carpet/mixins/ItemEntityMixin.java
+++ b/src/main/java/carpet/mixins/ItemEntityMixin.java
@@ -42,11 +42,6 @@ public abstract class ItemEntityMixin extends Entity implements ItemEntityInterf
}
}
- @Override
- public int getAgeCM() {
- return this.itemAge;
- }
-
@Override
public int getPickupDelayCM() {
return this.pickupDelay;
@@ -105,7 +100,7 @@ public abstract class ItemEntityMixin extends Entity implements ItemEntityInterf
self.setStack(selfStack);
this.pickupDelay = Math.max(((ItemEntityInterface)other).getPickupDelayCM(), this.pickupDelay);
- this.itemAge = Math.min(((ItemEntityInterface)other).getAgeCM(), this.itemAge);
+ this.itemAge = Math.min(other.getItemAge(), this.itemAge);
otherStack.decrement(amount);
if (otherStack.isEmpty())
diff --git a/src/main/java/carpet/mixins/Memory_scarpetMixin.java b/src/main/java/carpet/mixins/Memory_scarpetMixin.java
deleted file mode 100644
index d3b4db17..00000000
--- a/src/main/java/carpet/mixins/Memory_scarpetMixin.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package carpet.mixins;
-
-import carpet.fakes.MemoryInterface;
-import net.minecraft.entity.ai.brain.Memory;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Shadow;
-
-@Mixin(Memory.class)
-public class Memory_scarpetMixin implements MemoryInterface
-{
- @Shadow private long expiry;
-
- @Override
- public long getScarpetExpiry()
- {
- return expiry;
- }
-}
diff --git a/src/main/java/carpet/mixins/VillagerEntity_aiMixin.java b/src/main/java/carpet/mixins/VillagerEntity_aiMixin.java
index a41e9170..1810c48e 100644
--- a/src/main/java/carpet/mixins/VillagerEntity_aiMixin.java
+++ b/src/main/java/carpet/mixins/VillagerEntity_aiMixin.java
@@ -1,7 +1,5 @@
package carpet.mixins;
-import carpet.fakes.BrainInterface;
-import carpet.fakes.MemoryInterface;
import carpet.helpers.ParticleDisplay;
import carpet.utils.Messenger;
import carpet.utils.MobAI;
@@ -65,14 +63,14 @@ public abstract class VillagerEntity_aiMixin extends MerchantEntity
if (MobAI.isTracking(this, MobAI.TrackingType.IRON_GOLEM_SPAWNING))
{
long time;
- Optional extends Memory>> last_seen = ((BrainInterface)this.brain).getMobMemories().get(MemoryModuleType.GOLEM_DETECTED_RECENTLY);
+ Optional extends Memory>> last_seen = this.brain.getMemories().get(MemoryModuleType.GOLEM_DETECTED_RECENTLY);
if (!last_seen.isPresent())
{
time = 0;
}
else
{
- time = ((MemoryInterface)last_seen.get()).getScarpetExpiry();
+ time = last_seen.get().getExpiry();
}
boolean recentlySeen = time > 0;
Optional optional_11 = this.brain.getOptionalMemory(MemoryModuleType.LAST_SLEPT);
diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java
index d8b9c5f9..60da9003 100644
--- a/src/main/java/carpet/script/CarpetExpression.java
+++ b/src/main/java/carpet/script/CarpetExpression.java
@@ -91,7 +91,7 @@ public class CarpetExpression
public Value scriptRunCommand(ScriptHost host, BlockPos pos)
{
if (CarpetServer.scriptServer.stopAll)
- throw new CarpetExpressionException("SCRIPTING PAUSED", null);
+ throw new CarpetExpressionException("SCRIPTING PAUSED (unpause with /script resume)", null);
try
{
Context context = new CarpetContext(host, source, origin).
diff --git a/src/main/java/carpet/script/CarpetScriptHost.java b/src/main/java/carpet/script/CarpetScriptHost.java
index ef67e102..25ea3f57 100644
--- a/src/main/java/carpet/script/CarpetScriptHost.java
+++ b/src/main/java/carpet/script/CarpetScriptHost.java
@@ -13,6 +13,7 @@ import carpet.script.exception.ExpressionException;
import carpet.script.exception.IntegrityException;
import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.InvalidCallbackException;
+import carpet.script.exception.LoadException;
import carpet.script.utils.AppStoreManager;
import carpet.script.value.EntityValue;
import carpet.script.value.FunctionValue;
@@ -37,6 +38,7 @@ import net.fabricmc.loader.api.ModContainer;
import net.fabricmc.loader.api.SemanticVersion;
import net.fabricmc.loader.api.Version;
import net.fabricmc.loader.api.VersionParsingException;
+import net.fabricmc.loader.api.metadata.version.VersionPredicate;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.nbt.NbtElement;
@@ -60,7 +62,6 @@ import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
-import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -119,8 +120,7 @@ public class CarpetScriptHost extends ScriptHost
String code = module.getCode();
if (code == null)
{
- Messenger.m(source, "r Unable to load "+module.getName()+" app - code not found");
- return null;
+ throw new LoadException("Code not found");
}
host.setChatErrorSnooper(source);
CarpetExpression ex = new CarpetExpression(host.main, code, source, new BlockPos(0, 0, 0));
@@ -131,13 +131,12 @@ public class CarpetScriptHost extends ScriptHost
catch (CarpetExpressionException e)
{
host.handleErrorWithStack("Error while evaluating expression", e);
- host.resetErrorSnooper();
- return null;
+ throw new LoadException();
}
- catch (ArithmeticException ae)
+ catch (ArithmeticException ae) // is this branch ever reached? Seems like arithmetic exceptions are converted to CEEs earlier
{
host.handleErrorWithStack("Math doesn't compute", ae);
- return null;
+ throw new LoadException();
}
catch (StackOverflowError soe)
{
@@ -314,7 +313,7 @@ public class CarpetScriptHost extends ScriptHost
{
Value reqResult = callNow((FunctionValue) loadRequirements, Collections.emptyList());
if (reqResult.getBoolean()) // != false or null
- throw new InternalExpressionException(reqResult.getString());
+ throw new LoadException(reqResult.getString());
}
else
{
@@ -422,20 +421,6 @@ public class CarpetScriptHost extends ScriptHost
return addLegacyCommand(notifier);
}
- // Prefixes based on FLoader's SemanticVersionPredicateParser's class prefixes under Apache 2.0, since that's not public API
- private static final Map> VERSION_PREFIXES = new HashMap>() {{
- put(">=", (target, source) -> source.compareTo(target) >= 0);
- put("<=", (target, source) -> source.compareTo(target) <= 0);
- put(">", (target, source) -> source.compareTo(target) > 0);
- put("<", (target, source) -> source.compareTo(target) < 0);
- put("=", (target, source) -> source.compareTo(target) == 0);
- put("~", (target, source) -> source.compareTo(target) >= 0
- && source.getVersionComponent(0) == target.getVersionComponent(0)
- && source.getVersionComponent(1) == target.getVersionComponent(1));
- put("^", (target, source) -> source.compareTo(target) >= 0
- && source.getVersionComponent(0) == target.getVersionComponent(0));
- }};
-
public void checkModVersionRequirements(Value reqs) {
if (reqs == null)
return;
@@ -446,58 +431,25 @@ public class CarpetScriptHost extends ScriptHost
Map requirements = ((MapValue)reqs).getMap();
for (Entry requirement : requirements.entrySet())
{
- boolean successful = false;
String requiredModId = requirement.getKey().getString();
- String requirementString = requirement.getValue().getString();
-
+ String stringPredicate = requirement.getValue().getString();
+ VersionPredicate predicate;
+ try {
+ predicate = VersionPredicate.parse(stringPredicate);
+ } catch (VersionParsingException e) {
+ throw new InternalExpressionException("Failed to parse version conditions for '" + requiredModId + "' in 'requires': " + e.getMessage());
+ }
+
ModContainer mod = FabricLoader.getInstance().getModContainer(requiredModId).orElse(null);
if (mod != null)
{
- if (requirementString.equals("*"))
- continue;
Version presentVersion = mod.getMetadata().getVersion();
- BiPredicate tester = null;
- String remainingRequirementString = requirementString;
- for (Entry> s : VERSION_PREFIXES.entrySet())
- {
- if (requirementString.startsWith(s.getKey()))
- {
- tester = s.getValue();
- remainingRequirementString = requirementString.substring(s.getKey().length());
- }
- }
- if (tester == null)
- tester = VERSION_PREFIXES.get("=");
- if (presentVersion instanceof SemanticVersion)
- {
- SemanticVersion requiredVersion = null;
- try {
- requiredVersion = SemanticVersion.parse(remainingRequirementString);
- }
- catch (VersionParsingException e)
- {
- throw new InternalExpressionException("Failed to parse semantic version for '" + requiredModId + "' in 'requires': " + e.getMessage());
- }
- if (tester.test(requiredVersion, (SemanticVersion) presentVersion))
- successful = true;
- }
- else
- {
- if (FabricLoader.getInstance().isDevelopmentEnvironment())
- successful = true; // Autoversioning breaks semver in dev (loads as ${version})
- else
- {
- if (!(tester == VERSION_PREFIXES.get("=")))
- throw new InternalExpressionException("Mod '"+requiredModId+"' doesn't use semversion, thus can only check version equality");
- if (presentVersion.getFriendlyString().equals(remainingRequirementString))
- successful = true;
- }
+ if (predicate.test(presentVersion) || (FabricLoader.getInstance().isDevelopmentEnvironment() && !(presentVersion instanceof SemanticVersion)))
+ { // in a dev env, mod version is usually replaced with ${version}, and that isn't semantic
+ continue;
}
}
- if (!successful)
- {
- throw new InternalExpressionException(getName()+" requires " + requiredModId + " version " + requirementString + " in order to load");
- }
+ throw new LoadException(String.format("%s requires a version of mod '%s' matching '%s', which is missing!", getName(), requiredModId, stringPredicate));
}
}
@@ -732,10 +684,10 @@ public class CarpetScriptHost extends ScriptHost
public Value callLegacy(ServerCommandSource source, String call, List coords, String arg)
{
if (CarpetServer.scriptServer.stopAll)
- throw new CarpetExpressionException("SCARPET PAUSED", null);
+ throw new CarpetExpressionException("SCARPET PAUSED (unpause with /script resume)", null);
FunctionValue function = getFunction(call);
if (function == null)
- throw new CarpetExpressionException("UNDEFINED", null);
+ throw new CarpetExpressionException("Couldn't find function '" + call + "' in app '" + this.getName() + "'", null);
List argv = new ArrayList<>();
if (coords != null)
for (Integer i: coords)
@@ -832,7 +784,7 @@ public class CarpetScriptHost extends ScriptHost
public Value call(ServerCommandSource source, FunctionValue function, List argv)
{
if (CarpetServer.scriptServer.stopAll)
- throw new CarpetExpressionException("SCARPET PAUSED", null);
+ throw new CarpetExpressionException("SCARPET PAUSED (unpause with /script resume)", null);
List args = function.getArguments();
if (argv.size() != args.size())
diff --git a/src/main/java/carpet/script/CarpetScriptServer.java b/src/main/java/carpet/script/CarpetScriptServer.java
index 8b92c010..99597247 100644
--- a/src/main/java/carpet/script/CarpetScriptServer.java
+++ b/src/main/java/carpet/script/CarpetScriptServer.java
@@ -13,6 +13,7 @@ import carpet.CarpetServer;
import carpet.script.bundled.FileModule;
import carpet.script.bundled.Module;
import carpet.script.exception.ExpressionException;
+import carpet.script.exception.LoadException;
import carpet.script.language.Arithmetic;
import carpet.script.language.ControlFlow;
import carpet.script.language.DataStructures;
@@ -256,10 +257,14 @@ public class CarpetScriptServer
Messenger.m(source, "r Failed to add "+name+" app");
return false;
}
- CarpetScriptHost newHost = CarpetScriptHost.create(this, module, perPlayer, source, commandValidator, isRuleApp, installer);
- if (newHost == null)
+ CarpetScriptHost newHost;
+ try
{
- Messenger.m(source, "r Failed to add "+name+" app");
+ newHost = CarpetScriptHost.create(this, module, perPlayer, source, commandValidator, isRuleApp, installer);
+ }
+ catch (LoadException e)
+ {
+ Messenger.m(source, "r Failed to add " + name + " app" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
return false;
}
// config needs to be read as we load the app since some events use that info
diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java
index e4109da4..4796765c 100644
--- a/src/main/java/carpet/script/Expression.java
+++ b/src/main/java/carpet/script/Expression.java
@@ -481,9 +481,9 @@ public class Expression
}
- public void addLazyFunction(String name, int num_params, TriFunction, LazyValue> fun)
+ public void addLazyFunction(String name, int numParams, TriFunction, LazyValue> fun)
{
- functions.put(name, new AbstractLazyFunction(num_params, name)
+ functions.put(name, new AbstractLazyFunction(numParams, name)
{
@Override
public boolean pure() {
@@ -499,8 +499,11 @@ public class Expression
public LazyValue lazyEval(Context c, Context.Type i, Expression e, Tokenizer.Token t, List lazyParams)
{
ILazyFunction.checkInterrupts();
- if (num_params >= 0 && lazyParams.size() != num_params)
- throw new InternalExpressionException("'"+name+"' requires "+num_params+" parameters, "+lazyParams.size()+" provided.");
+ if (numParams >= 0 && lazyParams.size() != numParams)
+ {
+ String error = "Function '"+name+"' requires "+numParams+" arguments, got "+lazyParams.size()+". ";
+ throw new InternalExpressionException(error + (fun instanceof Fluff.UsageProvider up ? up.getUsage() : ""));
+ }
try
{
diff --git a/src/main/java/carpet/script/Fluff.java b/src/main/java/carpet/script/Fluff.java
index d2e07fdc..ab2e45ba 100644
--- a/src/main/java/carpet/script/Fluff.java
+++ b/src/main/java/carpet/script/Fluff.java
@@ -30,6 +30,8 @@ public abstract class Fluff
@FunctionalInterface
public interface SexFunction { R apply(A a, B b, C c, D d, E e, F f);}
+ public interface UsageProvider { String getUsage();}
+
public interface EvalNode
{
/**
diff --git a/src/main/java/carpet/script/annotation/AnnotationParser.java b/src/main/java/carpet/script/annotation/AnnotationParser.java
index 4aa47a52..ad8e3a94 100644
--- a/src/main/java/carpet/script/annotation/AnnotationParser.java
+++ b/src/main/java/carpet/script/annotation/AnnotationParser.java
@@ -21,6 +21,7 @@ import carpet.script.Context;
import carpet.script.Expression;
import carpet.script.Fluff.AbstractLazyFunction;
import carpet.script.Fluff.TriFunction;
+import carpet.script.Fluff.UsageProvider;
import carpet.script.exception.InternalExpressionException;
import carpet.script.LazyValue;
import carpet.script.value.Value;
@@ -73,6 +74,7 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList;
*/
public final class AnnotationParser
{
+ static final int UNDEFINED_PARAMS = -2;
private static final List functionList = new ArrayList<>();
/**
@@ -90,8 +92,8 @@ public final class AnnotationParser
* {@link InternalExpressionException}).
* Basically, it's fine as long as you don't add a {@code throws} declaration to your methods.
* Varargs (or effectively varargs) annotated methods must explicitly declare a maximum number of parameters to ingest in the {@link ScarpetFunction}
- * annotation. They can still declare an unlimited amount by setting that maximum to {@code -1}. "Effectively varargs" means a function that has
- * a parameter using/requiring a {@link ValueConverter} that has declared {@link ValueConverter#consumesVariableArgs()}.
+ * annotation. They can still declare an unlimited amount by setting that maximum to {@link ScarpetFunction#UNLIMITED_PARAMS}. "Effectively varargs"
+ * means a function that has at least a parameter requiring a {@link ValueConverter} that has declared {@link ValueConverter#consumesVariableArgs()}.
* Annotated methods must not have a parameter with generics as the varargs parameter. This is just because it was painful for me (altrisi) and
* didn't want to support it. Those will crash with a {@code ClassCastException}
*
@@ -141,7 +143,7 @@ public final class AnnotationParser
expr.addLazyFunction(function.name, function.scarpetParamCount, function);
}
- private static class ParsedFunction implements TriFunction, LazyValue>
+ private static class ParsedFunction implements TriFunction, LazyValue>, UsageProvider
{
private final String name;
private final boolean isMethodVarArgs;
@@ -186,10 +188,10 @@ public final class AnnotationParser
if (this.isEffectivelyVarArgs)
{
maxParams = method.getAnnotation(ScarpetFunction.class).maxParams();
- if (maxParams == -2)
- throw new IllegalArgumentException("No maximum number of params specified for " + name + ", use -1 for unlimited. "
+ if (maxParams == UNDEFINED_PARAMS)
+ throw new IllegalArgumentException("No maximum number of params specified for " + name + ", use ScarpetFunction.UNLIMITED_PARAMS for unlimited. "
+ "Provided in " + instance.getClass());
- if (maxParams == -1)
+ if (maxParams == ScarpetFunction.UNLIMITED_PARAMS)
maxParams = Integer.MAX_VALUE;
if (maxParams < this.minParams)
throw new IllegalArgumentException("Provided maximum number of params for " + name + " is smaller than method's param count."
@@ -293,7 +295,8 @@ public final class AnnotationParser
return params;
}
- private String getUsage()
+ @Override
+ public String getUsage()
{
// Possibility: More descriptive messages using param.getName()? Would need changing gradle setup to keep those
StringBuilder builder = new StringBuilder("Usage: '");
diff --git a/src/main/java/carpet/script/annotation/ScarpetFunction.java b/src/main/java/carpet/script/annotation/ScarpetFunction.java
index 466bda7e..edb980fd 100644
--- a/src/main/java/carpet/script/annotation/ScarpetFunction.java
+++ b/src/main/java/carpet/script/annotation/ScarpetFunction.java
@@ -51,6 +51,11 @@ import carpet.script.value.Value;
@Retention(RUNTIME)
public @interface ScarpetFunction
{
+ /**
+ * Used to define that this {@link ScarpetFunction} can accept an unlimited number of parameters
+ */
+ public static final int UNLIMITED_PARAMS = -1;
+
/**
* If the function can accept a variable number of parameters, either by declaring its last parameter as a varargs parameter or by having one
* of their parameters use a converter that consumes a variable number of arguments, this must define the maximum number of parameters this
@@ -65,11 +70,11 @@ public @interface ScarpetFunction
* consider that those can take either a single triple of values or 3 independent values, that would be counted in the maximum number of
* parameters.
*
- * Use -1 to specify an unlimited number of parameters.
+ * Use {@link ScarpetFunction#UNLIMITED_PARAMS} to allow an unlimited number of parameters.
*
* @return The maximum number of parameters this function can accept
*/
- int maxParams() default -2;
+ int maxParams() default AnnotationParser.UNDEFINED_PARAMS;
/**
* Defines the Context Type that will be used when evaluating arguments to annotated methods.
diff --git a/src/main/java/carpet/script/annotation/ValueConverter.java b/src/main/java/carpet/script/annotation/ValueConverter.java
index 2a5e50c8..ed1a1812 100644
--- a/src/main/java/carpet/script/annotation/ValueConverter.java
+++ b/src/main/java/carpet/script/annotation/ValueConverter.java
@@ -162,13 +162,13 @@ public interface ValueConverter
* constraints as {@link #convert(Value)}
* @param valueIterator An {@link Iterator} holding the {@link Value} to convert in next position
* @param context The {@link Context} this function has been called with. This was used when this passed lazy values instead in order to
- * evaluate, now it's used to get the context. It is now ignored by the default implementation
- * @param theLazyT The {@code t} that the original function was called with. It is ignored by the default implementation.
+ * evaluate, now it's used to get the context
+ * @param contextType The {@link Context.Type} that the original function was called with
* @return The next {@link Value} (s) converted to the type {@code } of this {@link ValueConverter}
* @implNote This method's default implementation runs the {@link #convert(Value)} function in the next {@link Value} ignoring {@link Context} and
* {@code theLazyT}.
*/
- default public R checkAndConvert(Iterator valueIterator, Context context, Context.Type theLazyT)
+ default public R checkAndConvert(Iterator valueIterator, Context context, Context.Type contextType)
{
if (!valueIterator.hasNext())
return null;
diff --git a/src/main/java/carpet/script/api/Auxiliary.java b/src/main/java/carpet/script/api/Auxiliary.java
index da35463d..5e508815 100644
--- a/src/main/java/carpet/script/api/Auxiliary.java
+++ b/src/main/java/carpet/script/api/Auxiliary.java
@@ -676,7 +676,7 @@ public class Auxiliary {
expression.addContextFunction("last_tick_times", -1, (c, t, lv) ->
{
c.host.issueDeprecation("last_tick_times()");
- return SystemInfo.get("last_tick_times", (CarpetContext)c);
+ return SystemInfo.get("server_last_tick_times", (CarpetContext)c);
});
@@ -736,6 +736,7 @@ public class Auxiliary {
return Value.TRUE;
});
+ // Should this be deprecated for system_info('source_dimension')?
expression.addContextFunction("current_dimension", 0, (c, t, lv) ->
ValueConversions.of( ((CarpetContext)c).s.getWorld()));
diff --git a/src/main/java/carpet/script/api/Entities.java b/src/main/java/carpet/script/api/Entities.java
index 8f4de7c8..4ad079ac 100644
--- a/src/main/java/carpet/script/api/Entities.java
+++ b/src/main/java/carpet/script/api/Entities.java
@@ -3,6 +3,7 @@ package carpet.script.api;
import carpet.script.CarpetContext;
import carpet.script.CarpetEventServer;
import carpet.script.CarpetScriptHost;
+import carpet.script.Context;
import carpet.script.Expression;
import carpet.script.argument.FunctionArgument;
import carpet.script.argument.Vector3Argument;
@@ -36,9 +37,20 @@ import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.UUID;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
public class Entities {
+ private static ListValue getPlayersFromWorldMatching(Context c, Predicate condition) {
+ List ret = new ArrayList<>();
+ for (ServerPlayerEntity player: ((CarpetContext) c).s.getWorld().getPlayers()) {
+ if (condition.test(player)) {
+ ret.add(new EntityValue(player));
+ }
+ }
+ return ListValue.wrap(ret);
+ }
+
public static void apply(Expression expression)
{
expression.addContextFunction("player", -1, (c, t, lv) ->
@@ -58,50 +70,26 @@ public class Entities {
return EntityValue.of(closestPlayer);
}
String playerName = lv.get(0).getString();
- Value retval = Value.NULL;
- if ("all".equalsIgnoreCase(playerName))
- {
- retval = ListValue.wrap(
- ((CarpetContext)c).s.getServer().getPlayerManager().getPlayerList().
- stream().map(EntityValue::new).collect(Collectors.toList()));
- }
- else if ("*".equalsIgnoreCase(playerName))
- {
- retval = ListValue.wrap(
- ((CarpetContext)c).s.getWorld().getPlayers().
- stream().map(EntityValue::new).collect(Collectors.toList()));
- }
- else if ("survival".equalsIgnoreCase(playerName))
- {
- retval = ListValue.wrap(
- ((CarpetContext)c).s.getWorld().getPlayers((p) -> p.interactionManager.isSurvivalLike()).
- stream().map(EntityValue::new).collect(Collectors.toList()));
- }
- else if ("creative".equalsIgnoreCase(playerName))
- {
- retval = ListValue.wrap(
- ((CarpetContext)c).s.getWorld().getPlayers(PlayerEntity::isCreative).
- stream().map(EntityValue::new).collect(Collectors.toList()));
- }
- else if ("spectating".equalsIgnoreCase(playerName))
- {
- retval = ListValue.wrap(
- ((CarpetContext)c).s.getWorld().getPlayers(PlayerEntity::isSpectator).
- stream().map(EntityValue::new).collect(Collectors.toList()));
- }
- else if ("!spectating".equalsIgnoreCase(playerName))
- {
- retval = ListValue.wrap(
- ((CarpetContext)c).s.getWorld().getPlayers((p) -> !p.isSpectator()).
- stream().map(EntityValue::new).collect(Collectors.toList()));
- }
- else
- {
- ServerPlayerEntity player = ((CarpetContext) c).s.getServer().getPlayerManager().getPlayer(playerName);
- if (player != null)
- retval = new EntityValue(player);
- }
- return retval;
+ return switch (playerName) {
+ case "all" -> {
+ List ret = new ArrayList<>();
+ for (ServerPlayerEntity player: ((CarpetContext)c).s.getServer().getPlayerManager().getPlayerList())
+ ret.add(new EntityValue(player));
+ yield ListValue.wrap(ret);
+ }
+ case "*" -> getPlayersFromWorldMatching(c, p -> true);
+ case "survival" -> getPlayersFromWorldMatching(c, p -> p.interactionManager.isSurvivalLike());
+ case "creative" -> getPlayersFromWorldMatching(c, PlayerEntity::isCreative);
+ case "spectating" -> getPlayersFromWorldMatching(c, PlayerEntity::isSpectator);
+ case "!spectating" -> getPlayersFromWorldMatching(c, p -> !p.isSpectator());
+ default -> {
+ ServerPlayerEntity player = ((CarpetContext) c).s.getServer().getPlayerManager().getPlayer(playerName);
+ if (player != null) {
+ yield new EntityValue(player);
+ }
+ yield Value.NULL;
+ }
+ };
});
expression.addContextFunction("spawn", -1, (c, t, lv) ->
diff --git a/src/main/java/carpet/script/exception/LoadException.java b/src/main/java/carpet/script/exception/LoadException.java
new file mode 100644
index 00000000..740a04b1
--- /dev/null
+++ b/src/main/java/carpet/script/exception/LoadException.java
@@ -0,0 +1,19 @@
+package carpet.script.exception;
+
+/**
+ * A Scarpet exception that indicates that load of the app has failed.
+ *
+ * Goes up the stack to the point of app load and gets caught there, preventing the app from loading with
+ * the given message.
+ *
+ */
+public class LoadException extends RuntimeException implements ResolvedException {
+
+ public LoadException() {
+ super();
+ }
+
+ public LoadException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/carpet/script/utils/BiomeInfo.java b/src/main/java/carpet/script/utils/BiomeInfo.java
index 065a6795..ee9f9524 100644
--- a/src/main/java/carpet/script/utils/BiomeInfo.java
+++ b/src/main/java/carpet/script/utils/BiomeInfo.java
@@ -8,9 +8,7 @@ import carpet.script.value.NumericValue;
import carpet.script.value.StringValue;
import carpet.script.value.Value;
import carpet.script.value.ValueConversions;
-import net.minecraft.client.color.world.FoliageColors;
import net.minecraft.server.world.ServerWorld;
-import net.minecraft.util.math.MathHelper;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.feature.ConfiguredFeature;
@@ -27,11 +25,11 @@ public class BiomeInfo
//put("under_material", (w, b) -> new BlockValue( b.getGenerationSettings().getSurfaceConfig().getUnderMaterial(), null, null));
put("category", (w, b) -> StringValue.of(b.getCategory().getName()));
put("temperature", (w, b) -> NumericValue.of(b.getTemperature()));
- put("fog_color", (w, b) -> ValueConversions.ofRGB(((BiomeEffectsInterface)b.getEffects()).getCMFogColor()));
- put("foliage_color", (w, b) -> ValueConversions.ofRGB(((BiomeEffectsInterface)b.getEffects()).getCMFoliageColor().orElse(4764952))); // client Biome.getDefaultFoliageColor
- put("sky_color", (w, b) -> ValueConversions.ofRGB(((BiomeEffectsInterface)b.getEffects()).getCMSkyColor()));
- put("water_color", (w, b) -> ValueConversions.ofRGB(((BiomeEffectsInterface)b.getEffects()).getCMWaterColor()));
- put("water_fog_color", (w, b) -> ValueConversions.ofRGB(((BiomeEffectsInterface)b.getEffects()).getCMWaterFogColor()));
+ put("fog_color", (w, b) -> ValueConversions.ofRGB(b.getEffects().getFogColor()));
+ put("foliage_color", (w, b) -> ValueConversions.ofRGB(b.getEffects().getFoliageColor().orElse(4764952))); // client Biome.getDefaultFoliageColor
+ put("sky_color", (w, b) -> ValueConversions.ofRGB(b.getEffects().getSkyColor()));
+ put("water_color", (w, b) -> ValueConversions.ofRGB(b.getEffects().getWaterColor()));
+ put("water_fog_color", (w, b) -> ValueConversions.ofRGB(b.getEffects().getWaterFogColor()));
put("humidity", (w, b) -> NumericValue.of(b.getDownfall()));
put("precipitation", (w, b) -> StringValue.of(b.getPrecipitation().getName()));
//put("depth", (w, b) -> NumericValue.of(b.getDepth()));
diff --git a/src/main/java/carpet/script/utils/SystemInfo.java b/src/main/java/carpet/script/utils/SystemInfo.java
index 6aa56030..73e4a125 100644
--- a/src/main/java/carpet/script/utils/SystemInfo.java
+++ b/src/main/java/carpet/script/utils/SystemInfo.java
@@ -5,6 +5,7 @@ import carpet.CarpetSettings;
import carpet.script.CarpetContext;
import carpet.script.CarpetScriptHost;
import carpet.script.value.BooleanValue;
+import carpet.script.value.EntityValue;
import carpet.script.value.ListValue;
import carpet.script.value.MapValue;
import carpet.script.value.NumericValue;
@@ -17,11 +18,9 @@ import com.sun.management.OperatingSystemMXBean;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.minecraft.SharedConstants;
-import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.WorldSavePath;
-import net.minecraft.util.registry.RegistryKey;
+import net.minecraft.util.math.Vec2f;
import net.minecraft.world.GameRules;
-import net.minecraft.world.World;
import net.minecraft.world.WorldProperties;
import net.minecraft.world.border.WorldBorder;
@@ -74,7 +73,9 @@ public class SystemInfo {
return ListValue.fromTriple(worldBorder.getCenterX(), 0, worldBorder.getCenterZ());
});
- put("world_size", c-> new NumericValue( c.s.getWorld().getWorldBorder().getMaxRadius()));
+ put("world_size", c -> new NumericValue(c.s.getWorld().getWorldBorder().getSize() / 2));
+
+ put("world_max_size", c-> new NumericValue( c.s.getWorld().getWorldBorder().getMaxRadius()));
put("world_time", c -> new NumericValue(c.s.getWorld().getTime()));
@@ -199,6 +200,15 @@ public class SystemInfo {
});
return MapValue.wrap(rules);
});
+
+ put("source_entity", c -> EntityValue.of(c.s.getEntity()));
+ put("source_position", c -> ValueConversions.of(c.s.getPosition()));
+ put("source_dimension", c -> ValueConversions.of(c.s.getWorld()));
+ put("source_rotation", c -> {
+ Vec2f rotation = c.s.getRotation();
+ return ListValue.of(new NumericValue(rotation.x), new NumericValue(rotation.y));
+ });
+
put("scarpet_version", c -> StringValue.of(CarpetSettings.carpetVersion));
}};
diff --git a/src/main/java/carpet/script/value/EntityValue.java b/src/main/java/carpet/script/value/EntityValue.java
index 1b58b8e3..dd761bc9 100644
--- a/src/main/java/carpet/script/value/EntityValue.java
+++ b/src/main/java/carpet/script/value/EntityValue.java
@@ -1,10 +1,8 @@
package carpet.script.value;
-import carpet.fakes.BrainInterface;
import carpet.fakes.EntityInterface;
import carpet.fakes.ItemEntityInterface;
import carpet.fakes.LivingEntityInterface;
-import carpet.fakes.MemoryInterface;
import carpet.fakes.MobEntityInterface;
import carpet.fakes.ServerPlayerEntityInterface;
import carpet.fakes.ServerPlayerInteractionManagerInterface;
@@ -633,11 +631,11 @@ public class EntityValue extends Value
if (e instanceof LivingEntity livingEntity)
{
Brain> brain = livingEntity.getBrain();
- Map, Optional extends Memory>>> memories = ((BrainInterface)brain).getMobMemories();
+ Map, Optional extends Memory>>> memories = brain.getMemories();
Optional extends Memory>> optmemory = memories.get(moduleType);
if (optmemory==null || !optmemory.isPresent()) return Value.NULL;
Memory> memory = optmemory.get();
- return ValueConversions.fromTimedMemory(e, ((MemoryInterface)memory).getScarpetExpiry(), memory.getValue());
+ return ValueConversions.fromTimedMemory(e, memory.getExpiry(), memory.getValue());
}
return Value.NULL;
});
@@ -1584,7 +1582,7 @@ public class EntityValue extends Value
});
put("absorption", (e, v) -> {
- if (e instanceof PlayerEntity) ((PlayerEntity) e).setAbsorptionAmount((float) NumericValue.asNumber(v, "absorbtion").getLong());
+ if (e instanceof PlayerEntity) ((PlayerEntity) e).setAbsorptionAmount(NumericValue.asNumber(v, "absorbtion").getFloat());
});
put("add_xp", (e, v) -> {
diff --git a/src/main/java/carpet/script/value/ThreadValue.java b/src/main/java/carpet/script/value/ThreadValue.java
index 30c63555..21b2e224 100644
--- a/src/main/java/carpet/script/value/ThreadValue.java
+++ b/src/main/java/carpet/script/value/ThreadValue.java
@@ -19,18 +19,29 @@ public class ThreadValue extends Value
private final long id;
private static long sequence = 0L;
+ public ThreadValue(CompletableFuture taskFuture)
+ {
+ this.taskFuture = taskFuture;
+ this.id = sequence++;
+ }
+
public ThreadValue(Value pool, FunctionValue function, Expression expr, Tokenizer.Token token, Context ctx, List args)
{
- id = sequence++;
+ this(getCompletableFutureFromFunction(pool, function, expr, token, ctx, args));
+ Thread.yield();
+ }
+
+ public static CompletableFuture getCompletableFutureFromFunction(Value pool, FunctionValue function, Expression expr, Tokenizer.Token token, Context ctx, List args)
+ {
ExecutorService executor = ctx.host.getExecutor(pool);
if (executor == null)
{
// app is shutting down - no more threads can be spawned.
- taskFuture = CompletableFuture.completedFuture(Value.NULL);
+ return CompletableFuture.completedFuture(Value.NULL);
}
else
{
- taskFuture = CompletableFuture.supplyAsync(
+ return CompletableFuture.supplyAsync(
() ->
{
try
@@ -52,7 +63,6 @@ public class ThreadValue extends Value
ctx.host.getExecutor(pool)
);
}
- Thread.yield();
}
@Override
diff --git a/src/main/java/carpet/utils/Messenger.java b/src/main/java/carpet/utils/Messenger.java
index e5a6c7f2..0fcfc050 100644
--- a/src/main/java/carpet/utils/Messenger.java
+++ b/src/main/java/carpet/utils/Messenger.java
@@ -103,23 +103,18 @@ public class Messenger
}
public static String creatureTypeColor(SpawnGroup type)
{
- switch (type)
+ return switch (type)
{
- case MONSTER:
- return "n";
- case CREATURE:
- return "e";
- case AMBIENT:
- return "f";
- case WATER_CREATURE:
- return "v";
- case WATER_AMBIENT:
- return "q";
- }
- return "w";
+ case MONSTER -> "n";
+ case CREATURE -> "e";
+ case AMBIENT -> "f";
+ case WATER_CREATURE -> "v";
+ case WATER_AMBIENT -> "q";
+ default -> "w"; // missing MISC and UNDERGROUND_WATER_CREATURE
+ };
}
- private static BaseText _getChatComponentFromDesc(String message, BaseText previous_message)
+ private static BaseText getChatComponentFromDesc(String message, BaseText previousMessage)
{
if (message.equalsIgnoreCase(""))
{
@@ -127,7 +122,7 @@ public class Messenger
}
if (Character.isWhitespace(message.charAt(0)))
{
- message = "w"+message;
+ message = "w" + message;
}
int limit = message.indexOf(' ');
String desc = message;
@@ -137,52 +132,37 @@ public class Messenger
desc = message.substring(0, limit);
str = message.substring(limit+1);
}
- if (desc.charAt(0) == '/') // deprecated
- {
- if (previous_message != null)
- previous_message.setStyle(
- previous_message.getStyle().withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, message))
- );
- return previous_message;
+ if (previousMessage == null) {
+ BaseText text = new LiteralText(str);
+ text.setStyle(parseStyle(desc));
+ return text;
}
- if (desc.charAt(0) == '?')
- {
- if (previous_message != null)
- previous_message.setStyle(
- previous_message.getStyle().withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, message.substring(1)))
- );
- return previous_message;
- }
- if (desc.charAt(0) == '!')
- {
- if (previous_message != null)
- previous_message.setStyle(
- previous_message.getStyle().withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, message.substring(1)))
- );
- return previous_message;
- }
- if (desc.charAt(0) == '^')
- {
- if (previous_message != null)
- previous_message.setStyle(
- previous_message.getStyle().withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, c(message.substring(1))))
- );
- return previous_message;
- }
- BaseText txt = new LiteralText(str);
- txt.setStyle(parseStyle(desc));
- return txt;
+ Style previousStyle = previousMessage.getStyle();
+ BaseText ret = previousMessage;
+ previousMessage.setStyle(switch (desc.charAt(0)) {
+ case '?' -> previousStyle.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, message.substring(1)));
+ case '!' -> previousStyle.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, message.substring(1)));
+ case '^' -> previousStyle.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, c(message.substring(1))));
+ case '@' -> previousStyle.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, message.substring(1)));
+ case '&' -> previousStyle.withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, message.substring(1)));
+ default -> { // Create a new component
+ ret = new LiteralText(str);
+ ret.setStyle(parseStyle(desc));
+ yield previousStyle; // no op for the previous style
+ }
+ });
+ return ret;
}
public static BaseText tp(String desc, Vec3d pos) { return tp(desc, pos.x, pos.y, pos.z); }
public static BaseText tp(String desc, BlockPos pos) { return tp(desc, pos.getX(), pos.getY(), pos.getZ()); }
public static BaseText tp(String desc, double x, double y, double z) { return tp(desc, (float)x, (float)y, (float)z);}
public static BaseText tp(String desc, float x, float y, float z)
{
- return _getCoordsTextComponent(desc, x, y, z, false);
+ return getCoordsTextComponent(desc, x, y, z, false);
}
public static BaseText tp(String desc, int x, int y, int z)
{
- return _getCoordsTextComponent(desc, (float)x, (float)y, (float)z, true);
+ return getCoordsTextComponent(desc, (float)x, (float)y, (float)z, true);
}
/// to be continued
@@ -232,7 +212,7 @@ public class Messenger
return c(components.toArray(new Object[0]));
}
- private static BaseText _getCoordsTextComponent(String style, float x, float y, float z, boolean isInt)
+ private static BaseText getCoordsTextComponent(String style, float x, float y, float z, boolean isInt)
{
String text;
String command;
@@ -266,19 +246,19 @@ public class Messenger
public static BaseText c(Object ... fields)
{
BaseText message = new LiteralText("");
- BaseText previous_component = null;
+ BaseText previousComponent = null;
for (Object o: fields)
{
if (o instanceof BaseText)
{
message.append((BaseText)o);
- previous_component = (BaseText)o;
+ previousComponent = (BaseText)o;
continue;
}
String txt = o.toString();
- BaseText comp = _getChatComponentFromDesc(txt,previous_component);
- if (comp != previous_component) message.append(comp);
- previous_component = comp;
+ BaseText comp = getChatComponentFromDesc(txt, previousComponent);
+ if (comp != previousComponent) message.append(comp);
+ previousComponent = comp;
}
return message;
}
diff --git a/src/main/resources/carpet.mixins.json b/src/main/resources/carpet.mixins.json
index 4ccacbc7..8f5d8084 100644
--- a/src/main/resources/carpet.mixins.json
+++ b/src/main/resources/carpet.mixins.json
@@ -67,8 +67,6 @@
"EntityTrackerEntry_leashFixMixin",
"VillagerEntity_aiMixin",
- "Brain_Mixin",
- "Memory_scarpetMixin",
"PlayerEntity_fakePlayersMixin",
"ThrownEnderpearlEntity_fakePlayersMixin",
@@ -190,7 +188,6 @@
"Team_scarpetMixin",
"TradeOutputSlot_scarpetEventMixin",
- "BiomeEffects_scarpetMixin",
"ChunkTicketManager_scarpetMixin",
"PointOfInterest_scarpetMixin",
"ServerWorld_scarpetMixin",
diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json
index fbefa022..4e037ea4 100644
--- a/src/main/resources/fabric.mod.json
+++ b/src/main/resources/fabric.mod.json
@@ -33,7 +33,7 @@
"depends": {
"minecraft": "1.18.x",
- "fabricloader": ">=0.11.6",
+ "fabricloader": ">=0.12.8",
"java": ">=17"
}
}