Merge branch 'master' into future

# Conflicts:
#	gradle.properties
#	src/main/java/carpet/script/annotation/AnnotationParser.java
#	src/main/java/carpet/script/utils/BiomeInfo.java
#	src/main/resources/fabric.mod.json
This commit is contained in:
gnembon committed 2022-01-11 23:44:52 +01:00
commit 529a5b358d
38 files changed
+247 -381

No files matched your search

+5 -2
View File
@@ -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 specific Y coordinate of the biome you want to change, and it affects roughly 4x4x4 area (give or take some random
noise). 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. Throws `unknown_biome` if the `biome_name` doesn't exist.
### `update(pos)` ### `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. 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: 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 * `'top_material'`: unlocalized block representing the top surface material (1.17.1 and below only)
* `'under_material'`: unlocalized block representing what sits below topsoil * `'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: * `'category'`: the parent biome this biome is derived from. Possible values include:
`'none'`, `'taiga'`, `'extreme_hills'`, `'jungle'`, `'mesa'`, `'plains'`, `'savanna'`, `'none'`, `'taiga'`, `'extreme_hills'`, `'jungle'`, `'mesa'`, `'plains'`, `'savanna'`,
`'icy'`, `'the_end'`, `'beach'`, `'forest'`, `'ocean'`, `'desert'`, `'river'`, `'icy'`, `'the_end'`, `'beach'`, `'forest'`, `'ocean'`, `'desert'`, `'river'`,
+26 -9
View File
@@ -252,6 +252,8 @@ Decorators (listed as extra argument after the component they would affect):
* `'^<format> <text>'` - hover over tooltip text, appearing when hovering with your mouse over the text below. * `'^<format> <text>'` - hover over tooltip text, appearing when hovering with your mouse over the text below.
* `'?<suggestion>` - command suggestion - a message that will be pasted to chat when text below it is clicked. * `'?<suggestion>` - command suggestion - a message that will be pasted to chat when text below it is clicked.
* `'!<message>'` - a chat message that will be executed when the text below it is clicked. * `'!<message>'` - a chat message that will be executed when the text below it is clicked.
* `'@<url>'` - a URL that will be opened when the text below it is clicked.
* `'&<text>'` - 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. 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 fetch various information, mostly not changing, or only available via low level
system calls. In all circumstances, these are only provided as read-only. 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_name` - current app name or `null` if its a default app
* `app_list` - list of all loaded apps excluding default commandline 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_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_name` - name of the world
* `world_seed` - a numeric seed of the world * `world_seed` - a numeric seed of the world
* `world_dimensions` - a list of dimensions in 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_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_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_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_difficulty` - current difficulty of the game: `'peaceful'`, `'easy'`, `'normal'`, or `'hard'`
* `game_hardcore` - boolean whether the game is in hardcore mode * `game_hardcore` - boolean whether the game is in hardcore mode
* `game_storage_format` - format of the world save files, either `'McRegion'` or `'Anvil'` * `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_version` - base version of the game
* `game_target` - target release version * `game_target` - target release version
* `game_major_target` - major release target. For 1.12.2, that would be 12 * `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_protocol` - protocol version number
* `game_pack_version` - datapack 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_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 * `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_motd` - the motd of the server visible when joining
* `server_ip` - IP adress of the game hosted * `server_ip` - IP adress of the game hosted
* `server_whitelisted` - boolean indicating whether the access to the server is only for whitelisted players * `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 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. 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_max_memory` - maximum allowed memory accessible by JVM
* `java_allocated_memory` - currently allocated memory by JVM * `java_allocated_memory` - currently allocated memory by JVM
* `java_used_memory` - currently used 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_system_cpu_load` - current percentage of CPU used by the system
* `java_process_cpu_load` - current percentage of CPU used by JVM * `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. * `scarpet_version` - returns the version of the carpet your scarpet comes with.
## NBT Storage ## NBT Storage
+6 -7
View File
@@ -157,12 +157,11 @@ Throws `unknown_poi` if the provided point of interest doesn't exist
### `set_biome(pos, biome_name, update=true)` ### `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 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 Be aware that depending on the MC version and dimension settings biome can be set either in a 1x1x256
is only effective if you set it at y=0, and affects the entire column of. In the nether - you have to use the column or 4x4x4 hyperblock, so for some versions Y will be ignored and for some precision of biome
specific Y coordinate of the biome you want to change, and it affects roughly 4x4x4 area (give or take some random setting is less than 1x1x1 block.
noise).
Throws `unknown_biome` if the `biome_name` doesn't exist. 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. 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: 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 * `'top_material'`: unlocalized block representing the top surface material (1.17.1 and below only)
* `'under_material'`: unlocalized block representing what sits below topsoil * `'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: * `'category'`: the parent biome this biome is derived from. Possible values include:
`'none'`, `'taiga'`, `'extreme_hills'`, `'jungle'`, `'mesa'`, `'plains'`, `'savanna'`, `'none'`, `'taiga'`, `'extreme_hills'`, `'jungle'`, `'mesa'`, `'plains'`, `'savanna'`,
`'icy'`, `'the_end'`, `'beach'`, `'forest'`, `'ocean'`, `'desert'`, `'river'`, `'icy'`, `'the_end'`, `'beach'`, `'forest'`, `'ocean'`, `'desert'`, `'river'`,
+10 -4
View File
@@ -202,13 +202,19 @@ List of entities riding the entity.
Entity that `e` rides. Entity that `e` rides.
### `query(e, 'scoreboard_tags')` and ### `(deprecated) query(e, 'tags')`
### `query(e, 'tags')`(deprecated)
Deprecated by `query(e, 'scoreboard_tags')`
### `query(e, 'scoreboard_tags')`
List of entity's scoreboard tags. List of entity's scoreboard tags.
### `query(e, 'has_scoreboard_tag',tag)` and ### `(deprecated) query(e, 'has_tag',tag)`
### `query(e, 'has_tag',tag)`(deprecated)
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. Boolean, true if the entity is marked with a `tag` scoreboad tag.
+1 -1
View File
@@ -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). 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. `'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. 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 * `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. descriptors, like the above `resources` field.
``` ```
+1 -1
View File
@@ -110,7 +110,7 @@ Or an example to find if a player has specific enchantment on a held axe (either
<pre> <pre>
global_get_enchantment(p, ench) -> ( global_get_enchantment(p, ench) -> (
$ for(['main','offhand'], $ for(['mainhand','offhand'],
$ holds = query(p, 'holds', _); $ holds = query(p, 'holds', _);
$ if( holds, $ if( holds,
$ [what, count, nbt] = holds; $ [what, count, nbt] = holds;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 105 KiB

+1 -1
View File
@@ -6,7 +6,7 @@ org.gradle.jvmargs=-Xmx1G
# or better: https://modmuss50.me/fabric.html # or better: https://modmuss50.me/fabric.html
minecraft_version=1.18 minecraft_version=1.18
yarn_mappings=1.18+build.1 yarn_mappings=1.18+build.1
loader_version=0.12.6 loader_version=0.12.12
fabric_version=0.43.1+1.18 fabric_version=0.43.1+1.18
# Mod Properties # Mod Properties
@@ -299,6 +299,9 @@ public class PlayerCommand
{ {
// Force override flying to true for spectator players, or they will fell out of the world. // Force override flying to true for spectator players, or they will fell out of the world.
flying = true; 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"); String playerName = StringArgumentType.getString(context, "player");
if (playerName.length()>maxPlayerLength(source.getServer())) if (playerName.length()>maxPlayerLength(source.getServer()))
@@ -51,10 +51,10 @@ public class TickCommand
then(literal("deep").executes( (c)-> setFreeze(c.getSource(), true, true)))). then(literal("deep").executes( (c)-> setFreeze(c.getSource(), true, true)))).
then(literal("off").executes( (c) -> setFreeze(c.getSource(), false, false)))). then(literal("off").executes( (c) -> setFreeze(c.getSource(), false, false)))).
then(literal("step"). then(literal("step").
executes((c) -> step(1)). executes((c) -> step(c.getSource(), 1)).
then(argument("ticks", integer(1,72000)). then(argument("ticks", integer(1,72000)).
suggests( (c, b) -> suggestMatching(new String[]{"20"},b)). 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("superHot").executes( (c)-> toggleSuperHot(c.getSource()))).
then(literal("health"). then(literal("health").
executes( (c) -> healthReport(c.getSource(), 100)). executes( (c) -> healthReport(c.getSource(), 100)).
@@ -130,9 +130,10 @@ public class TickCommand
return setFreeze(source, isDeep, !TickSpeed.isPaused()); 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); TickSpeed.add_ticks_to_run_in_pause(advance);
Messenger.m(source, "gi Stepping " + advance + " tick" + (advance != 1 ? "s" : ""));
return 1; return 1;
} }
@@ -1,12 +0,0 @@
package carpet.fakes;
import java.util.Optional;
public interface BiomeEffectsInterface
{
int getCMFogColor();
Optional<Integer> getCMFoliageColor();
int getCMSkyColor();
int getCMWaterColor();
int getCMWaterFogColor();
}
@@ -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<MemoryModuleType<?>, Optional<? extends Memory<?>>> getMobMemories();
}
@@ -2,6 +2,5 @@ package carpet.fakes;
public interface ItemEntityInterface public interface ItemEntityInterface
{ {
int getAgeCM();
int getPickupDelayCM(); int getPickupDelayCM();
} }
@@ -1,6 +0,0 @@
package carpet.fakes;
public interface MemoryInterface
{
long getScarpetExpiry();
}
@@ -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<Integer> 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<Integer> getCMFoliageColor()
{
return foliageColor;
}
@Override
public int getCMSkyColor()
{
return skyColor;
}
@Override
public int getCMWaterColor()
{
return waterColor;
}
@Override
public int getCMWaterFogColor()
{
return waterFogColor;
}
}
@@ -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<MemoryModuleType<?>, Optional<? extends Memory<?>>> memories;
@Override
public Map<MemoryModuleType<?>, Optional<? extends Memory<?>>> getMobMemories()
{
return memories;
}
}
@@ -42,11 +42,6 @@ public abstract class ItemEntityMixin extends Entity implements ItemEntityInterf
} }
} }
@Override
public int getAgeCM() {
return this.itemAge;
}
@Override @Override
public int getPickupDelayCM() { public int getPickupDelayCM() {
return this.pickupDelay; return this.pickupDelay;
@@ -105,7 +100,7 @@ public abstract class ItemEntityMixin extends Entity implements ItemEntityInterf
self.setStack(selfStack); self.setStack(selfStack);
this.pickupDelay = Math.max(((ItemEntityInterface)other).getPickupDelayCM(), this.pickupDelay); 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); otherStack.decrement(amount);
if (otherStack.isEmpty()) if (otherStack.isEmpty())
@@ -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;
}
}
@@ -1,7 +1,5 @@
package carpet.mixins; package carpet.mixins;
import carpet.fakes.BrainInterface;
import carpet.fakes.MemoryInterface;
import carpet.helpers.ParticleDisplay; import carpet.helpers.ParticleDisplay;
import carpet.utils.Messenger; import carpet.utils.Messenger;
import carpet.utils.MobAI; import carpet.utils.MobAI;
@@ -65,14 +63,14 @@ public abstract class VillagerEntity_aiMixin extends MerchantEntity
if (MobAI.isTracking(this, MobAI.TrackingType.IRON_GOLEM_SPAWNING)) if (MobAI.isTracking(this, MobAI.TrackingType.IRON_GOLEM_SPAWNING))
{ {
long time; 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()) if (!last_seen.isPresent())
{ {
time = 0; time = 0;
} }
else else
{ {
time = ((MemoryInterface)last_seen.get()).getScarpetExpiry(); time = last_seen.get().getExpiry();
} }
boolean recentlySeen = time > 0; boolean recentlySeen = time > 0;
Optional<Long> optional_11 = this.brain.getOptionalMemory(MemoryModuleType.LAST_SLEPT); Optional<Long> optional_11 = this.brain.getOptionalMemory(MemoryModuleType.LAST_SLEPT);
@@ -91,7 +91,7 @@ public class CarpetExpression
public Value scriptRunCommand(ScriptHost host, BlockPos pos) public Value scriptRunCommand(ScriptHost host, BlockPos pos)
{ {
if (CarpetServer.scriptServer.stopAll) if (CarpetServer.scriptServer.stopAll)
throw new CarpetExpressionException("SCRIPTING PAUSED", null); throw new CarpetExpressionException("SCRIPTING PAUSED (unpause with /script resume)", null);
try try
{ {
Context context = new CarpetContext(host, source, origin). Context context = new CarpetContext(host, source, origin).
@@ -13,6 +13,7 @@ import carpet.script.exception.ExpressionException;
import carpet.script.exception.IntegrityException; import carpet.script.exception.IntegrityException;
import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.InvalidCallbackException; import carpet.script.exception.InvalidCallbackException;
import carpet.script.exception.LoadException;
import carpet.script.utils.AppStoreManager; import carpet.script.utils.AppStoreManager;
import carpet.script.value.EntityValue; import carpet.script.value.EntityValue;
import carpet.script.value.FunctionValue; 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.SemanticVersion;
import net.fabricmc.loader.api.Version; import net.fabricmc.loader.api.Version;
import net.fabricmc.loader.api.VersionParsingException; import net.fabricmc.loader.api.VersionParsingException;
import net.fabricmc.loader.api.metadata.version.VersionPredicate;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtElement;
@@ -60,7 +62,6 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.function.BiPredicate;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -119,8 +120,7 @@ public class CarpetScriptHost extends ScriptHost
String code = module.getCode(); String code = module.getCode();
if (code == null) if (code == null)
{ {
Messenger.m(source, "r Unable to load "+module.getName()+" app - code not found"); throw new LoadException("Code not found");
return null;
} }
host.setChatErrorSnooper(source); host.setChatErrorSnooper(source);
CarpetExpression ex = new CarpetExpression(host.main, code, source, new BlockPos(0, 0, 0)); 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) catch (CarpetExpressionException e)
{ {
host.handleErrorWithStack("Error while evaluating expression", e); host.handleErrorWithStack("Error while evaluating expression", e);
host.resetErrorSnooper(); throw new LoadException();
return null;
} }
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); host.handleErrorWithStack("Math doesn't compute", ae);
return null; throw new LoadException();
} }
catch (StackOverflowError soe) catch (StackOverflowError soe)
{ {
@@ -314,7 +313,7 @@ public class CarpetScriptHost extends ScriptHost
{ {
Value reqResult = callNow((FunctionValue) loadRequirements, Collections.emptyList()); Value reqResult = callNow((FunctionValue) loadRequirements, Collections.emptyList());
if (reqResult.getBoolean()) // != false or null if (reqResult.getBoolean()) // != false or null
throw new InternalExpressionException(reqResult.getString()); throw new LoadException(reqResult.getString());
} }
else else
{ {
@@ -422,20 +421,6 @@ public class CarpetScriptHost extends ScriptHost
return addLegacyCommand(notifier); 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<String, BiPredicate<SemanticVersion, SemanticVersion>> VERSION_PREFIXES = new HashMap<String, BiPredicate<SemanticVersion, SemanticVersion>>() {{
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) { public void checkModVersionRequirements(Value reqs) {
if (reqs == null) if (reqs == null)
return; return;
@@ -446,58 +431,25 @@ public class CarpetScriptHost extends ScriptHost
Map<Value, Value> requirements = ((MapValue)reqs).getMap(); Map<Value, Value> requirements = ((MapValue)reqs).getMap();
for (Entry<Value, Value> requirement : requirements.entrySet()) for (Entry<Value, Value> requirement : requirements.entrySet())
{ {
boolean successful = false;
String requiredModId = requirement.getKey().getString(); 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); ModContainer mod = FabricLoader.getInstance().getModContainer(requiredModId).orElse(null);
if (mod != null) if (mod != null)
{ {
if (requirementString.equals("*"))
continue;
Version presentVersion = mod.getMetadata().getVersion(); Version presentVersion = mod.getMetadata().getVersion();
BiPredicate<SemanticVersion, SemanticVersion> tester = null; if (predicate.test(presentVersion) || (FabricLoader.getInstance().isDevelopmentEnvironment() && !(presentVersion instanceof SemanticVersion)))
String remainingRequirementString = requirementString; { // in a dev env, mod version is usually replaced with ${version}, and that isn't semantic
for (Entry<String, BiPredicate<SemanticVersion, SemanticVersion>> s : VERSION_PREFIXES.entrySet()) continue;
{
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 (!successful) throw new LoadException(String.format("%s requires a version of mod '%s' matching '%s', which is missing!", getName(), requiredModId, stringPredicate));
{
throw new InternalExpressionException(getName()+" requires " + requiredModId + " version " + requirementString + " in order to load");
}
} }
} }
@@ -732,10 +684,10 @@ public class CarpetScriptHost extends ScriptHost
public Value callLegacy(ServerCommandSource source, String call, List<Integer> coords, String arg) public Value callLegacy(ServerCommandSource source, String call, List<Integer> coords, String arg)
{ {
if (CarpetServer.scriptServer.stopAll) if (CarpetServer.scriptServer.stopAll)
throw new CarpetExpressionException("SCARPET PAUSED", null); throw new CarpetExpressionException("SCARPET PAUSED (unpause with /script resume)", null);
FunctionValue function = getFunction(call); FunctionValue function = getFunction(call);
if (function == null) if (function == null)
throw new CarpetExpressionException("UNDEFINED", null); throw new CarpetExpressionException("Couldn't find function '" + call + "' in app '" + this.getName() + "'", null);
List<LazyValue> argv = new ArrayList<>(); List<LazyValue> argv = new ArrayList<>();
if (coords != null) if (coords != null)
for (Integer i: coords) for (Integer i: coords)
@@ -832,7 +784,7 @@ public class CarpetScriptHost extends ScriptHost
public Value call(ServerCommandSource source, FunctionValue function, List<Value> argv) public Value call(ServerCommandSource source, FunctionValue function, List<Value> argv)
{ {
if (CarpetServer.scriptServer.stopAll) if (CarpetServer.scriptServer.stopAll)
throw new CarpetExpressionException("SCARPET PAUSED", null); throw new CarpetExpressionException("SCARPET PAUSED (unpause with /script resume)", null);
List<String> args = function.getArguments(); List<String> args = function.getArguments();
if (argv.size() != args.size()) if (argv.size() != args.size())
@@ -13,6 +13,7 @@ import carpet.CarpetServer;
import carpet.script.bundled.FileModule; import carpet.script.bundled.FileModule;
import carpet.script.bundled.Module; import carpet.script.bundled.Module;
import carpet.script.exception.ExpressionException; import carpet.script.exception.ExpressionException;
import carpet.script.exception.LoadException;
import carpet.script.language.Arithmetic; import carpet.script.language.Arithmetic;
import carpet.script.language.ControlFlow; import carpet.script.language.ControlFlow;
import carpet.script.language.DataStructures; import carpet.script.language.DataStructures;
@@ -256,10 +257,14 @@ public class CarpetScriptServer
Messenger.m(source, "r Failed to add "+name+" app"); Messenger.m(source, "r Failed to add "+name+" app");
return false; return false;
} }
CarpetScriptHost newHost = CarpetScriptHost.create(this, module, perPlayer, source, commandValidator, isRuleApp, installer); CarpetScriptHost newHost;
if (newHost == null) 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; return false;
} }
// config needs to be read as we load the app since some events use that info // config needs to be read as we load the app since some events use that info
+7 -4
View File
@@ -481,9 +481,9 @@ public class Expression
} }
public void addLazyFunction(String name, int num_params, TriFunction<Context, Context.Type, List<LazyValue>, LazyValue> fun) public void addLazyFunction(String name, int numParams, TriFunction<Context, Context.Type, List<LazyValue>, LazyValue> fun)
{ {
functions.put(name, new AbstractLazyFunction(num_params, name) functions.put(name, new AbstractLazyFunction(numParams, name)
{ {
@Override @Override
public boolean pure() { public boolean pure() {
@@ -499,8 +499,11 @@ public class Expression
public LazyValue lazyEval(Context c, Context.Type i, Expression e, Tokenizer.Token t, List<LazyValue> lazyParams) public LazyValue lazyEval(Context c, Context.Type i, Expression e, Tokenizer.Token t, List<LazyValue> lazyParams)
{ {
ILazyFunction.checkInterrupts(); ILazyFunction.checkInterrupts();
if (num_params >= 0 && lazyParams.size() != num_params) if (numParams >= 0 && lazyParams.size() != numParams)
throw new InternalExpressionException("'"+name+"' requires "+num_params+" parameters, "+lazyParams.size()+" provided."); {
String error = "Function '"+name+"' requires "+numParams+" arguments, got "+lazyParams.size()+". ";
throw new InternalExpressionException(error + (fun instanceof Fluff.UsageProvider up ? up.getUsage() : ""));
}
try try
{ {
+2
View File
@@ -30,6 +30,8 @@ public abstract class Fluff
@FunctionalInterface @FunctionalInterface
public interface SexFunction<A, B, C, D, E, F, R> { R apply(A a, B b, C c, D d, E e, F f);} public interface SexFunction<A, B, C, D, E, F, R> { R apply(A a, B b, C c, D d, E e, F f);}
public interface UsageProvider { String getUsage();}
public interface EvalNode public interface EvalNode
{ {
/** /**
@@ -21,6 +21,7 @@ import carpet.script.Context;
import carpet.script.Expression; import carpet.script.Expression;
import carpet.script.Fluff.AbstractLazyFunction; import carpet.script.Fluff.AbstractLazyFunction;
import carpet.script.Fluff.TriFunction; import carpet.script.Fluff.TriFunction;
import carpet.script.Fluff.UsageProvider;
import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InternalExpressionException;
import carpet.script.LazyValue; import carpet.script.LazyValue;
import carpet.script.value.Value; import carpet.script.value.Value;
@@ -73,6 +74,7 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList;
*/ */
public final class AnnotationParser public final class AnnotationParser
{ {
static final int UNDEFINED_PARAMS = -2;
private static final List<ParsedFunction> functionList = new ArrayList<>(); private static final List<ParsedFunction> functionList = new ArrayList<>();
/** /**
@@ -90,8 +92,8 @@ public final class AnnotationParser
* {@link InternalExpressionException}). * {@link InternalExpressionException}).
* Basically, it's fine as long as you don't add a {@code throws} declaration to your methods.</li> * Basically, it's fine as long as you don't add a {@code throws} declaration to your methods.</li>
* <li>Varargs (or effectively varargs) annotated methods must explicitly declare a maximum number of parameters to ingest in the {@link ScarpetFunction} * <li>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 * annotation. They can still declare an unlimited amount by setting that maximum to {@link ScarpetFunction#UNLIMITED_PARAMS}. "Effectively varargs"
* a parameter using/requiring a {@link ValueConverter} that has declared {@link ValueConverter#consumesVariableArgs()}.</li> * means a function that has at least a parameter requiring a {@link ValueConverter} that has declared {@link ValueConverter#consumesVariableArgs()}.</li>
* <li>Annotated methods must not have a parameter with generics as the varargs parameter. This is just because it was painful for me (altrisi) and * <li>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}</li> * didn't want to support it. Those will crash with a {@code ClassCastException}</li>
* </ul> * </ul>
@@ -141,7 +143,7 @@ public final class AnnotationParser
expr.addLazyFunction(function.name, function.scarpetParamCount, function); expr.addLazyFunction(function.name, function.scarpetParamCount, function);
} }
private static class ParsedFunction implements TriFunction<Context, Context.Type, List<LazyValue>, LazyValue> private static class ParsedFunction implements TriFunction<Context, Context.Type, List<LazyValue>, LazyValue>, UsageProvider
{ {
private final String name; private final String name;
private final boolean isMethodVarArgs; private final boolean isMethodVarArgs;
@@ -186,10 +188,10 @@ public final class AnnotationParser
if (this.isEffectivelyVarArgs) if (this.isEffectivelyVarArgs)
{ {
maxParams = method.getAnnotation(ScarpetFunction.class).maxParams(); maxParams = method.getAnnotation(ScarpetFunction.class).maxParams();
if (maxParams == -2) if (maxParams == UNDEFINED_PARAMS)
throw new IllegalArgumentException("No maximum number of params specified for " + name + ", use -1 for unlimited. " throw new IllegalArgumentException("No maximum number of params specified for " + name + ", use ScarpetFunction.UNLIMITED_PARAMS for unlimited. "
+ "Provided in " + instance.getClass()); + "Provided in " + instance.getClass());
if (maxParams == -1) if (maxParams == ScarpetFunction.UNLIMITED_PARAMS)
maxParams = Integer.MAX_VALUE; maxParams = Integer.MAX_VALUE;
if (maxParams < this.minParams) if (maxParams < this.minParams)
throw new IllegalArgumentException("Provided maximum number of params for " + name + " is smaller than method's param count." 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; return params;
} }
private String getUsage() @Override
public String getUsage()
{ {
// Possibility: More descriptive messages using param.getName()? Would need changing gradle setup to keep those // Possibility: More descriptive messages using param.getName()? Would need changing gradle setup to keep those
StringBuilder builder = new StringBuilder("Usage: '"); StringBuilder builder = new StringBuilder("Usage: '");
@@ -51,6 +51,11 @@ import carpet.script.value.Value;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface ScarpetFunction public @interface ScarpetFunction
{ {
/**
* <p>Used to define that this {@link ScarpetFunction} can accept an unlimited number of parameters</p>
*/
public static final int UNLIMITED_PARAMS = -1;
/** /**
* <p>If the function can accept a variable number of parameters, either by declaring its last parameter as a varargs parameter or by having one * <p>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 * 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 * 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.</p> * parameters.</p>
* *
* <p>Use -1 to specify an unlimited number of parameters.</p> * <p>Use {@link ScarpetFunction#UNLIMITED_PARAMS} to allow an unlimited number of parameters.</p>
* *
* @return The maximum number of parameters this function can accept * @return The maximum number of parameters this function can accept
*/ */
int maxParams() default -2; int maxParams() default AnnotationParser.UNDEFINED_PARAMS;
/** /**
* <p>Defines the Context Type that will be used when evaluating arguments to annotated methods.</p> * <p>Defines the Context Type that will be used when evaluating arguments to annotated methods.</p>
@@ -162,13 +162,13 @@ public interface ValueConverter<R>
* constraints as {@link #convert(Value)}</p> * constraints as {@link #convert(Value)}</p>
* @param valueIterator An {@link Iterator} holding the {@link Value} to convert in next position * @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 * @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 * evaluate, now it's used to get the context
* @param theLazyT The {@code t} that the original function was called with. It is ignored by the default implementation. * @param contextType The {@link Context.Type} that the original function was called with
* @return The next {@link Value} (s) converted to the type {@code <R>} of this {@link ValueConverter} * @return The next {@link Value} (s) converted to the type {@code <R>} 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 * @implNote This method's default implementation runs the {@link #convert(Value)} function in the next {@link Value} ignoring {@link Context} and
* {@code theLazyT}. * {@code theLazyT}.
*/ */
default public R checkAndConvert(Iterator<Value> valueIterator, Context context, Context.Type theLazyT) default public R checkAndConvert(Iterator<Value> valueIterator, Context context, Context.Type contextType)
{ {
if (!valueIterator.hasNext()) if (!valueIterator.hasNext())
return null; return null;
@@ -676,7 +676,7 @@ public class Auxiliary {
expression.addContextFunction("last_tick_times", -1, (c, t, lv) -> expression.addContextFunction("last_tick_times", -1, (c, t, lv) ->
{ {
c.host.issueDeprecation("last_tick_times()"); 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; return Value.TRUE;
}); });
// Should this be deprecated for system_info('source_dimension')?
expression.addContextFunction("current_dimension", 0, (c, t, lv) -> expression.addContextFunction("current_dimension", 0, (c, t, lv) ->
ValueConversions.of( ((CarpetContext)c).s.getWorld())); ValueConversions.of( ((CarpetContext)c).s.getWorld()));
+32 -44
View File
@@ -3,6 +3,7 @@ package carpet.script.api;
import carpet.script.CarpetContext; import carpet.script.CarpetContext;
import carpet.script.CarpetEventServer; import carpet.script.CarpetEventServer;
import carpet.script.CarpetScriptHost; import carpet.script.CarpetScriptHost;
import carpet.script.Context;
import carpet.script.Expression; import carpet.script.Expression;
import carpet.script.argument.FunctionArgument; import carpet.script.argument.FunctionArgument;
import carpet.script.argument.Vector3Argument; import carpet.script.argument.Vector3Argument;
@@ -36,9 +37,20 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class Entities { public class Entities {
private static ListValue getPlayersFromWorldMatching(Context c, Predicate<ServerPlayerEntity> condition) {
List<Value> 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) public static void apply(Expression expression)
{ {
expression.addContextFunction("player", -1, (c, t, lv) -> expression.addContextFunction("player", -1, (c, t, lv) ->
@@ -58,50 +70,26 @@ public class Entities {
return EntityValue.of(closestPlayer); return EntityValue.of(closestPlayer);
} }
String playerName = lv.get(0).getString(); String playerName = lv.get(0).getString();
Value retval = Value.NULL; return switch (playerName) {
if ("all".equalsIgnoreCase(playerName)) case "all" -> {
{ List<Value> ret = new ArrayList<>();
retval = ListValue.wrap( for (ServerPlayerEntity player: ((CarpetContext)c).s.getServer().getPlayerManager().getPlayerList())
((CarpetContext)c).s.getServer().getPlayerManager().getPlayerList(). ret.add(new EntityValue(player));
stream().map(EntityValue::new).collect(Collectors.toList())); yield ListValue.wrap(ret);
} }
else if ("*".equalsIgnoreCase(playerName)) case "*" -> getPlayersFromWorldMatching(c, p -> true);
{ case "survival" -> getPlayersFromWorldMatching(c, p -> p.interactionManager.isSurvivalLike());
retval = ListValue.wrap( case "creative" -> getPlayersFromWorldMatching(c, PlayerEntity::isCreative);
((CarpetContext)c).s.getWorld().getPlayers(). case "spectating" -> getPlayersFromWorldMatching(c, PlayerEntity::isSpectator);
stream().map(EntityValue::new).collect(Collectors.toList())); case "!spectating" -> getPlayersFromWorldMatching(c, p -> !p.isSpectator());
} default -> {
else if ("survival".equalsIgnoreCase(playerName)) ServerPlayerEntity player = ((CarpetContext) c).s.getServer().getPlayerManager().getPlayer(playerName);
{ if (player != null) {
retval = ListValue.wrap( yield new EntityValue(player);
((CarpetContext)c).s.getWorld().getPlayers((p) -> p.interactionManager.isSurvivalLike()). }
stream().map(EntityValue::new).collect(Collectors.toList())); yield Value.NULL;
} }
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;
}); });
expression.addContextFunction("spawn", -1, (c, t, lv) -> expression.addContextFunction("spawn", -1, (c, t, lv) ->
@@ -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);
}
}
@@ -8,9 +8,7 @@ import carpet.script.value.NumericValue;
import carpet.script.value.StringValue; import carpet.script.value.StringValue;
import carpet.script.value.Value; import carpet.script.value.Value;
import carpet.script.value.ValueConversions; import carpet.script.value.ValueConversions;
import net.minecraft.client.color.world.FoliageColors;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.Registry;
import net.minecraft.world.biome.Biome; import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.feature.ConfiguredFeature; 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("under_material", (w, b) -> new BlockValue( b.getGenerationSettings().getSurfaceConfig().getUnderMaterial(), null, null));
put("category", (w, b) -> StringValue.of(b.getCategory().getName())); put("category", (w, b) -> StringValue.of(b.getCategory().getName()));
put("temperature", (w, b) -> NumericValue.of(b.getTemperature())); put("temperature", (w, b) -> NumericValue.of(b.getTemperature()));
put("fog_color", (w, b) -> ValueConversions.ofRGB(((BiomeEffectsInterface)b.getEffects()).getCMFogColor())); put("fog_color", (w, b) -> ValueConversions.ofRGB(b.getEffects().getFogColor()));
put("foliage_color", (w, b) -> ValueConversions.ofRGB(((BiomeEffectsInterface)b.getEffects()).getCMFoliageColor().orElse(4764952))); // client Biome.getDefaultFoliageColor put("foliage_color", (w, b) -> ValueConversions.ofRGB(b.getEffects().getFoliageColor().orElse(4764952))); // client Biome.getDefaultFoliageColor
put("sky_color", (w, b) -> ValueConversions.ofRGB(((BiomeEffectsInterface)b.getEffects()).getCMSkyColor())); put("sky_color", (w, b) -> ValueConversions.ofRGB(b.getEffects().getSkyColor()));
put("water_color", (w, b) -> ValueConversions.ofRGB(((BiomeEffectsInterface)b.getEffects()).getCMWaterColor())); put("water_color", (w, b) -> ValueConversions.ofRGB(b.getEffects().getWaterColor()));
put("water_fog_color", (w, b) -> ValueConversions.ofRGB(((BiomeEffectsInterface)b.getEffects()).getCMWaterFogColor())); put("water_fog_color", (w, b) -> ValueConversions.ofRGB(b.getEffects().getWaterFogColor()));
put("humidity", (w, b) -> NumericValue.of(b.getDownfall())); put("humidity", (w, b) -> NumericValue.of(b.getDownfall()));
put("precipitation", (w, b) -> StringValue.of(b.getPrecipitation().getName())); put("precipitation", (w, b) -> StringValue.of(b.getPrecipitation().getName()));
//put("depth", (w, b) -> NumericValue.of(b.getDepth())); //put("depth", (w, b) -> NumericValue.of(b.getDepth()));
@@ -5,6 +5,7 @@ import carpet.CarpetSettings;
import carpet.script.CarpetContext; import carpet.script.CarpetContext;
import carpet.script.CarpetScriptHost; import carpet.script.CarpetScriptHost;
import carpet.script.value.BooleanValue; import carpet.script.value.BooleanValue;
import carpet.script.value.EntityValue;
import carpet.script.value.ListValue; import carpet.script.value.ListValue;
import carpet.script.value.MapValue; import carpet.script.value.MapValue;
import carpet.script.value.NumericValue; 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.FabricLoader;
import net.fabricmc.loader.api.ModContainer; import net.fabricmc.loader.api.ModContainer;
import net.minecraft.SharedConstants; import net.minecraft.SharedConstants;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.WorldSavePath; 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.GameRules;
import net.minecraft.world.World;
import net.minecraft.world.WorldProperties; import net.minecraft.world.WorldProperties;
import net.minecraft.world.border.WorldBorder; import net.minecraft.world.border.WorldBorder;
@@ -74,7 +73,9 @@ public class SystemInfo {
return ListValue.fromTriple(worldBorder.getCenterX(), 0, worldBorder.getCenterZ()); 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())); put("world_time", c -> new NumericValue(c.s.getWorld().getTime()));
@@ -199,6 +200,15 @@ public class SystemInfo {
}); });
return MapValue.wrap(rules); 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)); put("scarpet_version", c -> StringValue.of(CarpetSettings.carpetVersion));
}}; }};
@@ -1,10 +1,8 @@
package carpet.script.value; package carpet.script.value;
import carpet.fakes.BrainInterface;
import carpet.fakes.EntityInterface; import carpet.fakes.EntityInterface;
import carpet.fakes.ItemEntityInterface; import carpet.fakes.ItemEntityInterface;
import carpet.fakes.LivingEntityInterface; import carpet.fakes.LivingEntityInterface;
import carpet.fakes.MemoryInterface;
import carpet.fakes.MobEntityInterface; import carpet.fakes.MobEntityInterface;
import carpet.fakes.ServerPlayerEntityInterface; import carpet.fakes.ServerPlayerEntityInterface;
import carpet.fakes.ServerPlayerInteractionManagerInterface; import carpet.fakes.ServerPlayerInteractionManagerInterface;
@@ -633,11 +631,11 @@ public class EntityValue extends Value
if (e instanceof LivingEntity livingEntity) if (e instanceof LivingEntity livingEntity)
{ {
Brain<?> brain = livingEntity.getBrain(); Brain<?> brain = livingEntity.getBrain();
Map<MemoryModuleType<?>, Optional<? extends Memory<?>>> memories = ((BrainInterface)brain).getMobMemories(); Map<MemoryModuleType<?>, Optional<? extends Memory<?>>> memories = brain.getMemories();
Optional<? extends Memory<?>> optmemory = memories.get(moduleType); Optional<? extends Memory<?>> optmemory = memories.get(moduleType);
if (optmemory==null || !optmemory.isPresent()) return Value.NULL; if (optmemory==null || !optmemory.isPresent()) return Value.NULL;
Memory<?> memory = optmemory.get(); Memory<?> memory = optmemory.get();
return ValueConversions.fromTimedMemory(e, ((MemoryInterface)memory).getScarpetExpiry(), memory.getValue()); return ValueConversions.fromTimedMemory(e, memory.getExpiry(), memory.getValue());
} }
return Value.NULL; return Value.NULL;
}); });
@@ -1584,7 +1582,7 @@ public class EntityValue extends Value
}); });
put("absorption", (e, v) -> { 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) -> { put("add_xp", (e, v) -> {
@@ -19,18 +19,29 @@ public class ThreadValue extends Value
private final long id; private final long id;
private static long sequence = 0L; private static long sequence = 0L;
public ThreadValue(CompletableFuture<Value> taskFuture)
{
this.taskFuture = taskFuture;
this.id = sequence++;
}
public ThreadValue(Value pool, FunctionValue function, Expression expr, Tokenizer.Token token, Context ctx, List<Value> args) public ThreadValue(Value pool, FunctionValue function, Expression expr, Tokenizer.Token token, Context ctx, List<Value> args)
{ {
id = sequence++; this(getCompletableFutureFromFunction(pool, function, expr, token, ctx, args));
Thread.yield();
}
public static CompletableFuture<Value> getCompletableFutureFromFunction(Value pool, FunctionValue function, Expression expr, Tokenizer.Token token, Context ctx, List<Value> args)
{
ExecutorService executor = ctx.host.getExecutor(pool); ExecutorService executor = ctx.host.getExecutor(pool);
if (executor == null) if (executor == null)
{ {
// app is shutting down - no more threads can be spawned. // app is shutting down - no more threads can be spawned.
taskFuture = CompletableFuture.completedFuture(Value.NULL); return CompletableFuture.completedFuture(Value.NULL);
} }
else else
{ {
taskFuture = CompletableFuture.supplyAsync( return CompletableFuture.supplyAsync(
() -> () ->
{ {
try try
@@ -52,7 +63,6 @@ public class ThreadValue extends Value
ctx.host.getExecutor(pool) ctx.host.getExecutor(pool)
); );
} }
Thread.yield();
} }
@Override @Override
+37 -57
View File
@@ -103,23 +103,18 @@ public class Messenger
} }
public static String creatureTypeColor(SpawnGroup type) public static String creatureTypeColor(SpawnGroup type)
{ {
switch (type) return switch (type)
{ {
case MONSTER: case MONSTER -> "n";
return "n"; case CREATURE -> "e";
case CREATURE: case AMBIENT -> "f";
return "e"; case WATER_CREATURE -> "v";
case AMBIENT: case WATER_AMBIENT -> "q";
return "f"; default -> "w"; // missing MISC and UNDERGROUND_WATER_CREATURE
case WATER_CREATURE: };
return "v";
case WATER_AMBIENT:
return "q";
}
return "w";
} }
private static BaseText _getChatComponentFromDesc(String message, BaseText previous_message) private static BaseText getChatComponentFromDesc(String message, BaseText previousMessage)
{ {
if (message.equalsIgnoreCase("")) if (message.equalsIgnoreCase(""))
{ {
@@ -127,7 +122,7 @@ public class Messenger
} }
if (Character.isWhitespace(message.charAt(0))) if (Character.isWhitespace(message.charAt(0)))
{ {
message = "w"+message; message = "w" + message;
} }
int limit = message.indexOf(' '); int limit = message.indexOf(' ');
String desc = message; String desc = message;
@@ -137,52 +132,37 @@ public class Messenger
desc = message.substring(0, limit); desc = message.substring(0, limit);
str = message.substring(limit+1); str = message.substring(limit+1);
} }
if (desc.charAt(0) == '/') // deprecated if (previousMessage == null) {
{ BaseText text = new LiteralText(str);
if (previous_message != null) text.setStyle(parseStyle(desc));
previous_message.setStyle( return text;
previous_message.getStyle().withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, message))
);
return previous_message;
} }
if (desc.charAt(0) == '?') Style previousStyle = previousMessage.getStyle();
{ BaseText ret = previousMessage;
if (previous_message != null) previousMessage.setStyle(switch (desc.charAt(0)) {
previous_message.setStyle( case '?' -> previousStyle.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, message.substring(1)));
previous_message.getStyle().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))));
return previous_message; 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)));
if (desc.charAt(0) == '!') default -> { // Create a new component
{ ret = new LiteralText(str);
if (previous_message != null) ret.setStyle(parseStyle(desc));
previous_message.setStyle( yield previousStyle; // no op for the previous style
previous_message.getStyle().withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, message.substring(1))) }
); });
return previous_message; return ret;
}
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;
} }
public static BaseText tp(String desc, Vec3d pos) { return tp(desc, pos.x, pos.y, pos.z); } 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, 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, 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) 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) 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 /// to be continued
@@ -232,7 +212,7 @@ public class Messenger
return c(components.toArray(new Object[0])); 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 text;
String command; String command;
@@ -266,19 +246,19 @@ public class Messenger
public static BaseText c(Object ... fields) public static BaseText c(Object ... fields)
{ {
BaseText message = new LiteralText(""); BaseText message = new LiteralText("");
BaseText previous_component = null; BaseText previousComponent = null;
for (Object o: fields) for (Object o: fields)
{ {
if (o instanceof BaseText) if (o instanceof BaseText)
{ {
message.append((BaseText)o); message.append((BaseText)o);
previous_component = (BaseText)o; previousComponent = (BaseText)o;
continue; continue;
} }
String txt = o.toString(); String txt = o.toString();
BaseText comp = _getChatComponentFromDesc(txt,previous_component); BaseText comp = getChatComponentFromDesc(txt, previousComponent);
if (comp != previous_component) message.append(comp); if (comp != previousComponent) message.append(comp);
previous_component = comp; previousComponent = comp;
} }
return message; return message;
} }
-3
View File
@@ -67,8 +67,6 @@
"EntityTrackerEntry_leashFixMixin", "EntityTrackerEntry_leashFixMixin",
"VillagerEntity_aiMixin", "VillagerEntity_aiMixin",
"Brain_Mixin",
"Memory_scarpetMixin",
"PlayerEntity_fakePlayersMixin", "PlayerEntity_fakePlayersMixin",
"ThrownEnderpearlEntity_fakePlayersMixin", "ThrownEnderpearlEntity_fakePlayersMixin",
@@ -190,7 +188,6 @@
"Team_scarpetMixin", "Team_scarpetMixin",
"TradeOutputSlot_scarpetEventMixin", "TradeOutputSlot_scarpetEventMixin",
"BiomeEffects_scarpetMixin",
"ChunkTicketManager_scarpetMixin", "ChunkTicketManager_scarpetMixin",
"PointOfInterest_scarpetMixin", "PointOfInterest_scarpetMixin",
"ServerWorld_scarpetMixin", "ServerWorld_scarpetMixin",
+1 -1
View File
@@ -33,7 +33,7 @@
"depends": { "depends": {
"minecraft": "1.18.x", "minecraft": "1.18.x",
"fabricloader": ">=0.11.6", "fabricloader": ">=0.12.8",
"java": ">=17" "java": ">=17"
} }
} }