diff --git a/docs/scarpet/Full.md b/docs/scarpet/Full.md
index 572c8123..baed6c5d 100644
--- a/docs/scarpet/Full.md
+++ b/docs/scarpet/Full.md
@@ -276,7 +276,8 @@ global_foo = floor(rand(10));
check_foo_not_zero();
...
check_foo_not_zero() -> if(global_foo == 0, global_foo = 1)
-# Variables and Constants
+
+# Variables and Constants
`scarpet` provides a number of constants that can be used literally in scripts
@@ -2055,6 +2056,10 @@ Returns generation status as per the ticket system. Can return any value from se
can only be stable in a few states: `full`, `features`, `liquid_carvers`, and `structure_starts`. Returns `null`
if the chunk is not in memory unless called with optional `true`.
+### `inhabited_time(pos)`
+
+Returns inhabited time for a chunk.
+
### `structures(pos), structures(pos, structure_name)`
Returns structure information for a given block position. Note that structure information is the same for all the
@@ -2872,6 +2877,10 @@ __on_player_interacts_with_block(player, hand, block, face, hitvec) //right cli
__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_takes_damage(player, amount, source, source_entity)
+__on_player_deals_damage(player, amount, entity)
+__on_player_dies(player)
+__on_player_respawns(player)
__on_player_rides(player, forward, strafe, jumping, sneaking)
__on_player_jumps(player)
__on_player_deploys_elytra(player)
diff --git a/docs/scarpet/api/BlocksAndWorldAccess.md b/docs/scarpet/api/BlocksAndWorldAccess.md
index 7c31b2cd..1ec333d7 100644
--- a/docs/scarpet/api/BlocksAndWorldAccess.md
+++ b/docs/scarpet/api/BlocksAndWorldAccess.md
@@ -519,6 +519,10 @@ Returns generation status as per the ticket system. Can return any value from se
can only be stable in a few states: `full`, `features`, `liquid_carvers`, and `structure_starts`. Returns `null`
if the chunk is not in memory unless called with optional `true`.
+### `inhabited_time(pos)`
+
+Returns inhabited time for a chunk.
+
### `structures(pos), structures(pos, structure_name)`
Returns structure information for a given block position. Note that structure information is the same for all the
diff --git a/docs/scarpet/api/Events.md b/docs/scarpet/api/Events.md
index aa9f1c98..6408ac94 100644
--- a/docs/scarpet/api/Events.md
+++ b/docs/scarpet/api/Events.md
@@ -33,6 +33,10 @@ __on_player_interacts_with_block(player, hand, block, face, hitvec) //right cli
__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_takes_damage(player, amount, source, source_entity)
+__on_player_deals_damage(player, amount, entity)
+__on_player_dies(player)
+__on_player_respawns(player)
__on_player_rides(player, forward, strafe, jumping, sneaking)
__on_player_jumps(player)
__on_player_deploys_elytra(player)
diff --git a/docs/scarpet/language/Overview.md b/docs/scarpet/language/Overview.md
index 0689740f..0ad850f5 100644
--- a/docs/scarpet/language/Overview.md
+++ b/docs/scarpet/language/Overview.md
@@ -276,4 +276,4 @@ global_foo = floor(rand(10));
check_foo_not_zero();
...
check_foo_not_zero() -> if(global_foo == 0, global_foo = 1)
-
\ No newline at end of file
+
diff --git a/docs/scarpet/resources/editors/idea/2.txt b/docs/scarpet/resources/editors/idea/2.txt
index bbdf2f18..c98522d1 100644
--- a/docs/scarpet/resources/editors/idea/2.txt
+++ b/docs/scarpet/resources/editors/idea/2.txt
@@ -30,6 +30,7 @@ hardness
harvest
in_dimension
in_slime_chunk
+inhabited_time
inventory_find
inventory_get
inventory_remove
diff --git a/docs/scarpet/resources/editors/idea/4.txt b/docs/scarpet/resources/editors/idea/4.txt
index 6c37a65a..6200e26c 100644
--- a/docs/scarpet/resources/editors/idea/4.txt
+++ b/docs/scarpet/resources/editors/idea/4.txt
@@ -25,4 +25,8 @@ __on_player_wakes_up
__on_statistic
__on_tick
__on_tick_ender
-__on_tick_nether
\ No newline at end of file
+__on_tick_nether
+__on_player_takes_damage
+__on_player_deals_damage
+__on_player_dies
+__on_player_respawns
\ No newline at end of file
diff --git a/docs/scarpet/resources/editors/npp/scarpet.xml b/docs/scarpet/resources/editors/npp/scarpet.xml
index 332d1030..8c06f293 100644
--- a/docs/scarpet/resources/editors/npp/scarpet.xml
+++ b/docs/scarpet/resources/editors/npp/scarpet.xml
@@ -54,7 +54,7 @@
hardness blast_resistance top loaded suffocates power ticks_randomly update block_tick random_tick in_slime_chunk
set without_updates
blocks_movement block_sound material map_colour property block_properties block_data poi set_poi
- place_item set_biome biome loaded_status generation_status chunk_tickets
+ place_item set_biome biome loaded_status generation_status inhabited_time chunk_tickets
structures structure_references set_structure reset_chunk
scoreboard scoreboard_add scoreboard_remove scoreboard_display
@@ -104,6 +104,10 @@
__on_tick
__on_tick_ender
__on_tick_nether
+ __on_player_takes_damage
+ __on_player_deals_damage
+ __on_player_dies
+ __on_player_respawns
$
00' 01\ 02' 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
diff --git a/src/main/java/carpet/CarpetSettings.java b/src/main/java/carpet/CarpetSettings.java
index fdf2a1ed..8aab8102 100644
--- a/src/main/java/carpet/CarpetSettings.java
+++ b/src/main/java/carpet/CarpetSettings.java
@@ -5,13 +5,11 @@ import carpet.settings.Rule;
import carpet.settings.SettingsManager;
import carpet.settings.Validator;
import carpet.utils.Messenger;
+import carpet.utils.SpawnChunks;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.dedicated.DedicatedServer;
-import net.minecraft.server.world.ChunkTicketType;
-import net.minecraft.server.world.ServerChunkManager;
import net.minecraft.server.world.ServerWorld;
-import net.minecraft.util.Unit;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.ChunkPos;
@@ -236,13 +234,6 @@ public class CarpetSettings
@Rule( desc = "Pistons can push block entities, like hoppers, chests etc.", category = {EXPERIMENTAL, FEATURE} )
public static boolean movableBlockEntities = false;
- /*@Rule(
- desc = "Orange stained glass behaves like slime, but doesn't stick to it",
- extra = "Only available for 1.14. in 1.15 use honey instead",
- category = {EXPERIMENTAL, FEATURE}
- )
- public static boolean honeySlime = false;*/
-
@Rule( desc = "Saplings turn into dead shrubs in hot climates and no water access", category = FEATURE )
public static boolean desertShrubs = false;
@@ -359,9 +350,6 @@ public class CarpetSettings
)
public static boolean missingTools = false;
- //@Rule(desc = "Alternative, persistent caching strategy for nether portals", category = {SURVIVAL, CREATIVE})
- //public static boolean portalCaching = false; // ineffective in 1.15
-
@Rule(desc = "fill/clone/setblock and structure blocks cause block updates", category = CREATIVE)
public static boolean fillUpdates = true;
@@ -512,13 +500,9 @@ public class CarpetSettings
)
public static int viewDistance = 0;
- private static class DisableSpawnChunksValidator extends Validator {
- @Override public Boolean validate(ServerCommandSource source, ParsedRule currentRule, Boolean newValue, String string) {
- if (currentRule.get().booleanValue() == newValue.booleanValue())
- {
- //must been some startup thing
- return newValue;
- }
+ public static class ChangeSpawnChunksValidator extends Validator {
+ public static void changeSpawnSize(int size)
+ {
ServerWorld overworld = CarpetServer.minecraft_server.getWorld(DimensionType.OVERWORLD);
if (overworld != null) {
ChunkPos centerChunk = new ChunkPos(new BlockPos(
@@ -526,40 +510,37 @@ public class CarpetSettings
overworld.getLevelProperties().getSpawnY(),
overworld.getLevelProperties().getSpawnZ()
));
- ServerChunkManager chunkManager = (ServerChunkManager) overworld.getChunkManager();
-
- chunkManager.removeTicket(ChunkTicketType.START, centerChunk, 11, Unit.INSTANCE);
- if (!newValue)
- {
- chunkManager.addTicket(ChunkTicketType.START, centerChunk, 11, Unit.INSTANCE);
- }
+ SpawnChunks.changeSpawnChunks(overworld.getChunkManager(), centerChunk, size);
+ }
+ }
+ @Override public Integer validate(ServerCommandSource source, ParsedRule currentRule, Integer newValue, String string) {
+ if (newValue < 0 || newValue > 32)
+ {
+ Messenger.m(source, "r spawn chunk size has to be between 0 and 32");
+ return null;
+ }
+ if (currentRule.get().intValue() == newValue.intValue())
+ {
+ //must been some startup thing
+ return newValue;
+ }
+ ServerWorld currentOverworld = CarpetServer.minecraft_server.getWorld(DimensionType.OVERWORLD);
+ if (currentOverworld != null)
+ {
+ changeSpawnSize(newValue);
}
return newValue;
}
}
@Rule(
- desc = "Allows spawn chunks to unload",
+ desc = "Changes size of spawn chunks",
+ extra = {"Defines new radius", "setting it to 0 - disables spawn chunks"},
category = CREATIVE,
- validate = DisableSpawnChunksValidator.class
- )
- public static boolean disableSpawnChunks = false;
-
- /*private static class KelpLimit extends Validator
- {
- @Override public Integer validate(ServerCommandSource source, ParsedRule currentRule, Integer newValue, String string) {
- return (newValue>=0 && newValue <=25)?newValue:null;
- }
- @Override
- public String description() { return "You must choose a value from 0 to 25. 25 and all natural kelp can grow 25 blocks, choose 0 to make all generated kelp not to grow";}
- }
- @Rule(
- desc = "limits growth limit of newly naturally generated kelp to this amount of blocks",
- options = {"0", "2", "25"},
- category = FEATURE,
strict = false,
- validate = KelpLimit.class
+ options = {"0", "11"},
+ validate = ChangeSpawnChunksValidator.class
)
- public static int kelpGenerationGrowthLimit = 25;*/
+ public static int spawnChunksSize = 11;
@Rule(desc = "Coral structures will grow with bonemeal from coral plants", category = FEATURE)
public static boolean renewableCoral = false;
@@ -576,13 +557,6 @@ public class CarpetSettings
@Rule(desc = "Spawning requires much less CPU and Memory", category = OPTIMIZATION)
public static boolean lagFreeSpawning = false;
-
- //@Rule(
- // desc = "Prevents horses and other mobs to wander into the distance after dismounting",
- // extra = "Fixes issues with various Joergens wandering off and disappearing client-side",
- // category = BUGFIX
- //)
- //public static boolean horseWanderingFix = false;
@Rule(
desc = "Allows structure mobs to spawn in flat worlds",
diff --git a/src/main/java/carpet/commands/PlayerCommand.java b/src/main/java/carpet/commands/PlayerCommand.java
index 0ceba52d..e6d99c12 100644
--- a/src/main/java/carpet/commands/PlayerCommand.java
+++ b/src/main/java/carpet/commands/PlayerCommand.java
@@ -296,6 +296,14 @@ public class PlayerCommand
Messenger.m(context.getSource(), "r Cannot shadow fake players");
return 0;
}
+ ServerPlayerEntity sendingPlayer = null;
+ try
+ {
+ sendingPlayer = context.getSource().getPlayer();
+ }
+ catch (CommandSyntaxException ignored) { }
+
+ if (sendingPlayer!=player && cantManipulate(context)) return 0;
EntityPlayerMPFake.createShadow(player.server, player);
return 1;
}
diff --git a/src/main/java/carpet/fakes/ChunkTicketManagerInterface.java b/src/main/java/carpet/fakes/ChunkTicketManagerInterface.java
new file mode 100644
index 00000000..37c4ec65
--- /dev/null
+++ b/src/main/java/carpet/fakes/ChunkTicketManagerInterface.java
@@ -0,0 +1,12 @@
+package carpet.fakes;
+
+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
+import net.minecraft.server.world.ChunkTicket;
+import net.minecraft.util.SortedArraySet;
+import net.minecraft.util.math.ChunkPos;
+
+public interface ChunkTicketManagerInterface
+{
+ void changeSpawnChunks(ChunkPos pos, int distance);
+ Long2ObjectOpenHashMap>> getTicketsByPosition();
+}
diff --git a/src/main/java/carpet/fakes/ServerChunkManagerInterface.java b/src/main/java/carpet/fakes/ServerChunkManagerInterface.java
new file mode 100644
index 00000000..9f7daddc
--- /dev/null
+++ b/src/main/java/carpet/fakes/ServerChunkManagerInterface.java
@@ -0,0 +1,8 @@
+package carpet.fakes;
+
+import net.minecraft.server.world.ChunkTicketManager;
+
+public interface ServerChunkManagerInterface
+{
+ ChunkTicketManager getTicketManager();
+}
diff --git a/src/main/java/carpet/mixins/ChunkTicketManager_scarpetMixin.java b/src/main/java/carpet/mixins/ChunkTicketManager_scarpetMixin.java
index 5098b748..e22b9bda 100644
--- a/src/main/java/carpet/mixins/ChunkTicketManager_scarpetMixin.java
+++ b/src/main/java/carpet/mixins/ChunkTicketManager_scarpetMixin.java
@@ -1,15 +1,23 @@
package carpet.mixins;
+import carpet.fakes.ChunkTicketManagerInterface;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.minecraft.server.world.ChunkTicket;
import net.minecraft.server.world.ChunkTicketManager;
import net.minecraft.util.collection.SortedArraySet;
+import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.gen.Accessor;
+import org.spongepowered.asm.mixin.Shadow;
@Mixin(ChunkTicketManager.class)
-public interface ChunkTicketManager_scarpetMixin
+public abstract class ChunkTicketManager_scarpetMixin implements ChunkTicketManagerInterface
{
- @Accessor
- Long2ObjectOpenHashMap>> getTicketsByPosition();
+ @Shadow @Final private Long2ObjectOpenHashMap>> ticketsByPosition;
+
+ @Override
+ public Long2ObjectOpenHashMap>> getTicketsByPosition()
+ {
+ return ticketsByPosition;
+ }
+
}
diff --git a/src/main/java/carpet/mixins/ChunkTicketManager_spawnChunksMixin.java b/src/main/java/carpet/mixins/ChunkTicketManager_spawnChunksMixin.java
new file mode 100644
index 00000000..53987e95
--- /dev/null
+++ b/src/main/java/carpet/mixins/ChunkTicketManager_spawnChunksMixin.java
@@ -0,0 +1,60 @@
+package carpet.mixins;
+
+import carpet.fakes.ChunkTicketManagerInterface;
+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
+import net.minecraft.server.world.ChunkTicket;
+import net.minecraft.server.world.ChunkTicketManager;
+import net.minecraft.server.world.ChunkTicketType;
+import net.minecraft.util.SortedArraySet;
+import net.minecraft.util.Unit;
+import net.minecraft.util.math.ChunkPos;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+
+import java.util.Iterator;
+
+@Mixin(ChunkTicketManager.class)
+public abstract class ChunkTicketManager_spawnChunksMixin implements ChunkTicketManagerInterface
+{
+
+ @Shadow protected abstract SortedArraySet> getTicketSet(long position);
+
+ @Shadow @Final private Long2ObjectOpenHashMap>> ticketsByPosition;
+
+ @Shadow public abstract void removeTicket(ChunkTicketType type, ChunkPos pos, int radius, T argument);
+
+ @Shadow protected abstract void removeTicket(long pos, ChunkTicket> ticket);
+
+ @Shadow public abstract void addTicket(ChunkTicketType type, ChunkPos pos, int radius, T argument);
+
+ @Override
+ public void changeSpawnChunks(ChunkPos chunkPos, int distance)
+ {
+ long pos = chunkPos.toLong();
+ SortedArraySet> set = ticketsByPosition.get(pos);
+ ChunkTicket existingTicket = null;
+ if (set != null)
+ {
+ Iterator> iter = set.iterator();
+ while(iter.hasNext())
+ {
+ ChunkTicket ticket = iter.next();
+ if (ticket.getType() == ChunkTicketType.START)
+ {
+ existingTicket = ticket;
+ iter.remove();
+ }
+ }
+ set.add(existingTicket);
+ }
+ // the reason we are removing the ticket this way is that there are sideeffects of removal
+ if (existingTicket != null)
+ {
+ removeTicket(pos, existingTicket);
+ }
+ // set optionally new spawn ticket
+ if (distance > 0)
+ addTicket(ChunkTicketType.START, chunkPos, distance, Unit.INSTANCE);
+ }
+}
diff --git a/src/main/java/carpet/mixins/DamageTracker_scarpetEventMixin.java b/src/main/java/carpet/mixins/DamageTracker_scarpetEventMixin.java
index 6f6a7d62..3ac352d9 100644
--- a/src/main/java/carpet/mixins/DamageTracker_scarpetEventMixin.java
+++ b/src/main/java/carpet/mixins/DamageTracker_scarpetEventMixin.java
@@ -5,6 +5,7 @@ import carpet.script.EntityEventsGroup;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.damage.DamageTracker;
+import net.minecraft.server.network.ServerPlayerEntity;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -12,8 +13,11 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import static carpet.script.CarpetEventServer.Event.PLAYER_DEALS_DAMAGE;
+import static carpet.script.CarpetEventServer.Event.PLAYER_TAKES_DAMAGE;
+
@Mixin(DamageTracker.class)
-public class DamageTracker_scarpetEventMixin
+public abstract class DamageTracker_scarpetEventMixin
{
@Shadow @Final private LivingEntity entity;
@@ -21,5 +25,13 @@ public class DamageTracker_scarpetEventMixin
private void onDamageTaken(DamageSource damageSource_1, float float_1, float float_2, CallbackInfo ci)
{
((EntityInterface)entity).getEventContainer().onEvent(EntityEventsGroup.EntityEventType.ON_DAMAGE, entity, float_2, damageSource_1);
+ if (entity instanceof ServerPlayerEntity && PLAYER_TAKES_DAMAGE.isNeeded())
+ {
+ PLAYER_TAKES_DAMAGE.onDamage(entity, float_2, damageSource_1);
+ }
+ if (damageSource_1.getAttacker() instanceof ServerPlayerEntity && PLAYER_DEALS_DAMAGE.isNeeded())
+ {
+ PLAYER_DEALS_DAMAGE.onDamage(entity, float_2, damageSource_1);
+ }
}
}
diff --git a/src/main/java/carpet/mixins/MinecraftServer_coreMixin.java b/src/main/java/carpet/mixins/MinecraftServer_coreMixin.java
index 2850392c..3db6e3e7 100644
--- a/src/main/java/carpet/mixins/MinecraftServer_coreMixin.java
+++ b/src/main/java/carpet/mixins/MinecraftServer_coreMixin.java
@@ -1,7 +1,10 @@
package carpet.mixins;
import carpet.CarpetServer;
+import carpet.CarpetSettings;
+import com.google.gson.JsonElement;
import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.WorldGenerationProgressListener;
import net.minecraft.world.level.LevelGeneratorOptions;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@@ -40,4 +43,11 @@ public abstract class MinecraftServer_coreMixin
{
CarpetServer.onServerClosed((MinecraftServer) (Object) this);
}
+
+ @Inject(method = "prepareStartRegion", at = @At("RETURN"))
+ private void afterSpawnCreated(WorldGenerationProgressListener worldGenerationProgressListener, CallbackInfo ci)
+ {
+ if (CarpetSettings.spawnChunksSize != 11)
+ CarpetSettings.ChangeSpawnChunksValidator.changeSpawnSize(CarpetSettings.spawnChunksSize);
+ }
}
diff --git a/src/main/java/carpet/mixins/PlayerManager_scarpetEventsMixin.java b/src/main/java/carpet/mixins/PlayerManager_scarpetEventsMixin.java
new file mode 100644
index 00000000..9b03218d
--- /dev/null
+++ b/src/main/java/carpet/mixins/PlayerManager_scarpetEventsMixin.java
@@ -0,0 +1,21 @@
+package carpet.mixins;
+
+import net.minecraft.server.PlayerManager;
+import net.minecraft.server.network.ServerPlayerEntity;
+import net.minecraft.world.dimension.DimensionType;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+
+import static carpet.script.CarpetEventServer.Event.PLAYER_RESPAWNS;
+
+@Mixin(PlayerManager.class)
+public class PlayerManager_scarpetEventsMixin
+{
+ @Inject(method = "respawnPlayer", at = @At("HEAD"))
+ private void onRespawn(ServerPlayerEntity player, DimensionType dimension, boolean alive, CallbackInfoReturnable cir)
+ {
+ PLAYER_RESPAWNS.onPlayerEvent(player);
+ }
+}
diff --git a/src/main/java/carpet/mixins/ServerChunkManagerMixin.java b/src/main/java/carpet/mixins/ServerChunkManagerMixin.java
index ea11667e..39865de3 100644
--- a/src/main/java/carpet/mixins/ServerChunkManagerMixin.java
+++ b/src/main/java/carpet/mixins/ServerChunkManagerMixin.java
@@ -1,8 +1,10 @@
package carpet.mixins;
+import carpet.fakes.ServerChunkManagerInterface;
import carpet.utils.SpawnReporter;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.minecraft.entity.EntityCategory;
+import net.minecraft.server.world.ChunkTicketManager;
import net.minecraft.server.world.ServerChunkManager;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
@@ -24,12 +26,20 @@ import java.util.HashMap;
import java.util.HashSet;
@Mixin(ServerChunkManager.class)
-public abstract class ServerChunkManagerMixin
+public abstract class ServerChunkManagerMixin implements ServerChunkManagerInterface
{
@Shadow @Final private ServerWorld world;
@Shadow @Final private static int CHUNKS_ELIGIBLE_FOR_SPAWNING;
+ @Shadow @Final private ChunkTicketManager ticketManager;
+
+ @Override // shared between scarpet and spawnChunks setting
+ public ChunkTicketManager getTicketManager()
+ {
+ return ticketManager;
+ }
+
@Inject(
method = "tickChunks",
locals = LocalCapture.CAPTURE_FAILHARD,
diff --git a/src/main/java/carpet/mixins/ServerChunkManager_scarpetMixin.java b/src/main/java/carpet/mixins/ServerChunkManager_scarpetMixin.java
deleted file mode 100644
index 9cec83e8..00000000
--- a/src/main/java/carpet/mixins/ServerChunkManager_scarpetMixin.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package carpet.mixins;
-
-import net.minecraft.server.world.ChunkTicketManager;
-import net.minecraft.server.world.ServerChunkManager;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.gen.Accessor;
-
-@Mixin(ServerChunkManager.class)
-public interface ServerChunkManager_scarpetMixin
-{
- @Accessor
- ChunkTicketManager getTicketManager();
-}
diff --git a/src/main/java/carpet/mixins/ServerPlayerEntity_scarpetEventMixin.java b/src/main/java/carpet/mixins/ServerPlayerEntity_scarpetEventMixin.java
index c5beb8da..17bbd74d 100644
--- a/src/main/java/carpet/mixins/ServerPlayerEntity_scarpetEventMixin.java
+++ b/src/main/java/carpet/mixins/ServerPlayerEntity_scarpetEventMixin.java
@@ -17,6 +17,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import static carpet.script.CarpetEventServer.Event.PLAYER_DIES;
import static carpet.script.CarpetEventServer.Event.PLAYER_FINISHED_USING_ITEM;
import static carpet.script.CarpetEventServer.Event.STATISTICS;
@@ -61,6 +62,10 @@ public abstract class ServerPlayerEntity_scarpetEventMixin extends PlayerEntity
private void onDeathEvent(DamageSource source, CallbackInfo ci)
{
((EntityInterface)this).getEventContainer().onEvent(EntityEventsGroup.EntityEventType.ON_DEATH, this, source.name);
+ if (PLAYER_DIES.isNeeded())
+ {
+ PLAYER_DIES.onPlayerEvent((ServerPlayerEntity) (Object)this);
+ }
}
@Redirect(method = "method_14218", at = @At(
diff --git a/src/main/java/carpet/mixins/ServerWorld_spawnChunksMixin.java b/src/main/java/carpet/mixins/ServerWorld_spawnChunksMixin.java
new file mode 100644
index 00000000..a462a6f6
--- /dev/null
+++ b/src/main/java/carpet/mixins/ServerWorld_spawnChunksMixin.java
@@ -0,0 +1,17 @@
+package carpet.mixins;
+
+import carpet.CarpetSettings;
+import net.minecraft.server.world.ServerWorld;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.Constant;
+import org.spongepowered.asm.mixin.injection.ModifyConstant;
+
+@Mixin(ServerWorld.class)
+public class ServerWorld_spawnChunksMixin
+{
+ @ModifyConstant(method = "setSpawnPos", constant = @Constant(intValue = 11), expect = 2)
+ private int pushLimit(int original)
+ {
+ return CarpetSettings.spawnChunksSize;
+ }
+}
diff --git a/src/main/java/carpet/script/CarpetEventServer.java b/src/main/java/carpet/script/CarpetEventServer.java
index e6c87413..447396c0 100644
--- a/src/main/java/carpet/script/CarpetEventServer.java
+++ b/src/main/java/carpet/script/CarpetEventServer.java
@@ -12,6 +12,7 @@ import carpet.script.value.StringValue;
import carpet.script.value.Value;
import carpet.utils.Messenger;
import net.minecraft.block.BlockState;
+import net.minecraft.entity.damage.DamageSource;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.entity.Entity;
import net.minecraft.server.network.ServerPlayerEntity;
@@ -479,6 +480,53 @@ public class CarpetEventServer
handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
}
},
+ PLAYER_TAKES_DAMAGE("player_takes_damage", 4, false)
+ {
+ @Override
+ public void onDamage(Entity target, float amount, DamageSource source)
+ {
+ handler.call( () ->
+ {
+ return Arrays.asList(
+ ((c, t) -> new EntityValue(target)),
+ ((c, t) -> new NumericValue(amount)),
+ ((c, t) ->new StringValue(source.getName())),
+ ((c, t) -> source.getAttacker()==null?Value.NULL:new EntityValue(source.getAttacker()))
+ );
+ }, target::getCommandSource);
+ }
+ },
+ PLAYER_DEALS_DAMAGE("player_deals_damage", 3, false)
+ {
+ @Override
+ public void onDamage(Entity target, float amount, DamageSource source)
+ {
+ handler.call( () ->
+ {
+ return Arrays.asList(
+ ((c, t) -> new EntityValue(source.getAttacker())),
+ ((c, t) -> new NumericValue(amount)),
+ ((c, t) -> new EntityValue(target))
+ );
+ }, () -> source.getAttacker().getCommandSource());
+ }
+ },
+ PLAYER_DIES("player_dies", 1, false)
+ {
+ @Override
+ public void onPlayerEvent(ServerPlayerEntity player)
+ {
+ handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
+ }
+ },
+ PLAYER_RESPAWNS("player_respawns", 1, false)
+ {
+ @Override
+ public void onPlayerEvent(ServerPlayerEntity player)
+ {
+ handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource);
+ }
+ },
STATISTICS("statistic", 4, false)
{
private Identifier getStatId(Stat stat)
@@ -551,6 +599,8 @@ public class CarpetEventServer
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) { }
+ public void onDamage(Entity target, float amount, DamageSource source) { }
+
public void onWorldEvent(ServerWorld world, BlockPos pos) { }
public void onWorldEventFlag(ServerWorld world, BlockPos pos, int flag) { }
}
diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java
index 34d9d41c..cb1789b1 100644
--- a/src/main/java/carpet/script/CarpetExpression.java
+++ b/src/main/java/carpet/script/CarpetExpression.java
@@ -1,14 +1,14 @@
package carpet.script;
import carpet.CarpetServer;
+import carpet.fakes.ChunkTicketManagerInterface;
import carpet.fakes.MinecraftServerInterface;
import carpet.fakes.BiomeArrayInterface;
+import carpet.fakes.ServerChunkManagerInterface;
import carpet.fakes.StatTypeInterface;
import carpet.fakes.ThreadedAnvilChunkStorageInterface;
import carpet.helpers.FeatureGenerator;
-import carpet.mixins.ChunkTicketManager_scarpetMixin;
import carpet.mixins.PointOfInterest_scarpetMixin;
-import carpet.mixins.ServerChunkManager_scarpetMixin;
import carpet.script.Fluff.TriFunction;
import carpet.script.bundled.Module;
import carpet.CarpetSettings;
@@ -707,7 +707,7 @@ public class CarpetExpression
{
ServerWorld world = ((CarpetContext) c).s.getWorld();
Long2ObjectOpenHashMap>> levelTickets = (
- (ChunkTicketManager_scarpetMixin) ((ServerChunkManager_scarpetMixin) world.getChunkManager())
+ (ChunkTicketManagerInterface) ((ServerChunkManagerInterface) world.getChunkManager())
.getTicketManager()
).getTicketsByPosition();
List res = new ArrayList<>();
diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java
index cfb3380b..f03e4855 100644
--- a/src/main/java/carpet/script/Expression.java
+++ b/src/main/java/carpet/script/Expression.java
@@ -657,9 +657,18 @@ public class Expression
throw new InternalExpressionException("Failed to resolve left hand side of the += operation");
}
Value key = ((LContainerValue) v1).getAddress();
- Value res = cvi.get(key).add(v2);
- cvi.put(key, res);
- return (cc, tt) -> res;
+ Value value = cvi.get(key);
+ if (value instanceof ListValue || value instanceof MapValue)
+ {
+ ((AbstractListValue) value).append(v2);
+ return (cc, tt) -> value;
+ }
+ else
+ {
+ Value res = value.add(v2);
+ cvi.put(key, res);
+ return (cc, tt) -> res;
+ }
}
v1.assertAssignable();
String varname = v1.getVariable();
diff --git a/src/main/java/carpet/utils/SpawnChunks.java b/src/main/java/carpet/utils/SpawnChunks.java
new file mode 100644
index 00000000..e97cb531
--- /dev/null
+++ b/src/main/java/carpet/utils/SpawnChunks.java
@@ -0,0 +1,16 @@
+package carpet.utils;
+
+import carpet.fakes.ChunkTicketManagerInterface;
+import carpet.fakes.ServerChunkManagerInterface;
+import net.minecraft.server.world.ChunkTicketManager;
+import net.minecraft.server.world.ServerChunkManager;
+import net.minecraft.util.math.ChunkPos;
+
+public class SpawnChunks
+{
+ public static void changeSpawnChunks(ServerChunkManager chunkManager, ChunkPos pos, int size)
+ {
+ ChunkTicketManager ticketManager = ((ServerChunkManagerInterface)chunkManager).getTicketManager();
+ ((ChunkTicketManagerInterface)ticketManager).changeSpawnChunks(pos, size);
+ }
+}
diff --git a/src/main/resources/assets/carpet/scripts/event_test.sc b/src/main/resources/assets/carpet/scripts/event_test.sc
index 80e2346e..8e3d937a 100644
--- a/src/main/resources/assets/carpet/scripts/event_test.sc
+++ b/src/main/resources/assets/carpet/scripts/event_test.sc
@@ -185,3 +185,38 @@ __on_player_places_block(player, item_tuple, hand, block) ->
print(' > count: '+count);
print(' > nbt: '+nbt);
);
+
+__on_player_takes_damage(player, amount, source, entity) ->
+(
+ print('');
+ print('__on_player_takes_damage(player, amount, source, source_entity)');
+ print('player takes damage:');
+ print(' - player: '+player);
+ print(' - amount: '+str('%.2f',amount));
+ print(' - source: '+source);
+ print(' - source_entity: '+entity);
+);
+
+__on_player_deals_damage(player, amount, entity) ->
+(
+ print('');
+ print('__on_player_deals_damage(player, amount, target)');
+ print('player deals damage:');
+ print(' - player: '+player);
+ print(' - amount: '+str('%.2f',amount));
+ print(' - target: '+entity);
+);
+
+__on_player_dies(player) ->
+(
+ print('');
+ print('__on_player_dies(player)');
+ print('Player '+player+' dies.')
+);
+
+__on_player_respawns(player) ->
+(
+ print('');
+ print('__on_player_respawns(player)');
+ print('Player '+player+' respawns.')
+);
diff --git a/src/main/resources/carpet.mixins.json b/src/main/resources/carpet.mixins.json
index 75f1a574..a11c3601 100644
--- a/src/main/resources/carpet.mixins.json
+++ b/src/main/resources/carpet.mixins.json
@@ -29,6 +29,9 @@
"ThreadedAnvilChunkStorage_scarpetChunkCreationMixin",
"ChunkHolder_scarpetChunkCreationMixin",
+ "ChunkTicketManager_spawnChunksMixin",
+ "ServerWorld_spawnChunksMixin",
+
"MobEntityMixin",
"ServerWorld_unloadedEntityMixin",
"EntityTrackerEntry_leashFixMixin",
@@ -141,9 +144,9 @@
"ServerPlayerEntity_scarpetEventMixin",
"FallingBlockEntity_scarpetEventsMixin",
"BlockItem_scarpetEventMixin",
+ "PlayerManager_scarpetEventsMixin",
"ChunkTicketManager_scarpetMixin",
- "ServerChunkManager_scarpetMixin",
"StatType_scarpetMixin",
"PointOfInterest_scarpetMixin",
"ServerWorld_scarpetEventMixin",