diff --git a/src/main/java/carpet/mixins/ServerPlayNetworkHandler_scarpetEventsMixin.java b/src/main/java/carpet/mixins/ServerPlayNetworkHandler_scarpetEventsMixin.java
index 82420afe..6e560e89 100644
--- a/src/main/java/carpet/mixins/ServerPlayNetworkHandler_scarpetEventsMixin.java
+++ b/src/main/java/carpet/mixins/ServerPlayNetworkHandler_scarpetEventsMixin.java
@@ -22,6 +22,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import static carpet.script.CarpetEventServer.Event.PLAYER_ATTACKS_ENTITY;
import static carpet.script.CarpetEventServer.Event.PLAYER_CLICKS_BLOCK;
import static carpet.script.CarpetEventServer.Event.PLAYER_DEPLOYS_ELYTRA;
+import static carpet.script.CarpetEventServer.Event.PLAYER_DROPS_ITEM;
+import static carpet.script.CarpetEventServer.Event.PLAYER_DROPS_STACK;
import static carpet.script.CarpetEventServer.Event.PLAYER_INERACTSW_WITH_ENTITY;
import static carpet.script.CarpetEventServer.Event.PLAYER_RELEASED_ITEM;
import static carpet.script.CarpetEventServer.Event.PLAYER_RIDES;
@@ -49,6 +51,30 @@ public class ServerPlayNetworkHandler_scarpetEventsMixin
}
}
+ @Inject(method = "onPlayerAction", at = @At(
+ value = "INVOKE",
+ target = "Lnet/minecraft/server/network/ServerPlayerEntity;dropSelectedItem(Z)Lnet/minecraft/entity/ItemEntity;",
+ ordinal = 0,
+ shift = At.Shift.BEFORE
+ ))
+ private void onQItem(PlayerActionC2SPacket playerActionC2SPacket_1, CallbackInfo ci)
+ {
+ PLAYER_DROPS_ITEM.onPlayerEvent(player);
+ }
+
+ @Inject(method = "onPlayerAction", at = @At(
+ value = "INVOKE",
+ target = "Lnet/minecraft/server/network/ServerPlayerEntity;dropSelectedItem(Z)Lnet/minecraft/entity/ItemEntity;",
+ ordinal = 1,
+ shift = At.Shift.BEFORE
+ ))
+ private void onCtrlQItem(PlayerActionC2SPacket playerActionC2SPacket_1, CallbackInfo ci)
+ {
+ PLAYER_DROPS_STACK.onPlayerEvent(player);
+ }
+
+
+
@Inject(method = "onPlayerMove", at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/network/ServerPlayerEntity;jump()V"
diff --git a/src/main/java/carpet/script/CarpetEventServer.java b/src/main/java/carpet/script/CarpetEventServer.java
index 754216f7..54ab74f1 100644
--- a/src/main/java/carpet/script/CarpetEventServer.java
+++ b/src/main/java/carpet/script/CarpetEventServer.java
@@ -301,7 +301,7 @@ public class CarpetEventServer
@Override
public void onPlayerEvent(ServerPlayerEntity player)
{
- handler.call( () -> Arrays.asList(((c, t) -> new EntityValue(player))), player::getCommandSource);
+ handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
}
},
PLAYER_STOPS_SNEAKING("player_stops_sneaking",new CallbackList(1))
@@ -309,7 +309,7 @@ public class CarpetEventServer
@Override
public void onPlayerEvent(ServerPlayerEntity player)
{
- handler.call( () -> Arrays.asList(((c, t) -> new EntityValue(player))), player::getCommandSource);
+ handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
}
},
PLAYER_STARTS_SPRINTING("player_starts_sprinting",new CallbackList(1))
@@ -317,7 +317,7 @@ public class CarpetEventServer
@Override
public void onPlayerEvent(ServerPlayerEntity player)
{
- handler.call( () -> Arrays.asList(((c, t) -> new EntityValue(player))), player::getCommandSource);
+ handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
}
},
PLAYER_STOPS_SPRINTING("player_stops_sprinting",new CallbackList(1))
@@ -325,7 +325,7 @@ public class CarpetEventServer
@Override
public void onPlayerEvent(ServerPlayerEntity player)
{
- handler.call( () -> Arrays.asList(((c, t) -> new EntityValue(player))), player::getCommandSource);
+ handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
}
},
@@ -360,7 +360,24 @@ public class CarpetEventServer
);
}, player::getCommandSource);
}
+ },
+ PLAYER_DROPS_ITEM("player_drops_item", new CallbackList(1))
+ {
+ @Override
+ public void onPlayerEvent(ServerPlayerEntity player)
+ {
+ handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
+ }
+ },
+ PLAYER_DROPS_STACK("player_drops_stack", new CallbackList(1))
+ {
+ @Override
+ public void onPlayerEvent(ServerPlayerEntity player)
+ {
+ handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
+ }
};
+
// on projectile thrown (arrow from bows, crossbows, tridents, snoballs, e-pearls
public String name;
diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java
index 84e27f33..cd1fc8a4 100644
--- a/src/main/java/carpet/script/CarpetExpression.java
+++ b/src/main/java/carpet/script/CarpetExpression.java
@@ -31,6 +31,7 @@ import net.minecraft.block.CommandBlock;
import net.minecraft.block.JigsawBlock;
import net.minecraft.block.StructureBlock;
import net.minecraft.block.entity.BlockEntity;
+import net.minecraft.client.network.packet.GuiSlotUpdateS2CPacket;
import net.minecraft.client.network.packet.PlaySoundIdS2CPacket;
import net.minecraft.command.arguments.ItemStackArgument;
import net.minecraft.command.arguments.ParticleArgumentType;
@@ -1051,6 +1052,13 @@ public class CarpetExpression
* stack_limit('ender_pearl') => 16
* stack_limit('stone') => 64
*
+ *
item_category(item)
+ * Returns the string representing the category of a given item, like `building_blocks`, `combat`, or `tools`.
+ *
+ * item_category('wooden_axe') => tools
+ * item_category('ender_pearl') => misc
+ * item_category('stone') => building_blocks
+ *
* inventory_size(inventory)
* Returns the size of the inventory for the entity or block in question. Returns null if the block or entity
* don't have an inventory
@@ -1120,6 +1128,13 @@ public class CarpetExpression
return (_c, _t) -> res;
});
+ this.expr.addLazyFunction("item_category", 1, (c, t, lv) ->
+ {
+ ItemStackArgument item = NBTSerializableValue.parseItem(lv.get(0).evalValue(c).getString());
+ Value res = new StringValue(item.getItem().getGroup().getName());
+ return (_c, _t) -> res;
+ });
+
this.expr.addLazyFunction("inventory_size", -1, (c, t, lv) ->
{
CarpetContext cc = (CarpetContext) c;
@@ -1173,6 +1188,7 @@ public class CarpetExpression
{
// clear slot
ItemStack removedStack = inventoryLocator.inventory.removeInvStack(slot);
+ syncPlayerInventory(inventoryLocator, slot);
//Value res = ListValue.fromItemStack(removedStack); // that tuple will be read only but cheaper if noone cares
return (_c, _t) -> ListValue.fromItemStack(removedStack);
}
@@ -1182,6 +1198,7 @@ public class CarpetExpression
ItemStack newStack = previousStack.copy();
newStack.setCount(count);
inventoryLocator.inventory.setInvStack(slot, newStack);
+ syncPlayerInventory(inventoryLocator, slot);
return (_c, _t) -> ListValue.fromItemStack(previousStack);
}
CompoundTag nbt = null; // skipping one argument
@@ -1204,6 +1221,7 @@ public class CarpetExpression
try
{
inventoryLocator.inventory.setInvStack(slot, newitem.createStack(count, false));
+ syncPlayerInventory(inventoryLocator, slot);
}
catch (CommandSyntaxException e)
{
@@ -1279,11 +1297,13 @@ public class CarpetExpression
{
stack.setCount(left);
inventoryLocator.inventory.setInvStack(i, stack);
+ syncPlayerInventory(inventoryLocator, i);
return (_c, _t) -> Value.TRUE;
}
else
{
inventoryLocator.inventory.removeInvStack(i);
+ syncPlayerInventory(inventoryLocator, i);
amount -= stack.getCount();
}
}
@@ -1344,11 +1364,22 @@ public class CarpetExpression
item.setToDefaultPickupDelay();
cc.s.getWorld().spawnEntity(item);
}
- inventoryLocator.inventory.markDirty();
Value res = new NumericValue(item.getStack().getCount());
return (_c, _t) -> res;
});
}
+ private void syncPlayerInventory(NBTSerializableValue.InventoryLocator inventory, int int_1)
+ {
+ if (inventory.owner instanceof ServerPlayerEntity)
+ {
+ ServerPlayerEntity player = (ServerPlayerEntity) inventory.owner;
+ player.networkHandler.sendPacket(new GuiSlotUpdateS2CPacket(
+ -2,
+ int_1,
+ inventory.inventory.getInvStack(int_1)
+ ));
+ }
+ }
/**
@@ -3105,6 +3136,8 @@ public class CarpetExpression
* __on_player_stops_sneaking(player)
* __on_player_starts_sprinting(player)
* __on_player_stops_sprinting(player)
+ * __on_player_drops_item(player)
+ * __on_player_drops_stack(player)
*
* /script event command
* used to display current events and bounded functions. use add_to ro register new event, or remove_from
diff --git a/src/main/java/carpet/script/CarpetScriptServer.java b/src/main/java/carpet/script/CarpetScriptServer.java
index d4a29872..c03d67bb 100644
--- a/src/main/java/carpet/script/CarpetScriptServer.java
+++ b/src/main/java/carpet/script/CarpetScriptServer.java
@@ -1,8 +1,8 @@
package carpet.script;
+import carpet.script.bundled.BundledModule;
import carpet.settings.CarpetSettings;
import carpet.CarpetServer;
-import carpet.script.bundled.CameraPathModule;
import carpet.script.bundled.FileModule;
import carpet.script.bundled.ModuleInterface;
import carpet.script.exception.CarpetExpressionException;
@@ -40,7 +40,8 @@ public class CarpetScriptServer
public CarpetEventServer events;
public static List bundledModuleData = new ArrayList(){{
- add(new CameraPathModule());
+ add(new BundledModule("camera"));
+ add(new BundledModule("event_test"));
}};
public CarpetScriptServer()
diff --git a/src/main/java/carpet/script/bundled/BundledModule.java b/src/main/java/carpet/script/bundled/BundledModule.java
new file mode 100644
index 00000000..a21890db
--- /dev/null
+++ b/src/main/java/carpet/script/bundled/BundledModule.java
@@ -0,0 +1,39 @@
+package carpet.script.bundled;
+
+import org.apache.commons.io.IOUtils;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+public class BundledModule implements ModuleInterface
+{
+ private String name;
+ private String code;
+ public BundledModule(String scriptName)
+ {
+ try
+ {
+ name = scriptName;
+ code = IOUtils.toString(
+ getClass().getClassLoader().getResourceAsStream("assets/carpet/scripts/"+scriptName+".sc"),
+ StandardCharsets.UTF_8
+ );
+ }
+ catch ( NullPointerException | IOException e)
+ {
+ name = null;
+ code = null;
+ }
+ }
+ @Override
+ public String getName()
+ {
+ return name;
+ }
+
+ @Override
+ public String getCode()
+ {
+ return code;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/carpet/script/bundled/CameraPathModule.java b/src/main/java/carpet/script/bundled/CameraPathModule.java
deleted file mode 100644
index f2aca079..00000000
--- a/src/main/java/carpet/script/bundled/CameraPathModule.java
+++ /dev/null
@@ -1,334 +0,0 @@
-package carpet.script.bundled;
-
-public class CameraPathModule implements ModuleInterface
-{
- @Override
- public String getName()
- {
- return "camera";
- }
-
- @Override
- public String getCode()
- {
- return " __command() ->\n" +
- " (\n" +
- " print('Camera path module.');\n" +
- " print('-------------------');\n" +
- " print(' \"/camera start\" - set the starting point');\n" +
- " print('');\n" +
- " print(' \"/camera add \" - add another point frames later');\n" +
- " print('');\n" +
- " print(' \"/camera select_interpolation < linear | gauss_? >\"');\n" +
- " print(' Select interpolation between points:');\n" +
- " print(' - linear: straight paths between points.');\n" +
- " print(' - gauss_auto: automatic smooth transitions.');\n" +
- " print(' - gauss_: custom fixed variance ');\n" +
- " print(' (in points) for special effects.');\n" +
- " print('');\n" +
- " print(' \"/camera repeat \" - ');\n" +
- " print(' Repeat existing points configuration n-times');\n" +
- " print(' using points to link path ends');\n" +
- " print('');\n" +
- " print(' \"/camera speed - ');\n" +
- " print(' Change number of frames between points');\n" +
- " print(' from 25 -> 4 times faster (less points),');\n" +
- " print(' to 400 -> 4 times slower (more points)');\n" +
- " print('');\n" +
- " print(' \"/camera play : run a path with a player');\n" +
- " print(' needs to be multiples of 20, (20 tps)');\n" +
- " print('');\n" +
- " print(' \"/camera show\": shows current path for a moment');\n" +
- " print('');\n" +
- " print(' \"/script in camera invoke _show_path_tick \":');\n" +
- " print(' place this in a repeating commandblock');\n" +
- " print(' to display path continuously');\n" +
- " print(' with set particle and number of particles per tick');\n" +
- " print(' example: \\'dust 0.9 0.1 0.1 1\\' 100 ');\n" +
- " ''\n" +
- " );\n" +
- " start() -> \n" +
- "(\n" +
- " p = player();\n" +
- " global_points = l(l(l(p~'x',p~'y',p~'z',p~'yaw',p~'pitch'),0,'sharp'));\n" +
- " undef('global_path_precalculated');\n" +
- " str('Started path at %.1f %.1f %.1f', p~'x', p~'y', p~'z')\n" +
- ");\n" +
- "\n" +
- " add(delay) -> \n" +
- "( \n" +
- " p = player(); \n" +
- " mode = 'sharp';\n" +
- " 'mode is currently unused, run_path does always sharp, gauss interpolator is always smooth';\n" +
- " ' but this option could be used could be used at some point by more robust interpolators';\n" +
- " vector = l(p~'x',p~'y',p~'z', p~'yaw', p~'pitch');\n" +
- " __add_path_segment(vector, delay, mode);\n" +
- " str('Added point %d: %.1f %.1f %.1f', length(global_points), p~'x', p~'y', p~'z')\n" +
- ");\n" +
- "\n" +
- " __add_path_segment(vector, duration, mode) -> \n" +
- "(\n" +
- " undef('global_path_precalculated');\n" +
- " if ( (l('sharp','smooth') ~ mode) == null, exit('use smooth or sharp point')); \n" +
- " if(!global_points, exit('Cannot add point to path that didn\\'t started yet!'));\n" +
- " l(v, end_time, m) = element(global_points, -1);\n" +
- " put(vector,-2, __adjusted_rot(element(v, -2), element(vector, -2)));\n" +
- " global_points += l(vector, end_time+duration, mode)\n" +
- ");\n" +
- "\n" +
- "'adjusts current rotation so we don\\'t spin around like crazy';\n" +
- " __adjusted_rot(previous_rot, current_rot) -> \n" +
- "(\n" +
- " while( abs(previous_rot-current_rot) > 180, 1000,\n" +
- " current_rot += if(previous_rot < current_rot, -360, 360)\n" +
- " );\n" +
- " current_rot\n" +
- ");\n" +
- "\n" +
- "\n" +
- " repeat(times, last_section_duration) -> \n" +
- "(\n" +
- " undef('global_path_precalculated');\n" +
- " positions = map(global_points, k = element(_, 0));\n" +
- " modes = map(global_points, element(_, -1));\n" +
- " durations = map(global_points, element(element(global_points, _i+1), 1)-element(_, 1));\n" +
- " put(durations, -1, last_section_duration);\n" +
- " loop(times,\n" +
- " loop( length(positions),\n" +
- " __add_path_segment(element(positions, _), element(durations, _), element(modes, _))\n" +
- " )\n" +
- " );\n" +
- " str('Add %d points %d times', length(positions), times)\n" +
- ");\n" +
- "\n" +
- " speed(percentage) ->\n" +
- "(\n" +
- " undef('global_path_precalculated');\n" +
- " if (percentage < 25 || percentage > 400, \n" +
- " exit('path speed can only be speed, or slowed down 4 times. Recall command for larger changes')\n" +
- " );\n" +
- " ratio = percentage/100;\n" +
- " previous_path_length = element(element(global_points, -1),1);\n" +
- " for(global_points, put(_, 1, element(_, 1)*ratio ) );\n" +
- " undef('global_path_precalculated');\n" +
- " str('path %s from %d to %d ticks',\n" +
- " if(ratio<1,'shortened','extended'),\n" +
- " previous_path_length,\n" +
- " element(element(global_points, -1),1)\n" +
- " )\n" +
- ");\n" +
- "\n" +
- " select_interpolation(method) ->\n" +
- "(\n" +
- " undef('global_path_precalculated');\n" +
- " __prepare_path_if_needed() -> __prepare_path_if_needed_generic();\n" +
- " 'each supported method needs to specify its __find_position_for_point to trace the path';\n" +
- " 'accepting segment number, and position in the segment';\n" +
- " 'or optionally __prepare_path_if_needed, if path is inefficient to compute point by point';\n" +
- " if (\n" +
- " method == 'linear',\n" +
- " (\n" +
- " __find_position_for_point(s, p) -> __find_position_for_linear(s, p)\n" +
- " ),\n" +
- " method ~ '^gauss_',\n" +
- " (\n" +
- " type = method - 'gauss_';\n" +
- " global_interpol_option = if(type=='auto',0,number(type));\n" +
- " __find_position_for_point(s, p) -> __find_position_for_gauss(s, p)\n" +
- " ),\n" +
- " method ~ '^bungee_',\n" +
- " (\n" +
- " exit('unsupported / planned');\n" +
- " type = method - 'bungee_';\n" +
- " global_interpol_option = if(type=='auto',80,number(type));\n" +
- " __prepare_path_if_needed() -> __prepare_path_if_needed_bungee()\n" +
- " ),\n" +
- " \n" +
- " exit('Choose one of the following methods: linear, gauss:auto, gauss:')\n" +
- " );\n" +
- " 'Ok'\n" +
- ");\n" +
- "\n" +
- " select_interpolation('linear');\n" +
- "\n" +
- " __assert_valid_for_motion() ->\n" +
- "(\n" +
- " if(!global_points, exit('Path not defined yet'));\n" +
- " if(length(global_points)<2, exit('Path not complete - add more points'));\n" +
- " null \n" +
- ");\n" +
- "\n" +
- " __get_path_at(segment, start, index) ->\n" +
- "(\n" +
- " v = element(global_path_precalculated, start+index);\n" +
- " if(v == null,\n" +
- " v = __find_position_for_point(segment, index);\n" +
- " put(global_path_precalculated, start+index, v)\n" +
- " );\n" +
- " v\n" +
- ");\n" +
- "\n" +
- " __invalidate_points_cache() -> global_path_precalculated = map(range(element(element(global_points, -1),1)), null);\n" +
- "\n" +
- " show() -> \n" +
- "(\n" +
- " loop(100,\n" +
- " _show_path_tick('dust 0.9 0.1 0.1 1', 100);\n" +
- " game_tick(50)\n" +
- " );\n" +
- " 'Done!'\n" +
- ");\n" +
- "\n" +
- " __play(fps) -> \n" +
- "(\n" +
- " p = player();\n" +
- " __assert_valid_for_motion();\n" +
- " __prepare_path_if_needed();\n" +
- " loop( length(global_points)-1,\n" +
- " segment = _;\n" +
- " start = element(element(global_points, segment),1);\n" +
- " end = element(element(global_points, segment+1),1);\n" +
- " loop(end-start,\n" +
- " v = __get_path_at(segment, start, _);\n" +
- " modify(p, 'location', v);\n" +
- " game_tick(1000/fps)\n" +
- " )\n" +
- " );\n" +
- " game_tick(1000);\n" +
- " 'Done!'\n" +
- ");\n" +
- "\n" +
- " play(fps) -> \n" +
- "(\n" +
- " p = player();\n" +
- " __assert_valid_for_motion();\n" +
- " __prepare_path_if_needed();\n" +
- " if ((fps % 20 != 0) || fps < 20, exit('FPS needs to be multiples of 20') );\n" +
- "\ttpt = round(fps / 20);\n" +
- " mspt = 50 / tpt; \n" +
- " start_time = time();\n" +
- " point = 0;\n" +
- " loop( length(global_points)-1,\n" +
- " segment = _;\n" +
- " start = element(element(global_points, segment),1);\n" +
- " end = element(element(global_points, segment+1),1);\n" +
- " loop(end-start,\n" +
- " v = __get_path_at(segment, start, _);\n" +
- " modify(p, 'location', v);\n" +
- " point += 1;\n" +
- " if ((point % tpt == 0), game_tick());\n" +
- " end_time = time();\n" +
- " took = end_time - start_time;\n" +
- " if (took < mspt, sleep(mspt-took));\n" +
- " start_time = time()\n" +
- " )\n" +
- " );\n" +
- " game_tick(1000);\n" +
- " 'Done!'\n" +
- ");\n" +
- "\n" +
- " _show_path_tick(particle_type, total) -> (\n" +
- " __assert_valid_for_motion();\n" +
- " __prepare_path_if_needed();\n" +
- " loop(total,\n" +
- " segment = floor(rand(length(global_points)-1));\n" +
- " start = element(element(global_points, segment),1);\n" +
- " end = element(element(global_points, segment+1),1);\n" +
- " index = floor(rand(end-start));\n" +
- " l(x, y, z) = slice(__get_path_at(segment, start, index), 0, 3);\n" +
- " particle(particle_type, x, y, z, 1, 0, 0)\n" +
- " );\n" +
- " null\n" +
- ");\n" +
- "\n" +
- " __prepare_path_if_needed_generic() ->\n" +
- "(\n" +
- " if(!global_path_precalculated, __invalidate_points_cache())\n" +
- ");\n" +
- "\n" +
- "__find_position_for_linear(segment, point) ->\n" +
- "(\n" +
- " l(va, start, mode_a) = element(global_points,segment);\n" +
- " l(vb, end, mode_b) = element(global_points,segment+1);\n" +
- " section = end-start;\n" +
- " dt = point/section;\n" +
- " dt*vb+(1-dt)*va\n" +
- ");\n" +
- "\n" +
- "\n" +
- "'(1/sqrt(2*pi*d*d))*euler^(-((x-miu)^2)/(2*d*d)) ';\n" +
- " 'but we will be normalizing anyways, so who cares';\n" +
- " __norm_prob(x, miu, d) -> euler^(-((x-miu)^2)/(2*d*d));\n" +
- "\n" +
- " __find_position_for_gauss(from_index, point) -> \n" +
- "(\n" +
- " dev = global_interpol_option;\n" +
- " components = l();\n" +
- " path_point = element(element(global_points, from_index),1);\n" +
- " \n" +
- " try(\n" +
- " for(range(from_index+1, length(global_points)),\n" +
- " l(v,ptime,mode) = element(global_points, _);\n" +
- " dev = if (global_interpol_option > 0, global_interpol_option, \n" +
- " devs = l();\n" +
- " if (_+1 < length(global_points), devs += element(element(global_points, _+1),1)-ptime);\n" +
- " if (_-1 >= 0, devs += ptime-element(element(global_points, _-1),1));\n" +
- " 0.6*reduce(devs, _a+_, 0)/length(devs)\n" +
- " );\n" +
- " impact = __norm_prob(path_point+point, ptime, dev);\n" +
- " if(rtotal && impact < 0.000001*rtotal, throw(null));\n" +
- " components += l(v, impact);\n" +
- " rtotal += impact\n" +
- " )\n" +
- " ,null\n" +
- " );\n" +
- " try(\n" +
- " for(range(from_index, -1, -1),\n" +
- " l(v,ptime,mode) = element(global_points, _);\n" +
- " dev = if (global_interpol_option > 0, global_interpol_option, \n" +
- " devs = l();\n" +
- " if (_+1 < length(global_points), devs += element(element(global_points, _+1),1)-ptime);\n" +
- " if (_-1 >= 0, devs += ptime-element(element(global_points, _-1),1));\n" +
- " 0.6*reduce(devs, _a+_, 0)/length(devs)\n" +
- " );\n" +
- " impact = __norm_prob(path_point+point, ptime, dev);\n" +
- " if(ltotal && impact < 0.000001*ltotal, throw(null));\n" +
- " components += l(v, impact);\n" +
- " ltotal += impact\n" +
- " )\n" +
- " ,null\n" +
- " );\n" +
- " total = rtotal+ltotal;\n" +
- " reduce(components, _a+element(_,0)*(element(_,1)/total), l(0,0,0,0,0))\n" +
- ");\n" +
- " __prepare_path_if_needed_bungee(fps) ->\n" +
- "(\n" +
- " exit('not ready!');\n" +
- " if(!global_points, exit('Cannot show path that doesn\\'t exist'));\n" +
- " if(length(global_points)<2, exit('Path not complete - add more points'));\n" +
- " v = element(element(global_points, 0),0);\n" +
- " modify(p, 'pos', slice(v,0,3));\n" +
- " modify(p, 'yaw', element(v,3));\n" +
- " modify(p, 'pitch', element(v,4));\n" +
- " current_target = element(element(global_points, 1),0);\n" +
- " current_hook = 1;\n" +
- " loop(length(global_points)-1, \n" +
- " current_base = _;\n" +
- " l(va, start, mode_a) = element(global_points,_);\n" +
- " l(vb, end, mode_b) = element(global_points,_+1);\n" +
- " section = end-start;\n" +
- " loop(section,\n" +
- " dt = _/section;\n" +
- "\n" +
- " v = dt*vb+(1-dt)*va;\n" +
- " modify(p, 'pos', slice(v,0,3));\n" +
- " modify(p, 'yaw', element(v,3));\n" +
- " modify(p, 'pitch', element(v,4));\n" +
- " game_tick(1000/fps)\n" +
- " )\n" +
- " );\n" +
- " game_tick(1000);\n" +
- " 'Done!'\n" +
- ")\n";
- }
-}
diff --git a/src/main/resources/assets/carpet/scripts/camera.sc b/src/main/resources/assets/carpet/scripts/camera.sc
new file mode 100644
index 00000000..5e4d7d6f
--- /dev/null
+++ b/src/main/resources/assets/carpet/scripts/camera.sc
@@ -0,0 +1,248 @@
+__command() ->
+(
+ print('camera_path module.');
+ print('-------------------');
+ print(' "/camera_path start" - set the starting point');
+ print('');
+ print(' "/camera_path add " - add another point frames later');
+ print('');
+ print(' "/camera_path select_interpolation < linear | gauss_? >"');
+ print(' Select interpolation between points:');
+ print(' - linear: straight paths between points.');
+ print(' - gauss_auto: automatic smooth transitions.');
+ print(' - gauss_: custom fixed variance ');
+ print(' (in points) for special effects.');
+ print('');
+ print(' "/camera_path repeat " - ');
+ print(' Repeat existing points configuration n-times');
+ print(' using points to link path ends');
+ print('');
+ print(' "/camera_path speed - ');
+ print(' Change number of frames between points');
+ print(' from 25 -> 4 times faster (less points),');
+ print(' to 400 -> 4 times slower (more points)');
+ print('');
+ print(' "/camera_path play : run a path with a player');
+ print(' needs to be multiples of 20, (20 tps)');
+ print('');
+ print(' "/camera_path show": shows current path for a moment');
+ print('');
+ print(' "/script in camera_path invoke _show_path_tick ":');
+ print(' place this in a repeating commandblock');
+ print(' to display path continuously');
+ print(' with set particle and number of particles per tick');
+ print(' example: \'dust 0.9 0.1 0.1 1\' 100 ');
+ ''
+);
+
+start() ->
+(
+ p = player();
+ global_points = l(l(p ~ 'location', 0,'sharp'));
+ undef('global_path_precalculated');
+ str('Started path at %.1f %.1f %.1f', p~'x', p~'y', p~'z')
+);
+add(delay) ->
+(
+ p = player();
+ mode = 'sharp';
+ //mode is currently unused, run_path does always sharp, gauss interpolator is always smooth
+ // but this option could be used could be used at some point by more robust interpolators
+ __add_path_segment(p ~ 'location', delay, mode);
+ str('Added point %d: %.1f %.1f %.1f', length(global_points), p~'x', p~'y', p~'z')
+);
+__add_path_segment(vector, duration, mode) ->
+(
+ undef('global_path_precalculated');
+ if ( (l('sharp','smooth') ~ mode) == null, exit('use smooth or sharp point'));
+ if(!global_points, exit('Cannot add point to path that didn\'t started yet!'));
+ l(v, end_time, m) = get(global_points, -1);
+ put(vector,-2, __adjusted_rot(get(v, -2), get(vector, -2)));
+ global_points += l(vector, end_time+duration, mode)
+);
+// adjusts current rotation so we don\'t spin around like crazy
+__adjusted_rot(previous_rot, current_rot) ->
+(
+ while( abs(previous_rot-current_rot) > 180, 1000,
+ current_rot += if(previous_rot < current_rot, -360, 360)
+ );
+ current_rot
+);
+
+
+repeat(times, last_section_duration) ->
+(
+ undef('global_path_precalculated');
+ positions = map(global_points, k = get(_, 0));
+ modes = map(global_points, get(_, -1));
+ durations = map(global_points, get(get(global_points, _i+1), 1)-get(_, 1));
+ put(durations, -1, last_section_duration);
+ loop(times,
+ loop( length(positions),
+ __add_path_segment(get(positions, _), get(durations, _), get(modes, _))
+ )
+ );
+ str('Add %d points %d times', length(positions), times)
+);
+speed(percentage) ->
+(
+ undef('global_path_precalculated');
+ if (percentage < 25 || percentage > 400,
+ exit('path speed can only be speed, or slowed down 4 times. Recall command for larger changes')
+ );
+ ratio = percentage/100;
+ previous_path_length = get(get(global_points, -1),1);
+ for(global_points, put(_, 1, get(_, 1)*ratio ) );
+ undef('global_path_precalculated');
+ str('path %s from %d to %d ticks',
+ if(ratio<1,'shortened','extended'),
+ previous_path_length,
+ get(get(global_points, -1),1)
+ )
+);
+select_interpolation(method) ->
+(
+ undef('global_path_precalculated');
+ __prepare_path_if_needed() -> __prepare_path_if_needed_generic();
+ // each supported method needs to specify its __find_position_for_point to trace the path
+ // accepting segment number, and position in the segment
+ // or optionally __prepare_path_if_needed, if path is inefficient to compute point by point
+ if (
+ method == 'linear',
+ (
+ __find_position_for_point(s, p) -> __find_position_for_linear(s, p)
+ ),
+ method ~ '^gauss_',
+ (
+ type = method - 'gauss_';
+ global_interpol_option = if(type=='auto',0,number(type));
+ __find_position_for_point(s, p) -> __find_position_for_gauss(s, p)
+ ),
+
+ exit('Choose one of the following methods: linear, gauss:auto, gauss:')
+ );
+ 'Ok'
+);
+select_interpolation('gauss_auto');
+__assert_valid_for_motion() ->
+(
+ if(!global_points, exit('Path not defined yet'));
+ if(length(global_points)<2, exit('Path not complete - add more points'));
+ null
+);
+__get_path_at(segment, start, index) ->
+(
+ v = get(global_path_precalculated, start+index);
+ if(v == null,
+ v = __find_position_for_point(segment, index);
+ put(global_path_precalculated, start+index, v)
+ );
+ v
+);
+__invalidate_points_cache() -> global_path_precalculated = map(range(get(get(global_points, -1),1)), null);
+show() ->
+(
+ loop(100,
+ _show_path_tick('dust 0.9 0.1 0.1 1', 100);
+ game_tick(50)
+ );
+ 'Done!'
+);
+play(fps) ->
+(
+ p = player();
+ __assert_valid_for_motion();
+ __prepare_path_if_needed();
+ if ((fps % 20 != 0) || fps < 20, exit('FPS needs to be multiples of 20') );
+ tpt = round(fps / 20);
+ mspt = 50 / tpt;
+ start_time = time();
+ point = 0;
+ loop( length(global_points)-1,
+ segment = _;
+ start = get(get(global_points, segment),1);
+ end = get(get(global_points, segment+1),1);
+ loop(end-start,
+ v = __get_path_at(segment, start, _);
+ modify(p, 'location', v);
+ point += 1;
+ if ((point % tpt == 0), game_tick());
+ end_time = time();
+ took = end_time - start_time;
+ if (took < mspt, sleep(mspt-took));
+ start_time = time()
+ )
+ );
+ game_tick(1000);
+ 'Done!'
+);
+_show_path_tick(particle_type, total) ->
+(
+ __assert_valid_for_motion();
+ __prepare_path_if_needed();
+ loop(total,
+ segment = floor(rand(length(global_points)-1));
+ start = get(get(global_points, segment),1);
+ end = get(get(global_points, segment+1),1);
+ index = floor(rand(end-start));
+ l(x, y, z) = slice(__get_path_at(segment, start, index), 0, 3);
+ particle(particle_type, x, y, z, 1, 0, 0)
+ );
+ null
+);
+__prepare_path_if_needed_generic() ->
+(
+ if(!global_path_precalculated, __invalidate_points_cache())
+);
+__find_position_for_linear(segment, point) ->
+(
+ l(va, start, mode_a) = get(global_points,segment);
+ l(vb, end, mode_b) = get(global_points,segment+1);
+ section = end-start;
+ dt = point/section;
+ dt*vb+(1-dt)*va
+);
+//(1/sqrt(2*pi*d*d))*euler^(-((x-miu)^2)/(2*d*d))
+// but we will be normalizing anyways, so who cares
+__norm_prob(x, miu, d) -> euler^(-((x-miu)^2)/(2*d*d));
+__find_position_for_gauss(from_index, point) ->
+(
+ dev = global_interpol_option;
+ components = l();
+ path_point = get(get(global_points, from_index),1);
+
+ try(
+ for(range(from_index+1, length(global_points)),
+ l(v,ptime,mode) = get(global_points, _);
+ dev = if (global_interpol_option > 0, global_interpol_option,
+ devs = l();
+ if (_+1 < length(global_points), devs += get(get(global_points, _+1),1)-ptime);
+ if (_-1 >= 0, devs += ptime-get(get(global_points, _-1),1));
+ 0.6*reduce(devs, _a+_, 0)/length(devs)
+ );
+ impact = __norm_prob(path_point+point, ptime, dev);
+ if(rtotal && impact < 0.000001*rtotal, throw(null));
+ components += l(v, impact);
+ rtotal += impact
+ )
+ ,null
+ );
+ try(
+ for(range(from_index, -1, -1),
+ l(v,ptime,mode) = get(global_points, _);
+ dev = if (global_interpol_option > 0, global_interpol_option,
+ devs = l();
+ if (_+1 < length(global_points), devs += get(get(global_points, _+1),1)-ptime);
+ if (_-1 >= 0, devs += ptime-get(get(global_points, _-1),1));
+ 0.6*reduce(devs, _a+_, 0)/length(devs)
+ );
+ impact = __norm_prob(path_point+point, ptime, dev);
+ if(ltotal && impact < 0.000001*ltotal, throw(null));
+ components += l(v, impact);
+ ltotal += impact
+ )
+ ,null
+ );
+ total = rtotal+ltotal;
+ reduce(components, _a+get(_,0)*(get(_,1)/total), l(0,0,0,0,0))
+)
\ No newline at end of file
diff --git a/src/main/resources/assets/carpet/scripts/event_test.sc b/src/main/resources/assets/carpet/scripts/event_test.sc
new file mode 100644
index 00000000..b5605eef
--- /dev/null
+++ b/src/main/resources/assets/carpet/scripts/event_test.sc
@@ -0,0 +1,116 @@
+
+__on_player_jumps(player) -> print('Player '+player+' jumps.');
+
+__on_player_deploys_elytra(player) -> print('Player '+player+' deploys elytra.');
+
+__on_player_wakes_up(player) -> print('Player '+player+' wakes up. Lemme know when this starts working');
+
+__on_player_rides(player, forward, strafe, jumping, sneaking) ->
+(
+ print('');
+ print('player rides a vehicle:');
+ print(' - player: '+player);
+ print(' - forward/backward: '+forward);
+ print(' - strafing: '+strafe);
+ print(' - jumping: '+jumping);
+ print(' - sneaking: '+sneaking)
+);
+
+__on_player_uses_item(player, item_tuple, hand) ->
+(
+ l(item, count, nbt) = item_tuple || l('None', 0, null);
+ print('');
+ print('player uses an item:');
+ print(' - player: '+player);
+ print(' - item:');
+ print(' > name: '+item);
+ print(' > count: '+count);
+ print(' > nbt: '+nbt);
+ print(' - hand: '+hand)
+);
+
+__on_player_clicks_block(player, block, face) ->
+(
+ print('');
+ print('player clicks an item:');
+ print(' - player: '+player);
+ print(' - block: '+block+' at '+map(pos(block), str('%.2f',_)));
+ print(' - face: '+face)
+);
+
+
+__on_player_right_clicks_block(player, item_tuple, hand, block, face, hitvec) ->
+(
+ l(item, count, nbt) = item_tuple || l('None', 0, null);
+ print('');
+ print('block right clicked by player:');
+ print(' - player: '+player);
+ print(' - item: '+item);
+ print(' - hand: '+hand);
+ print(' - block: '+block+' at '+map(pos(block), str('%.2f',_)));
+ print(' - face: '+face);
+ print(' - hitvec: '+map(hitvec, str('%.2f',_)))
+);
+
+__on_player_breaks_block(player, block) ->
+(
+ print('');
+ print('player breaks block:');
+ print(' - player: '+player);
+ print(' - block: '+block+' at '+map(pos(block), str('%.2f',_)))
+);
+
+__on_player_interacts_with_entity(player, entity, hand) ->
+(
+ print('');
+ print('player interacts with entity:');
+ print(' - player: '+player);
+ print(' - entity: '+entity+' at '+map(pos(entity), str('%.2f',_)));
+ print(' - hand: '+hand)
+);
+
+__on_player_attacks_entity(player, entity) ->
+(
+ print('');
+ print('player attacks entity:');
+ print(' - player: '+player);
+ print(' - entity: '+entity+' at '+map(pos(entity), str('%.2f',_)))
+);
+
+__on_player_starts_sneaking(player) -> print('Player '+player+' starts sneaking.');
+
+__on_player_stops_sneaking(player) -> print('Player '+player+' stops sneaking.');
+
+__on_player_starts_sprinting(player) -> print('Player '+player+' starts sprinting.');
+
+__on_player_stops_sprinting(player) -> print('Player '+player+' stops sprinting.');
+
+__on_player_releases_item(player, item_tuple, hand) ->
+(
+ l(item, count, nbt) = item_tuple || l('None', 0, null);
+ print('');
+ print('player releases an item:');
+ print(' - player: '+player);
+ print(' - item:');
+ print(' > name: '+item);
+ print(' > count: '+count);
+ print(' > nbt: '+nbt);
+ print(' - hand: '+hand)
+);
+
+__on_player_finishes_using_item(player, item_tuple, hand) ->
+(
+ l(item, count, nbt) = item_tuple || l('None', 0, null);
+ print('');
+ print('player finishes using an item:');
+ print(' - player: '+player);
+ print(' - item:');
+ print(' > name: '+item);
+ print(' > count: '+count);
+ print(' > nbt: '+nbt);
+ print(' - hand: '+hand)
+);
+
+__on_player_drops_item(player) -> print('Player '+player+' drops current item.');
+
+__on_player_drops_stack(player) -> print('Player '+player+' drops current stack.');
\ No newline at end of file