Merge branch 'master' into 1.17
# Conflicts: # src/main/java/carpet/mixins/ServerWorld_scarpetMixin.java # src/main/java/carpet/script/CarpetEventServer.java
This commit is contained in:
commit
2127c3ac8e
3 files changed
+53
-11
No files matched your search
@@ -816,7 +816,10 @@ In case you want to pass an event handler that is not defined in your module, pl
|
||||
### `entity_load_handler(descriptor / descriptors, function)`, `entity_load_handler(descriptor / descriptors, call_name, ... args?)`
|
||||
|
||||
Attaches a callback to when any entity matching the following type / types is loaded in the game, allowing to grab a handle
|
||||
to an entity right when it is loaded to the world without querying them every tick. Callback expects one parameter - the entity.
|
||||
to an entity right when it is loaded to the world without querying them every tick. Callback expects two parameters - the entity,
|
||||
and a boolean indicating if the entity was newly created(`true`) or just loaded from disk. Single argument functions accepting
|
||||
only entities are allowed, but deprecated and will be removed at some point.
|
||||
|
||||
If callback is `null`, then the current entity handler, if present, is removed. Consecutive calls to `entity_load_handler` will add / subtract
|
||||
of the currently targeted entity types pool.
|
||||
|
||||
@@ -826,10 +829,10 @@ that it is not clear which player to use run the load call.
|
||||
```
|
||||
// veryfast method of getting rid of all the zombies. Callback is so early, its packets haven't reached yet the clients
|
||||
// so to save on log errors, removal of mobs needs to be scheduled for later.
|
||||
entity_load_handler('zombie', _(e) -> schedule(0, _(outer(e)) -> modify(e, 'remove')))
|
||||
entity_load_handler('zombie', _(e, new) -> schedule(0, _(outer(e)) -> modify(e, 'remove')))
|
||||
|
||||
// making all zombies immediately faster and less susceptible to friction of any sort
|
||||
entity_load_handler('zombie', _(e) -> entity_event(e, 'on_tick', _(e) -> modify(e, 'motion', 1.2*e~'motion')))
|
||||
entity_load_handler('zombie', _(e, new) -> entity_event(e, 'on_tick', _(e) -> modify(e, 'motion', 1.2*e~'motion')))
|
||||
```
|
||||
|
||||
Word of caution: entities can be loaded with chunks in various states, for instance when a chunk is being generated, this means
|
||||
@@ -837,25 +840,30 @@ that accessing world blocks would cause the game to freeze due to force generati
|
||||
sure to never assume the chunk is ready and use `entity_load_handler` to schedule actions around the loaded entity,
|
||||
or manipulate entity directly.
|
||||
|
||||
Also, it is possible that mobs that spawn with world generation, while being 'added' have their metadata serialized and cached
|
||||
internally (vanilla limitation), so some modifications to these entities may have no effect on them. This affects mobs created with
|
||||
world generation.
|
||||
|
||||
For instance the following handler is safe, as it only accesses the entity directly. It makes all spawned pigmen jump
|
||||
```
|
||||
/script run entity_load_handler('zombified_piglin', _(e) -> modify(e, 'motion', 0, 1, 0) )
|
||||
/script run entity_load_handler('zombified_piglin', _(e, new) -> if(new, modify(e, 'motion', 0, 1, 0)) )
|
||||
```
|
||||
But the following handler, attempting to despawn pigmen that spawn in portals, will cause the game to freeze due to cascading access to blocks that would cause neighbouring chunks
|
||||
to force generate, causing also error messages for all pigmen caused by packets send after entity is removed by script.
|
||||
```
|
||||
/script run entity_load_handler('zombified_piglin', _(e) -> if(block(pos(e))=='nether_portal', modify(e, 'remove') ) )
|
||||
/script run entity_load_handler('zombified_piglin', _(e, new) -> if(new && block(pos(e))=='nether_portal', modify(e, 'remove') ) )
|
||||
```
|
||||
Easiest method to circumvent these issues is delay the check, which may or may not cause cascade load to happen, but
|
||||
will definitely break the infinite chain.
|
||||
```
|
||||
/script run entity_load_handler('zombified_piglin', _(e) -> schedule(0, _(outer(e)) -> if(block(pos(e))=='nether_portal', modify(e, 'remove') ) ) )
|
||||
/script run entity_load_handler('zombified_piglin', _(e, new) -> if(new, schedule(0, _(outer(e)) -> if(block(pos(e))=='nether_portal', modify(e, 'remove') ) ) ) )
|
||||
```
|
||||
But the best is to perform the check first time the entity will be ticked - giving the game all the time to ensure chunk
|
||||
is fully loaded and entity processing, removing the tick handler
|
||||
is fully loaded and entity processing, removing the tick handler:
|
||||
```
|
||||
/script run entity_load_handler('zombified_piglin', _(e) -> entity_event(e, 'on_tick', _(e) -> ( if(block(pos(e))=='nether_portal', modify(e, 'remove')); entity_event(e, 'on_tick', null) ) ) )
|
||||
/script run entity_load_handler('zombified_piglin', _(e, new) -> if(new, entity_event(e, 'on_tick', _(e) -> ( if(block(pos(e))=='nether_portal', modify(e, 'remove')); entity_event(e, 'on_tick', null) ) ) ) )
|
||||
```
|
||||
Looks little convoluted, but that's the safest method to ensure your app won't crash.
|
||||
|
||||
### `entity_event(e, event, function)`, `entity_event(e, event, call_name, ... args?)`
|
||||
|
||||
|
||||
@@ -928,16 +928,39 @@ public class CarpetEventServer
|
||||
}
|
||||
};
|
||||
|
||||
@Deprecated
|
||||
public static String getEntityLoadEventName(EntityType<? extends Entity> et)
|
||||
{
|
||||
return "entity_loaded_" + ValueConversions.of(Registry.ENTITY_TYPE.getId(et)).getString();
|
||||
}
|
||||
|
||||
public static final Map<EntityType<? extends Entity>, Event> ENTITY_LOAD= new HashMap<>()
|
||||
{{
|
||||
@Deprecated
|
||||
public static final Map<EntityType<? extends Entity>, Event> ENTITY_LOAD= new HashMap<EntityType<? extends Entity>, Event>() {{
|
||||
EntityType.get("zombie");
|
||||
Registry.ENTITY_TYPE.forEach(et -> {
|
||||
put(et, new Event(getEntityLoadEventName(et), 2, true, false)
|
||||
put(et, new Event(getEntityLoadEventName(et), 1, true, false)
|
||||
{
|
||||
@Override
|
||||
public void onEntityAction(Entity entity, boolean created)
|
||||
{
|
||||
handler.call(
|
||||
() -> Collections.singletonList(new EntityValue(entity)),
|
||||
() -> CarpetServer.minecraft_server.getCommandSource().withWorld((ServerWorld) entity.world).withLevel(CarpetSettings.runPermissionLevel)
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
}};
|
||||
|
||||
public static String getEntityHandlerEventName(EntityType<? extends Entity> et)
|
||||
{
|
||||
return "entity_handler_" + ValueConversions.of(Registry.ENTITY_TYPE.getId(et)).getString();
|
||||
}
|
||||
|
||||
public static final Map<EntityType<? extends Entity>, Event> ENTITY_HANDLER= new HashMap<EntityType<? extends Entity>, Event>() {{
|
||||
EntityType.get("zombie");
|
||||
Registry.ENTITY_TYPE.forEach(et -> {
|
||||
put(et, new Event(getEntityHandlerEventName(et), 2, true, false)
|
||||
{
|
||||
@Override
|
||||
public void onEntityAction(Entity entity, boolean created)
|
||||
|
||||
@@ -275,11 +275,22 @@ public class Entities {
|
||||
if (funArg.function == null)
|
||||
{
|
||||
types.forEach(et -> events.removeBuiltInEvent(CarpetEventServer.Event.getEntityLoadEventName(et), (CarpetScriptHost) c.host));
|
||||
types.forEach(et -> events.removeBuiltInEvent(CarpetEventServer.Event.getEntityHandlerEventName(et), (CarpetScriptHost) c.host));
|
||||
}
|
||||
else
|
||||
{
|
||||
///compat
|
||||
int argno = funArg.function.getArguments().size() - funArg.args.size();
|
||||
if (argno == 1)
|
||||
{
|
||||
c.host.issueDeprecation("entity_load_handler() with single argument callback");
|
||||
types.forEach(et -> events.addBuiltInEvent(CarpetEventServer.Event.getEntityLoadEventName(et), c.host, funArg.function, funArg.args));
|
||||
}
|
||||
else
|
||||
{
|
||||
types.forEach(et -> events.addBuiltInEvent(CarpetEventServer.Event.getEntityHandlerEventName(et), c.host, funArg.function, funArg.args));
|
||||
}
|
||||
}
|
||||
return new NumericValue(types.size());
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user