Merge branch 'master' into 1.15
# Conflicts: # src/main/java/carpet/mixins/ServerPlayNetworkHandler_scarpetEventsMixin.java # src/main/java/carpet/script/CarpetExpression.java # src/main/resources/carpet.mixins.json
This commit is contained in:
commit
e9e36f64a3
14 files changed
+321
-16
No files matched your search
@@ -296,6 +296,43 @@ public class CarpetEventServer
|
||||
}, player::getCommandSource);
|
||||
}
|
||||
},
|
||||
PLAYER_INTERACTS_WITH_BLOCK("player_interacts_with_block", new CallbackList(5))
|
||||
{
|
||||
@Override
|
||||
public void onBlockHit(ServerPlayerEntity player, Hand enumhand, BlockHitResult hitRes)
|
||||
{
|
||||
handler.call( () ->
|
||||
{
|
||||
BlockPos blockpos = hitRes.getBlockPos();
|
||||
Direction enumfacing = hitRes.getSide();
|
||||
Vec3d vec3d = hitRes.getPos().subtract(blockpos.getX(), blockpos.getY(), blockpos.getZ());
|
||||
return Arrays.asList(
|
||||
((c, t) -> new EntityValue(player)),
|
||||
((c, t) -> new StringValue(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand")),
|
||||
((c, t) -> new BlockValue(null, player.getServerWorld(), blockpos)),
|
||||
((c, t) -> new StringValue(enumfacing.getName())),
|
||||
((c, t) -> ListValue.of(
|
||||
new NumericValue(vec3d.x),
|
||||
new NumericValue(vec3d.y),
|
||||
new NumericValue(vec3d.z)
|
||||
))
|
||||
);
|
||||
}, player::getCommandSource);
|
||||
}
|
||||
},
|
||||
PLAYER_PLACES_BLOCK("player_places_block", new CallbackList(4))
|
||||
{
|
||||
@Override
|
||||
public void onBlockPlaced(ServerPlayerEntity player, BlockPos pos, Hand enumhand, ItemStack itemstack)
|
||||
{
|
||||
handler.call( () -> Arrays.asList(
|
||||
((c, t) -> new EntityValue(player)),
|
||||
((c, t) -> ListValue.fromItemStack(itemstack)),
|
||||
((c, t) -> new StringValue(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand")),
|
||||
((c, t) -> new BlockValue(null, player.getServerWorld(), pos))
|
||||
), player::getCommandSource);
|
||||
}
|
||||
},
|
||||
PLAYER_BREAK_BLOCK("player_breaks_block",new CallbackList(2))
|
||||
{
|
||||
@Override
|
||||
@@ -307,7 +344,7 @@ public class CarpetEventServer
|
||||
), player::getCommandSource);
|
||||
}
|
||||
},
|
||||
PLAYER_INERACTSW_WITH_ENTITY("player_interacts_with_entity",new CallbackList(3))
|
||||
PLAYER_INTERACTS_WITH_ENTITY("player_interacts_with_entity",new CallbackList(3))
|
||||
{
|
||||
@Override
|
||||
public void onEntityAction(ServerPlayerEntity player, Entity entity, Hand enumhand)
|
||||
@@ -465,6 +502,7 @@ public class CarpetEventServer
|
||||
public void onBlockAction(ServerPlayerEntity player, BlockPos blockpos, Direction facing) { }
|
||||
public void onBlockHit(ServerPlayerEntity player, Hand enumhand, BlockHitResult hitRes) { }
|
||||
public void onBlockBroken(ServerPlayerEntity player, BlockPos pos, BlockState previousBS) { }
|
||||
public void onBlockPlaced(ServerPlayerEntity player, BlockPos pos, Hand enumhand, ItemStack itemstack) { }
|
||||
public void onEntityAction(ServerPlayerEntity player, Entity entity, Hand enumhand) { }
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package carpet.script;
|
||||
import carpet.CarpetServer;
|
||||
import carpet.fakes.MinecraftServerInterface;
|
||||
import carpet.fakes.BiomeArrayInterface;
|
||||
import carpet.fakes.StatTypeInterface;
|
||||
import carpet.helpers.FeatureGenerator;
|
||||
import carpet.mixins.ChunkTicketManager_scarpetMixin;
|
||||
import carpet.mixins.ServerChunkManager_scarpetMixin;
|
||||
@@ -68,11 +69,14 @@ import net.minecraft.server.world.ChunkTicket;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.sound.BlockSoundGroup;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.stat.Stat;
|
||||
import net.minecraft.stat.StatType;
|
||||
import net.minecraft.state.StateManager;
|
||||
import net.minecraft.state.property.Property;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.util.Clearable;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.InvalidIdentifierException;
|
||||
import net.minecraft.util.SortedArraySet;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Box;
|
||||
@@ -1743,6 +1747,9 @@ public class CarpetExpression
|
||||
* <p>String with gamemode, or <code>null</code> if not a player.</p>
|
||||
* <h3><code>query(e,'gamemode_id')</code></h3>
|
||||
* <p>Good'ol gamemode id, or null if not a player.</p>
|
||||
* <h3><code>query(e,'permission_level')</code></h3>
|
||||
* <p>Player's permission level, or <code>null</code> if not applicable for this entity.</p>
|
||||
*
|
||||
* <h3><code>query(e,'effect',name?)</code></h3>
|
||||
* <p>Without extra arguments, it returns list of effect active on a living entity.
|
||||
* Each entry is a triple of short effect name, amplifier, and remaining duration.
|
||||
@@ -1834,6 +1841,12 @@ public class CarpetExpression
|
||||
* <p>Make noises.</p>
|
||||
* <h3><code>modify(e, 'ai', boolean)</code></h3>
|
||||
* <p>If called with <code>false</code> value, it will disable AI in the mob. <code>true</code> will enable it again.</p>
|
||||
* <h3><code>modify(e, 'no_clip', boolean)</code></h3>
|
||||
* <p>Sets if the entity obeys any collisions, including collisions with the terrain and basic physics.
|
||||
* Not affecting players, since they are controlled client side</p>
|
||||
* <h3><code>modify(e, 'effect', name, duration, amplifier?, show_particles?, show_icon?)</code></h3>
|
||||
* <p>Applies status effect to the living entity. Takes several optional parameters, which default to <code>0</code>,
|
||||
* <code>true</code> and <code>true</code>.</p>
|
||||
* <h3><code>modify(e, 'home', null), modify(e, 'home', block, distance?), modify(e, 'home', x, y, z, distance?)</code></h3>
|
||||
* <p>Sets AI to stay around the home position, within <code>distance</code> blocks from it. <code>distance</code>
|
||||
* defaults to 16 blocks. <code>null</code> removes it. <i>May</i> not work fully with mobs that have this AI built in, like
|
||||
@@ -2638,7 +2651,7 @@ public class CarpetExpression
|
||||
* <h3><code>load_app_data(), load_app_data(file)</code></h3>
|
||||
* <p>Loads the app data associated with the app from the world /scripts folder. Without argument returns the memory
|
||||
* managed and buffered / throttled NBT tag. With a file name - reads explicitly a file with that name from the scripts
|
||||
* floder.</p>
|
||||
* folder.</p>
|
||||
* <p> You can use app data to save non-vanilla information separately from the world and other scripts.</p>
|
||||
* <h3><code>store_app_data(tag), store_app_data(tag, file)</code></h3>
|
||||
* <p>Stores the app data associated with the app from the world /scripts folder. With the <code>file</code> parameter
|
||||
@@ -2663,6 +2676,25 @@ public class CarpetExpression
|
||||
* <h3><code>schedule(delay, function, args...)</code></h3>
|
||||
* <p>Schedules a user defined function to run with a specified <code>delay</code> ticks of delay.
|
||||
* Scheduled functions run at the end of the tick, and they will run in order they were scheduled.</p>
|
||||
* <h3><code>statistic(player, category, entry)</code></h3>
|
||||
* <p>Queries in-game statistics for certain values. Categories include:</p>
|
||||
* <ul>
|
||||
* <li><code>mined</code>: blocks mined</li>
|
||||
* <li><code>crafted</code>: items crafted</li>
|
||||
* <li><code>used</code>: items used</li>
|
||||
* <li><code>broken</code>: items broken</li>
|
||||
* <li><code>picked_up</code>: items picked up</li>
|
||||
* <li><code>dropped</code>: items dropped</li>
|
||||
* <li><code>killed</code>: mobs killed</li>
|
||||
* <li><code>killed_by</code>: blocks mined</li>
|
||||
* <li><code>custom</code>: various random stats</li>
|
||||
* </ul>
|
||||
* <p>For the options of <code>entry</code>, consult your statistics page, or give it a guess.</p>
|
||||
* <p>The call will return <code>null</code> if the statistics options are incorrect, or player didn't get these
|
||||
* in their history. If the player encountered the statisitic, or game created for him empty one, it will
|
||||
* return a number. Scarpet will not affect the entries of the statistics, even if it is just creating empty ones.
|
||||
* With <code>null</code> response it could either mean your input is wrone, or statistic has effectively
|
||||
* a value of <code>0</code>.</p>
|
||||
* <h3><code>plop(pos, what)</code></h3>
|
||||
* <p>Plops a structure or a feature at a given <code>pos</code>, so block, triple position coordinates
|
||||
* or a list of coordinates. To <code>what</code> gets plopped and exactly where it often depends on the
|
||||
@@ -3008,12 +3040,12 @@ public class CarpetExpression
|
||||
});
|
||||
|
||||
//"overidden" native call to cancel if on main thread
|
||||
this.expr.addLazyFunction("join_task", 1, (c, t, lv) -> {
|
||||
this.expr.addLazyFunction("task_join", 1, (c, t, lv) -> {
|
||||
if (((CarpetContext)c).s.getMinecraftServer().isOnThread())
|
||||
throw new InternalExpressionException("'join_task' cannot be called from main thread to avoid deadlocks");
|
||||
throw new InternalExpressionException("'task_join' cannot be called from main thread to avoid deadlocks");
|
||||
Value v = lv.get(0).evalValue(c);
|
||||
if (!(v instanceof ThreadValue))
|
||||
throw new InternalExpressionException("'join_task' could only be used with a task value");
|
||||
throw new InternalExpressionException("'task_join' could only be used with a task value");
|
||||
Value ret = ((ThreadValue) v).join();
|
||||
return (_c, _t) -> ret;
|
||||
});
|
||||
@@ -3219,8 +3251,43 @@ public class CarpetExpression
|
||||
((CarpetScriptHost)((CarpetContext)c).host).setGlobalState(tag, file);
|
||||
return (cc, tt) -> Value.NULL;
|
||||
});
|
||||
|
||||
this.expr.addLazyFunction("statistic", 3, (c, t, lv) ->
|
||||
{
|
||||
Value playerValue = lv.get(0).evalValue(c);
|
||||
CarpetContext cc = (CarpetContext)c;
|
||||
ServerPlayerEntity player = EntityValue.getPlayerByValue(cc.s.getMinecraftServer(), playerValue);
|
||||
if (player == null) return LazyValue.NULL;
|
||||
Identifier category;
|
||||
Identifier statName;
|
||||
try
|
||||
{
|
||||
category = new Identifier(lv.get(1).evalValue(c).getString());
|
||||
statName = new Identifier(lv.get(2).evalValue(c).getString());
|
||||
}
|
||||
catch (InvalidIdentifierException e)
|
||||
{
|
||||
return LazyValue.NULL;
|
||||
}
|
||||
StatType<?> type = Registry.STAT_TYPE.get(category);
|
||||
if (type == null)
|
||||
return LazyValue.NULL;
|
||||
Stat<?> stat = getStat(type, statName);
|
||||
if (stat == null)
|
||||
return LazyValue.NULL;
|
||||
return (_c, _t) -> new NumericValue(player.getStatHandler().getStat(stat));
|
||||
});
|
||||
}
|
||||
|
||||
private <T> Stat<T> getStat(StatType<T> type, Identifier id)
|
||||
{
|
||||
T key = type.getRegistry().get(id);
|
||||
if (key == null || !((StatTypeInterface)type).hasStatCreated(key))
|
||||
return null;
|
||||
return type.getOrCreateStat(key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <h1>.</h1>
|
||||
* @param expression expression
|
||||
@@ -3446,7 +3513,11 @@ public class CarpetExpression
|
||||
* should be running at startup. WARNING: all apps will run once at startup anyways, so be aware that their actions
|
||||
* that are called statically, will be performed once anyways.</li>
|
||||
* </ul>
|
||||
* <p>Unloading an app removes all of its state from the game, disables commands, and removes bounded events</p>
|
||||
* <p>Unloading an app removes all of its state from the game, disables commands, and removes bounded events,
|
||||
* and saves its global state. If more
|
||||
* cleanup is needed, one can define an <code>__on_close()</code> function which will be executed when the module is unloaded,
|
||||
* or server is closing, or crashing. However, there is no need to do that explicitly for the things mentioned
|
||||
* in the previous statement.</p>
|
||||
* <p>Scripts can be loaded in shared(global) and player mode. Default is player, so all globals and stored functions are
|
||||
* individual for each player, meaning scripts don't need to worry about making sure they store some intermittent data
|
||||
* for each player independently. In global mode - all global values and stored functions are shared among all players.
|
||||
@@ -3486,8 +3557,10 @@ public class CarpetExpression
|
||||
* __on_player_releases_item(player, item_tuple, hand) // client action (e.g. bow)
|
||||
* __on_player_finishes_using_item(player, item_tuple, hand)) // server action (e.g. food), called item is from before it is used.
|
||||
* __on_player_clicks_block(player, block, face) // left click attack on a block
|
||||
* __on_player_right_clicks_block(player, item_tuple, hand, block, face, hitvec)
|
||||
* __on_player_breaks_block(player, block) // called after block is broken (the caller receives previous blockstate)
|
||||
* __on_player_right_clicks_block(player, item_tuple, hand, block, face, hitvec) // player right clicks block with anything
|
||||
* __on_player_interacts_with_block(player, hand, block, face, hitvec) //right click on a block resulted in activation of said block
|
||||
* __on_player_places_block(player, item_tuple, hand, block) // player have just placed the block.
|
||||
* __on_player_interacts_with_entity(player, entity, hand)
|
||||
* __on_player_attacks_entity(player, entity)
|
||||
* __on_player_rides(player, forward, strafe, jumping, sneaking)
|
||||
@@ -3500,6 +3573,8 @@ public class CarpetExpression
|
||||
* __on_player_stops_sprinting(player)
|
||||
* __on_player_drops_item(player)
|
||||
* __on_player_drops_stack(player)
|
||||
*
|
||||
* __on_statistic(player, category, event, value) // player statistic changes
|
||||
* </pre>
|
||||
* <h3><code>/script event</code> command</h3>
|
||||
* <p>used to display current events and bounded functions. use <code>add_to</code> ro register new event, or <code>remove_from</code>
|
||||
|
||||
@@ -46,6 +46,7 @@ public class CarpetScriptServer
|
||||
private static List<ModuleInterface> bundledModuleData = new ArrayList<ModuleInterface>(){{
|
||||
add(new BundledModule("camera"));
|
||||
add(new BundledModule("event_test"));
|
||||
add(new BundledModule("stats_test"));
|
||||
}};
|
||||
|
||||
public CarpetScriptServer()
|
||||
@@ -166,6 +167,11 @@ public class CarpetScriptServer
|
||||
//TODO add per player modules to support player actions better on a server
|
||||
name = name.toLowerCase(Locale.ROOT);
|
||||
ModuleInterface module = getModule(name);
|
||||
if (module == null)
|
||||
{
|
||||
Messenger.m(source, "r Failed to add "+name+" app");
|
||||
return false;
|
||||
}
|
||||
CarpetScriptHost newHost = createMinecraftScriptHost(name, module, perPlayer, source);
|
||||
if (newHost == null)
|
||||
{
|
||||
|
||||
@@ -60,7 +60,7 @@ import static java.lang.Math.min;
|
||||
|
||||
|
||||
/**
|
||||
* <h1>Fundamental components of <code>scarpet</code> programming language (version 1.6).</h1>
|
||||
* <h1>Fundamental components of <code>scarpet</code> programming language (towards version 1.7).</h1>
|
||||
*
|
||||
* <p>Scarpet (a.k.a. Carpet Script, or Script for Carpet) is a programming language designed to provide
|
||||
* the ability to write custom programs to run within Minecraft and
|
||||
@@ -2613,6 +2613,59 @@ public class Expression implements Cloneable
|
||||
* </pre>
|
||||
*
|
||||
* <hr>
|
||||
* <h2>Threading and Parallel Execution</h2>
|
||||
* <p>Scarpet allows to run threads of execution in parallel to the main script execution thread. In Minecraft, the main
|
||||
* thread scripts are executed on the main server thread. Since Minecraft is inherently NOT thread safe, it is not that
|
||||
* beneficial to parallel execution in order to access world resources faster. Both
|
||||
* <code>GetBlockState</code> and <code>setBlockState</code> are not thread safe and require the execution to park on the server thread,
|
||||
* where these requests can be executed in the off-tick time in between ticks that didn't take 50ms. There are however
|
||||
* benefits of running things in parallel, like fine time control not relying on the tick clock, or running things independent
|
||||
* on each other. You can still run your actions on tick-by-tick basis, either taking control of the execution using
|
||||
* <code>game_tick()</code> API function (nasty solution), or scheduling tick using <code>schedule()</code> function (much nicer solution),
|
||||
* but threading often gives the neatest solution to solve problems in parallel (see scarpet camera).
|
||||
* </p>
|
||||
* <p>Due to limitations with the game, there are some limits to the threading as well. You cannot for instance <code>join_task()</code> at all
|
||||
* from the main script and server thread, because any use of Minecraft specific function that require any world access, will
|
||||
* require to park and join on the main thread to get world access, meaning that calling join on that task would inevitably lead to a
|
||||
* typical deadlock. You can still join tasks from other threads, just because the only possibility of a deadlock in this case would
|
||||
* come explicitly from your bad code, not the internal world access behaviour. Some things tough like player or entity manipulation,
|
||||
* can be effectively parallelized.</p>
|
||||
* <h3><code>task(function, ?args...., ?executor)</code></h3>
|
||||
* <p>Creates and runs a parallel task, returning the handle to the task object. Task will return the return value of the function
|
||||
* when its completed, or will return <code>null</code> immediately if task is still in progress, so grabbing a value of
|
||||
* a task object is non-blocking. Function can be either function value, or function lambda, or a name of an existing defined function.
|
||||
* In case function needs arguments to be called with, they should be supplied after the function name, or value.
|
||||
* Optional <code>executor</code> identifier is to place the task in a specific queue identified by this value. The default
|
||||
* thread value is the <code>null</code> thread. There is no limits on number of parallel tasks for any executor, so using different queues is solely
|
||||
* for synchronization purposes. Also, since <code>task</code> function knows how many extra arguments it requires, the use of
|
||||
* tailing optional parameter for the custom executor thread pool is not ambiguous.
|
||||
* </p>
|
||||
* <pre>
|
||||
* task( _() -> print('Hello Other World') ) => Runs print command on a separate thread
|
||||
* foo(a, b) -> print(a+b); task('foo',2,2) => Uses existing function definition to start a task
|
||||
* task('foo',3,5,'temp'); => runs function foo with a different thread executor, identified as 'temp'
|
||||
* a = 3; task( _(outer(a), b) -> foo(a,b), 5, 'temp') => Another example of running the same thing passing arguments using closure over anonymous function as well as passing a parameter.
|
||||
* </pre>
|
||||
* <h3><code>task_count(executor?)</code></h3>
|
||||
* <p>If no argument provided, returns total number of tasks being executed in parallel at this moment using scarpet threading system.
|
||||
* If the executor is provided, returns number of active tasks for that provider. Use <code>task_count(null)</code> to
|
||||
* get the task count of the default executor only.</p>
|
||||
*
|
||||
* <h3><code>task_value(task)</code></h3>
|
||||
* <p>Returns the task return value, or <code>null</code> if task hasn't finished yet. Its a non-blocking operation.
|
||||
* Unlike <code>join_task</code>, can be called on any task at any point</p>
|
||||
*
|
||||
* <h3><code>task_join(task)</code></h3>
|
||||
* <p>Waits for the task completion and returns its computed value. If the task has already finished returns it immediately.
|
||||
* Unless taking the task value directly, i.e. via <code>task_value</code>, this operation is blocking. Since Minecraft has
|
||||
* a limitation that all world access operations have to be performed on the main game thread in the off-tick time, joining any tasks that use
|
||||
* Minecraft API from the main thread would mean automatic lock, so joining from the main thread is not allowed.
|
||||
* Join tasks from other threads, if you really need to, or communicate asynchronously with the task via globals or
|
||||
* function data / arguments to monitor its progress, communicate, get partial results, or signal termination. </p>
|
||||
*
|
||||
* <h3><code>task_completed(task)</code></h3>
|
||||
* <p>Returns true if task has completed, or false otherwise.</p>
|
||||
*
|
||||
* <h2>Auxiliary functions</h2>
|
||||
*
|
||||
* <h3><code>lower(expr), upper(expr), title(expr)</code></h3>
|
||||
@@ -3039,9 +3092,15 @@ public class Expression implements Cloneable
|
||||
return new NumericValue(ThreadValue.taskCount());
|
||||
});
|
||||
|
||||
addUnaryFunction("join_task", (v) -> {
|
||||
addUnaryFunction("task_value", (v) -> {
|
||||
if (!(v instanceof ThreadValue))
|
||||
throw new InternalExpressionException("'join_task' could only be used with a task value");
|
||||
throw new InternalExpressionException("'task_value' could only be used with a task value");
|
||||
return ((ThreadValue) v).getValue();
|
||||
});
|
||||
|
||||
addUnaryFunction("task_join", (v) -> {
|
||||
if (!(v instanceof ThreadValue))
|
||||
throw new InternalExpressionException("'task_join' could only be used with a task value");
|
||||
return ((ThreadValue) v).join();
|
||||
});
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import net.minecraft.entity.mob.MobEntityWithAi;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.predicate.entity.EntityPredicates;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
@@ -93,6 +94,25 @@ public class EntityValue extends Value
|
||||
return entity;
|
||||
}
|
||||
|
||||
public static ServerPlayerEntity getPlayerByValue(MinecraftServer server, Value value)
|
||||
{
|
||||
ServerPlayerEntity player = null;
|
||||
if (value instanceof EntityValue)
|
||||
{
|
||||
Entity e = ((EntityValue) value).getEntity();
|
||||
if (e instanceof ServerPlayerEntity)
|
||||
{
|
||||
player = (ServerPlayerEntity) e;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
String playerName = value.getString();
|
||||
player = server.getPlayerManager().getPlayer(playerName);
|
||||
}
|
||||
return player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString()
|
||||
{
|
||||
|
||||
@@ -37,6 +37,11 @@ public class ThreadValue extends Value
|
||||
return taskFuture.getNow(Value.NULL).getString();
|
||||
}
|
||||
|
||||
public Value getValue()
|
||||
{
|
||||
return taskFuture.getNow(Value.NULL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean()
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user