hytale-server/com/hypixel/hytale/server/npc/NPCPlugin.java

1651 lines
92 KiB
Java

package com.hypixel.hytale.server.npc;
import com.hypixel.hytale.assetstore.AssetMap;
import com.hypixel.hytale.assetstore.AssetPack;
import com.hypixel.hytale.assetstore.AssetRegistry;
import com.hypixel.hytale.assetstore.event.LoadedAssetsEvent;
import com.hypixel.hytale.assetstore.event.RemovedAssetsEvent;
import com.hypixel.hytale.assetstore.map.DefaultAssetMap;
import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap;
import com.hypixel.hytale.builtin.path.path.TransientPathDefinition;
import com.hypixel.hytale.builtin.path.waypoint.RelativeWaypointDefinition;
import com.hypixel.hytale.builtin.tagset.TagSetPlugin;
import com.hypixel.hytale.builtin.tagset.config.NPCGroup;
import com.hypixel.hytale.codec.Codec;
import com.hypixel.hytale.codec.KeyedCodec;
import com.hypixel.hytale.codec.builder.BuilderCodec;
import com.hypixel.hytale.codec.schema.config.Schema;
import com.hypixel.hytale.common.benchmark.TimeDistributionRecorder;
import com.hypixel.hytale.common.util.FormatUtil;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.component.ComponentRegistryProxy;
import com.hypixel.hytale.component.ComponentType;
import com.hypixel.hytale.component.Holder;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.RemoveReason;
import com.hypixel.hytale.component.ResourceType;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.component.dependency.Dependency;
import com.hypixel.hytale.component.dependency.Order;
import com.hypixel.hytale.component.dependency.SystemDependency;
import com.hypixel.hytale.component.spatial.KDTree;
import com.hypixel.hytale.component.spatial.SpatialResource;
import com.hypixel.hytale.event.EventRegistry;
import com.hypixel.hytale.function.consumer.TriConsumer;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.logger.sentry.SkipSentryException;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.math.vector.Vector3f;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.Options;
import com.hypixel.hytale.server.core.asset.AssetModule;
import com.hypixel.hytale.server.core.asset.AssetPackRegisterEvent;
import com.hypixel.hytale.server.core.asset.AssetPackUnregisterEvent;
import com.hypixel.hytale.server.core.asset.GenerateSchemaEvent;
import com.hypixel.hytale.server.core.asset.HytaleAssetStore;
import com.hypixel.hytale.server.core.asset.LoadAssetEvent;
import com.hypixel.hytale.server.core.asset.type.item.config.Item;
import com.hypixel.hytale.server.core.asset.type.model.config.Model;
import com.hypixel.hytale.server.core.asset.type.model.config.ModelAsset;
import com.hypixel.hytale.server.core.asset.type.responsecurve.config.ResponseCurve;
import com.hypixel.hytale.server.core.entity.UUIDComponent;
import com.hypixel.hytale.server.core.modules.entity.EntityModule;
import com.hypixel.hytale.server.core.modules.entity.component.DisplayNameComponent;
import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation;
import com.hypixel.hytale.server.core.modules.entity.component.ModelComponent;
import com.hypixel.hytale.server.core.modules.entity.component.PersistentModel;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import com.hypixel.hytale.server.core.modules.entitystats.EntityStatMap;
import com.hypixel.hytale.server.core.modules.entitystats.EntityStatsSystems;
import com.hypixel.hytale.server.core.modules.entitystats.asset.EntityStatType;
import com.hypixel.hytale.server.core.modules.interaction.interaction.config.Interaction;
import com.hypixel.hytale.server.core.modules.interaction.interaction.config.RootInteraction;
import com.hypixel.hytale.server.core.modules.migrations.MigrationModule;
import com.hypixel.hytale.server.core.modules.time.WorldTimeResource;
import com.hypixel.hytale.server.core.plugin.JavaPlugin;
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
import com.hypixel.hytale.server.core.universe.Universe;
import com.hypixel.hytale.server.core.universe.world.npc.INonPlayerCharacter;
import com.hypixel.hytale.server.core.universe.world.path.WorldPathChangedEvent;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.server.core.util.Config;
import com.hypixel.hytale.server.flock.FlockPlugin;
import com.hypixel.hytale.server.flock.config.FlockAsset;
import com.hypixel.hytale.server.migrations.RenameSpawnMarkerMigration;
import com.hypixel.hytale.server.npc.asset.builder.Builder;
import com.hypixel.hytale.server.npc.asset.builder.BuilderDescriptor;
import com.hypixel.hytale.server.npc.asset.builder.BuilderFactory;
import com.hypixel.hytale.server.npc.asset.builder.BuilderInfo;
import com.hypixel.hytale.server.npc.asset.builder.BuilderManager;
import com.hypixel.hytale.server.npc.asset.builder.BuilderSupport;
import com.hypixel.hytale.server.npc.blackboard.Blackboard;
import com.hypixel.hytale.server.npc.blackboard.view.attitude.AttitudeMap;
import com.hypixel.hytale.server.npc.blackboard.view.attitude.ItemAttitudeMap;
import com.hypixel.hytale.server.npc.blackboard.view.combat.CombatViewSystems;
import com.hypixel.hytale.server.npc.commands.NPCCommand;
import com.hypixel.hytale.server.npc.commands.NPCRunTestsCommand;
import com.hypixel.hytale.server.npc.components.FailedSpawnComponent;
import com.hypixel.hytale.server.npc.components.SortBufferProviderResource;
import com.hypixel.hytale.server.npc.components.StepComponent;
import com.hypixel.hytale.server.npc.components.Timers;
import com.hypixel.hytale.server.npc.components.messaging.BeaconSupport;
import com.hypixel.hytale.server.npc.components.messaging.NPCBlockEventSupport;
import com.hypixel.hytale.server.npc.components.messaging.NPCEntityEventSupport;
import com.hypixel.hytale.server.npc.components.messaging.PlayerBlockEventSupport;
import com.hypixel.hytale.server.npc.components.messaging.PlayerEntityEventSupport;
import com.hypixel.hytale.server.npc.config.AttitudeGroup;
import com.hypixel.hytale.server.npc.config.ItemAttitudeGroup;
import com.hypixel.hytale.server.npc.config.balancing.BalanceAsset;
import com.hypixel.hytale.server.npc.corecomponents.IEntityFilter;
import com.hypixel.hytale.server.npc.corecomponents.ISensorEntityCollector;
import com.hypixel.hytale.server.npc.corecomponents.ISensorEntityPrioritiser;
import com.hypixel.hytale.server.npc.corecomponents.WeightedAction;
import com.hypixel.hytale.server.npc.corecomponents.audiovisual.builders.BuilderActionAppearance;
import com.hypixel.hytale.server.npc.corecomponents.audiovisual.builders.BuilderActionDisplayName;
import com.hypixel.hytale.server.npc.corecomponents.audiovisual.builders.BuilderActionModelAttachment;
import com.hypixel.hytale.server.npc.corecomponents.audiovisual.builders.BuilderActionPlayAnimation;
import com.hypixel.hytale.server.npc.corecomponents.audiovisual.builders.BuilderActionPlaySound;
import com.hypixel.hytale.server.npc.corecomponents.audiovisual.builders.BuilderActionSpawnParticles;
import com.hypixel.hytale.server.npc.corecomponents.audiovisual.builders.BuilderSensorAnimation;
import com.hypixel.hytale.server.npc.corecomponents.builders.BuilderWeightedAction;
import com.hypixel.hytale.server.npc.corecomponents.combat.builders.BuilderActionApplyEntityEffect;
import com.hypixel.hytale.server.npc.corecomponents.combat.builders.BuilderActionAttack;
import com.hypixel.hytale.server.npc.corecomponents.combat.builders.BuilderBodyMotionAimCharge;
import com.hypixel.hytale.server.npc.corecomponents.combat.builders.BuilderHeadMotionAim;
import com.hypixel.hytale.server.npc.corecomponents.combat.builders.BuilderSensorDamage;
import com.hypixel.hytale.server.npc.corecomponents.combat.builders.BuilderSensorIsBackingAway;
import com.hypixel.hytale.server.npc.corecomponents.debug.builders.BuilderActionLog;
import com.hypixel.hytale.server.npc.corecomponents.debug.builders.BuilderActionTest;
import com.hypixel.hytale.server.npc.corecomponents.debug.builders.BuilderBodyMotionTestProbe;
import com.hypixel.hytale.server.npc.corecomponents.entity.builders.BuilderActionBeacon;
import com.hypixel.hytale.server.npc.corecomponents.entity.builders.BuilderActionIgnoreForAvoidance;
import com.hypixel.hytale.server.npc.corecomponents.entity.builders.BuilderActionNotify;
import com.hypixel.hytale.server.npc.corecomponents.entity.builders.BuilderActionOverrideAttitude;
import com.hypixel.hytale.server.npc.corecomponents.entity.builders.BuilderActionReleaseTarget;
import com.hypixel.hytale.server.npc.corecomponents.entity.builders.BuilderActionSetMarkedTarget;
import com.hypixel.hytale.server.npc.corecomponents.entity.builders.BuilderActionSetStat;
import com.hypixel.hytale.server.npc.corecomponents.entity.builders.BuilderHeadMotionWatch;
import com.hypixel.hytale.server.npc.corecomponents.entity.builders.BuilderSensorBeacon;
import com.hypixel.hytale.server.npc.corecomponents.entity.builders.BuilderSensorCount;
import com.hypixel.hytale.server.npc.corecomponents.entity.builders.BuilderSensorEntity;
import com.hypixel.hytale.server.npc.corecomponents.entity.builders.BuilderSensorKill;
import com.hypixel.hytale.server.npc.corecomponents.entity.builders.BuilderSensorPlayer;
import com.hypixel.hytale.server.npc.corecomponents.entity.builders.BuilderSensorSelf;
import com.hypixel.hytale.server.npc.corecomponents.entity.builders.BuilderSensorTarget;
import com.hypixel.hytale.server.npc.corecomponents.entity.filters.builders.BuilderEntityFilterAltitude;
import com.hypixel.hytale.server.npc.corecomponents.entity.filters.builders.BuilderEntityFilterAnd;
import com.hypixel.hytale.server.npc.corecomponents.entity.filters.builders.BuilderEntityFilterAttitude;
import com.hypixel.hytale.server.npc.corecomponents.entity.filters.builders.BuilderEntityFilterCombat;
import com.hypixel.hytale.server.npc.corecomponents.entity.filters.builders.BuilderEntityFilterHeightDifference;
import com.hypixel.hytale.server.npc.corecomponents.entity.filters.builders.BuilderEntityFilterInsideBlock;
import com.hypixel.hytale.server.npc.corecomponents.entity.filters.builders.BuilderEntityFilterInventory;
import com.hypixel.hytale.server.npc.corecomponents.entity.filters.builders.BuilderEntityFilterItemInHand;
import com.hypixel.hytale.server.npc.corecomponents.entity.filters.builders.BuilderEntityFilterLineOfSight;
import com.hypixel.hytale.server.npc.corecomponents.entity.filters.builders.BuilderEntityFilterMovementState;
import com.hypixel.hytale.server.npc.corecomponents.entity.filters.builders.BuilderEntityFilterNPCGroup;
import com.hypixel.hytale.server.npc.corecomponents.entity.filters.builders.BuilderEntityFilterNot;
import com.hypixel.hytale.server.npc.corecomponents.entity.filters.builders.BuilderEntityFilterOr;
import com.hypixel.hytale.server.npc.corecomponents.entity.filters.builders.BuilderEntityFilterSpotsMe;
import com.hypixel.hytale.server.npc.corecomponents.entity.filters.builders.BuilderEntityFilterStandingOnBlock;
import com.hypixel.hytale.server.npc.corecomponents.entity.filters.builders.BuilderEntityFilterStat;
import com.hypixel.hytale.server.npc.corecomponents.entity.filters.builders.BuilderEntityFilterViewSector;
import com.hypixel.hytale.server.npc.corecomponents.entity.prioritisers.builders.BuilderSensorEntityPrioritiserAttitude;
import com.hypixel.hytale.server.npc.corecomponents.interaction.builders.BuilderActionLockOnInteractionTarget;
import com.hypixel.hytale.server.npc.corecomponents.interaction.builders.BuilderActionSetInteractable;
import com.hypixel.hytale.server.npc.corecomponents.interaction.builders.BuilderSensorCanInteract;
import com.hypixel.hytale.server.npc.corecomponents.interaction.builders.BuilderSensorHasInteracted;
import com.hypixel.hytale.server.npc.corecomponents.interaction.builders.BuilderSensorInteractionContext;
import com.hypixel.hytale.server.npc.corecomponents.items.builders.BuilderActionDropItem;
import com.hypixel.hytale.server.npc.corecomponents.items.builders.BuilderActionInventory;
import com.hypixel.hytale.server.npc.corecomponents.items.builders.BuilderActionPickUpItem;
import com.hypixel.hytale.server.npc.corecomponents.items.builders.BuilderSensorDroppedItem;
import com.hypixel.hytale.server.npc.corecomponents.lifecycle.builders.BuilderActionDelayDespawn;
import com.hypixel.hytale.server.npc.corecomponents.lifecycle.builders.BuilderActionDespawn;
import com.hypixel.hytale.server.npc.corecomponents.lifecycle.builders.BuilderActionDie;
import com.hypixel.hytale.server.npc.corecomponents.lifecycle.builders.BuilderActionRemove;
import com.hypixel.hytale.server.npc.corecomponents.lifecycle.builders.BuilderActionRole;
import com.hypixel.hytale.server.npc.corecomponents.lifecycle.builders.BuilderActionSpawn;
import com.hypixel.hytale.server.npc.corecomponents.lifecycle.builders.BuilderSensorAge;
import com.hypixel.hytale.server.npc.corecomponents.movement.builders.BuilderActionCrouch;
import com.hypixel.hytale.server.npc.corecomponents.movement.builders.BuilderActionOverrideAltitude;
import com.hypixel.hytale.server.npc.corecomponents.movement.builders.BuilderActionRecomputePath;
import com.hypixel.hytale.server.npc.corecomponents.movement.builders.BuilderBodyMotionFind;
import com.hypixel.hytale.server.npc.corecomponents.movement.builders.BuilderBodyMotionLand;
import com.hypixel.hytale.server.npc.corecomponents.movement.builders.BuilderBodyMotionLeave;
import com.hypixel.hytale.server.npc.corecomponents.movement.builders.BuilderBodyMotionMaintainDistance;
import com.hypixel.hytale.server.npc.corecomponents.movement.builders.BuilderBodyMotionMatchLook;
import com.hypixel.hytale.server.npc.corecomponents.movement.builders.BuilderBodyMotionMoveAway;
import com.hypixel.hytale.server.npc.corecomponents.movement.builders.BuilderBodyMotionTakeOff;
import com.hypixel.hytale.server.npc.corecomponents.movement.builders.BuilderBodyMotionTeleport;
import com.hypixel.hytale.server.npc.corecomponents.movement.builders.BuilderBodyMotionWander;
import com.hypixel.hytale.server.npc.corecomponents.movement.builders.BuilderBodyMotionWanderInCircle;
import com.hypixel.hytale.server.npc.corecomponents.movement.builders.BuilderBodyMotionWanderInRect;
import com.hypixel.hytale.server.npc.corecomponents.movement.builders.BuilderSensorInAir;
import com.hypixel.hytale.server.npc.corecomponents.movement.builders.BuilderSensorMotionController;
import com.hypixel.hytale.server.npc.corecomponents.movement.builders.BuilderSensorNav;
import com.hypixel.hytale.server.npc.corecomponents.movement.builders.BuilderSensorOnGround;
import com.hypixel.hytale.server.npc.corecomponents.statemachine.builders.BuilderActionParentState;
import com.hypixel.hytale.server.npc.corecomponents.statemachine.builders.BuilderActionState;
import com.hypixel.hytale.server.npc.corecomponents.statemachine.builders.BuilderActionToggleStateEvaluator;
import com.hypixel.hytale.server.npc.corecomponents.statemachine.builders.BuilderSensorIsBusy;
import com.hypixel.hytale.server.npc.corecomponents.statemachine.builders.BuilderSensorState;
import com.hypixel.hytale.server.npc.corecomponents.timer.builders.BuilderActionSetAlarm;
import com.hypixel.hytale.server.npc.corecomponents.timer.builders.BuilderActionTimerContinue;
import com.hypixel.hytale.server.npc.corecomponents.timer.builders.BuilderActionTimerModify;
import com.hypixel.hytale.server.npc.corecomponents.timer.builders.BuilderActionTimerPause;
import com.hypixel.hytale.server.npc.corecomponents.timer.builders.BuilderActionTimerRestart;
import com.hypixel.hytale.server.npc.corecomponents.timer.builders.BuilderActionTimerStart;
import com.hypixel.hytale.server.npc.corecomponents.timer.builders.BuilderActionTimerStop;
import com.hypixel.hytale.server.npc.corecomponents.timer.builders.BuilderBodyMotionTimer;
import com.hypixel.hytale.server.npc.corecomponents.timer.builders.BuilderHeadMotionTimer;
import com.hypixel.hytale.server.npc.corecomponents.timer.builders.BuilderSensorAlarm;
import com.hypixel.hytale.server.npc.corecomponents.timer.builders.BuilderSensorTimer;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderActionNothing;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderActionRandom;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderActionResetInstructions;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderActionSequence;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderActionSetFlag;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderActionTimeout;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderBodyMotionNothing;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderBodyMotionSequence;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderHeadMotionNothing;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderHeadMotionSequence;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderSensorAdjustPosition;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderSensorAnd;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderSensorAny;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderSensorEval;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderSensorFlag;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderSensorNot;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderSensorOr;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderSensorRandom;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderSensorSwitch;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderSensorValueProviderWrapper;
import com.hypixel.hytale.server.npc.corecomponents.utility.builders.BuilderValueToParameterMapping;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderActionMakePath;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderActionPlaceBlock;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderActionResetBlockSensors;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderActionResetPath;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderActionResetSearchRays;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderActionSetBlockToPlace;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderActionSetLeashPosition;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderActionStorePosition;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderActionTriggerSpawners;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderBodyMotionPath;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderHeadMotionObserve;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderSensorBlock;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderSensorBlockChange;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderSensorBlockType;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderSensorCanPlace;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderSensorEntityEvent;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderSensorInWater;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderSensorLeash;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderSensorLight;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderSensorPath;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderSensorReadPosition;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderSensorSearchRay;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderSensorTime;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderSensorWeather;
import com.hypixel.hytale.server.npc.decisionmaker.core.conditions.base.Condition;
import com.hypixel.hytale.server.npc.decisionmaker.stateevaluator.StateEvaluator;
import com.hypixel.hytale.server.npc.entities.NPCEntity;
import com.hypixel.hytale.server.npc.instructions.Action;
import com.hypixel.hytale.server.npc.instructions.ActionList;
import com.hypixel.hytale.server.npc.instructions.BodyMotion;
import com.hypixel.hytale.server.npc.instructions.HeadMotion;
import com.hypixel.hytale.server.npc.instructions.Instruction;
import com.hypixel.hytale.server.npc.instructions.Sensor;
import com.hypixel.hytale.server.npc.instructions.builders.BuilderActionList;
import com.hypixel.hytale.server.npc.instructions.builders.BuilderInstruction;
import com.hypixel.hytale.server.npc.instructions.builders.BuilderInstructionRandomized;
import com.hypixel.hytale.server.npc.instructions.builders.BuilderInstructionReference;
import com.hypixel.hytale.server.npc.interactions.ContextualUseNPCInteraction;
import com.hypixel.hytale.server.npc.interactions.SpawnNPCInteraction;
import com.hypixel.hytale.server.npc.interactions.UseNPCInteraction;
import com.hypixel.hytale.server.npc.movement.controllers.BuilderMotionControllerMapUtil;
import com.hypixel.hytale.server.npc.movement.controllers.MotionController;
import com.hypixel.hytale.server.npc.movement.controllers.builders.BuilderMotionControllerDive;
import com.hypixel.hytale.server.npc.movement.controllers.builders.BuilderMotionControllerFly;
import com.hypixel.hytale.server.npc.movement.controllers.builders.BuilderMotionControllerMap;
import com.hypixel.hytale.server.npc.movement.controllers.builders.BuilderMotionControllerWalk;
import com.hypixel.hytale.server.npc.navigation.AStarNodePoolProviderSimple;
import com.hypixel.hytale.server.npc.path.builders.BuilderRelativeWaypointDefinition;
import com.hypixel.hytale.server.npc.path.builders.BuilderTransientPathDefinition;
import com.hypixel.hytale.server.npc.role.Role;
import com.hypixel.hytale.server.npc.role.builders.BuilderRole;
import com.hypixel.hytale.server.npc.role.builders.BuilderRoleAbstract;
import com.hypixel.hytale.server.npc.role.builders.BuilderRoleVariant;
import com.hypixel.hytale.server.npc.statetransition.StateTransitionController;
import com.hypixel.hytale.server.npc.systems.AvoidanceSystem;
import com.hypixel.hytale.server.npc.systems.BalancingInitialisationSystem;
import com.hypixel.hytale.server.npc.systems.BlackboardSystems;
import com.hypixel.hytale.server.npc.systems.ComputeVelocitySystem;
import com.hypixel.hytale.server.npc.systems.FailedSpawnSystem;
import com.hypixel.hytale.server.npc.systems.MessageSupportSystem;
import com.hypixel.hytale.server.npc.systems.MovementStatesSystem;
import com.hypixel.hytale.server.npc.systems.NPCDamageSystems;
import com.hypixel.hytale.server.npc.systems.NPCDeathSystems;
import com.hypixel.hytale.server.npc.systems.NPCInteractionSystems;
import com.hypixel.hytale.server.npc.systems.NPCPreTickSystem;
import com.hypixel.hytale.server.npc.systems.NPCSpatialSystem;
import com.hypixel.hytale.server.npc.systems.NPCSystems;
import com.hypixel.hytale.server.npc.systems.NPCVelocityInstructionSystem;
import com.hypixel.hytale.server.npc.systems.NewSpawnStartTickingSystem;
import com.hypixel.hytale.server.npc.systems.PositionCacheSystems;
import com.hypixel.hytale.server.npc.systems.RoleBuilderSystem;
import com.hypixel.hytale.server.npc.systems.RoleChangeSystem;
import com.hypixel.hytale.server.npc.systems.RoleSystems;
import com.hypixel.hytale.server.npc.systems.StateEvaluatorSystem;
import com.hypixel.hytale.server.npc.systems.SteeringSystem;
import com.hypixel.hytale.server.npc.systems.StepCleanupSystem;
import com.hypixel.hytale.server.npc.systems.TimerSystem;
import com.hypixel.hytale.server.npc.util.SensorSupportBenchmark;
import com.hypixel.hytale.server.npc.util.expression.StdScope;
import com.hypixel.hytale.server.npc.valuestore.ValueStore;
import it.unimi.dsi.fastutil.Pair;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class NPCPlugin extends JavaPlugin {
@Nonnull
public static String FACTORY_CLASS_ROLE = "Role";
@Nonnull
public static String FACTORY_CLASS_BODY_MOTION = "BodyMotion";
@Nonnull
public static String FACTORY_CLASS_HEAD_MOTION = "HeadMotion";
@Nonnull
public static String FACTORY_CLASS_ACTION = "Action";
@Nonnull
public static String FACTORY_CLASS_SENSOR = "Sensor";
@Nonnull
public static String FACTORY_CLASS_INSTRUCTION = "Instruction";
@Nonnull
public static String FACTORY_CLASS_TRANSIENT_PATH = "Path";
@Nonnull
public static String FACTORY_CLASS_ACTION_LIST = "ActionList";
@Nonnull
public static String ROLE_ASSETS_PATH = "Server/NPC/Roles";
private static NPCPlugin instance;
protected List<BuilderDescriptor> builderDescriptors;
protected final BuilderManager builderManager = new BuilderManager();
protected boolean validateBuilder;
protected int maxBlackboardBlockCountPerType = 20;
protected boolean logFailingTestErrors;
protected String[] presetCoverageTestNPCs;
@Nonnull
protected AtomicInteger pathChangeRevision = new AtomicInteger(0);
@Nonnull
protected Lock benchmarkLock = new ReentrantLock();
@Nullable
protected Int2ObjectMap<TimeDistributionRecorder> roleTickDistribution;
@Nullable
protected Int2ObjectMap<SensorSupportBenchmark> roleSensorSupportDistribution;
@Nullable
protected TimeDistributionRecorder roleTickDistributionAll;
@Nullable
protected SensorSupportBenchmark roleSensorSupportDistributionAll;
protected boolean autoReload;
private AttitudeMap attitudeMap;
private ItemAttitudeMap itemAttitudeMap;
private static final Vector3f NULL_ROTATION = new Vector3f(0.0F, 0.0F, 0.0F);
public static final short PRIORITY_LOAD_NPC = -8;
public static final short PRIORITY_SPAWN_VALIDATION = -7;
private final Config<NPCPlugin.NPCConfig> config = this.withConfig("NPCModule", NPCPlugin.NPCConfig.CODEC);
private ResourceType<EntityStore, Blackboard> blackboardResourceType;
private ResourceType<EntityStore, CombatViewSystems.CombatDataPool> combatDataPoolResourceType;
private ResourceType<EntityStore, RoleChangeSystem.RoleChangeQueue> roleChangeQueueResourceType;
private ResourceType<EntityStore, NewSpawnStartTickingSystem.QueueResource> newSpawnStartTickingQueueResourceType;
private ResourceType<EntityStore, SortBufferProviderResource> sortBufferProviderResourceResourceType;
private ResourceType<EntityStore, AStarNodePoolProviderSimple> aStarNodePoolProviderSimpleResourceType;
private ResourceType<EntityStore, SpatialResource<Ref<EntityStore>, EntityStore>> npcSpatialResource;
private ComponentType<EntityStore, CombatViewSystems.CombatData> combatDataComponentType;
private ComponentType<EntityStore, NPCRunTestsCommand.NPCTestData> npcTestDataComponentType;
private ComponentType<EntityStore, BeaconSupport> beaconSupportComponentType;
private ComponentType<EntityStore, NPCBlockEventSupport> npcBlockEventSupportComponentType;
private ComponentType<EntityStore, PlayerBlockEventSupport> playerBlockEventSupportComponentType;
private ComponentType<EntityStore, NPCEntityEventSupport> npcEntityEventSupportComponentType;
private ComponentType<EntityStore, PlayerEntityEventSupport> playerEntityEventSupportComponentType;
private ComponentType<EntityStore, StepComponent> stepComponentType;
private ComponentType<EntityStore, FailedSpawnComponent> failedSpawnComponentType;
private ComponentType<EntityStore, Timers> timersComponentType;
private ComponentType<EntityStore, StateEvaluator> stateEvaluatorComponentType;
private ComponentType<EntityStore, ValueStore> valueStoreComponentType;
public static NPCPlugin get() {
return instance;
}
public NPCPlugin(@Nonnull JavaPluginInit init) {
super(init);
}
@Override
protected void setup() {
instance = this;
ComponentRegistryProxy<EntityStore> entityStoreRegistry = this.getEntityStoreRegistry();
EventRegistry eventRegistry = this.getEventRegistry();
this.getCommandRegistry().registerCommand(new NPCCommand());
eventRegistry.register(LoadedAssetsEvent.class, ModelAsset.class, this::onModelsChanged);
eventRegistry.register(LoadedAssetsEvent.class, NPCGroup.class, this::onNPCGroupsLoaded);
eventRegistry.register(RemovedAssetsEvent.class, NPCGroup.class, this::onNPCGroupsRemoved);
eventRegistry.register(LoadedAssetsEvent.class, AttitudeGroup.class, this::onAttitudeGroupsLoaded);
eventRegistry.register(RemovedAssetsEvent.class, AttitudeGroup.class, this::onAttitudeGroupsRemoved);
eventRegistry.register(LoadedAssetsEvent.class, ItemAttitudeGroup.class, this::onItemAttitudeGroupsLoaded);
eventRegistry.register(RemovedAssetsEvent.class, ItemAttitudeGroup.class, this::onItemAttitudeGroupsRemoved);
eventRegistry.register(LoadedAssetsEvent.class, BalanceAsset.class, NPCPlugin::onBalanceAssetsChanged);
eventRegistry.register(RemovedAssetsEvent.class, BalanceAsset.class, NPCPlugin::onBalanceAssetsRemoved);
eventRegistry.register(WorldPathChangedEvent.class, this::onPathChange);
eventRegistry.register(AllNPCsLoadedEvent.class, this::onNPCsLoaded);
eventRegistry.register(
(short)-8,
LoadAssetEvent.class,
event -> {
HytaleLogger.getLogger().at(Level.INFO).log("Loading NPC assets phase...");
long start = System.nanoTime();
this.builderManager.setAutoReload(this.autoReload);
boolean validateAssets = Options.getOptionSet().has(Options.VALIDATE_ASSETS);
List<AssetPack> assetPacks = AssetModule.get().getAssetPacks();
for (int i = 0; i < assetPacks.size(); i++) {
boolean includeTests = i == 0;
boolean loadSucceeded = this.builderManager.loadBuilders(assetPacks.get(i), includeTests);
if (!loadSucceeded) {
event.failed(validateAssets, "failed to validate npc's");
}
}
HytaleLogger.getLogger()
.at(Level.INFO)
.log(
"Loading NPC assets phase completed! Boot time %s, Took %s",
FormatUtil.nanosToString(System.nanoTime() - event.getBootStart()),
FormatUtil.nanosToString(System.nanoTime() - start)
);
}
);
eventRegistry.register(AssetPackRegisterEvent.class, event -> this.builderManager.loadBuilders(event.getAssetPack(), false));
eventRegistry.register(AssetPackUnregisterEvent.class, event -> this.builderManager.unloadBuilders(event.getAssetPack()));
eventRegistry.register(GenerateSchemaEvent.class, this::onSchemaGenerate);
AssetRegistry.register(
((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)HytaleAssetStore.builder(
AttitudeGroup.class, new IndexedLookupTableAssetMap<>(AttitudeGroup[]::new)
)
.setPath("NPC/Attitude/Roles"))
.setCodec(AttitudeGroup.CODEC))
.setKeyFunction(AttitudeGroup::getId))
.setReplaceOnRemove(AttitudeGroup::new))
.loadsAfter(NPCGroup.class))
.build()
);
AssetRegistry.register(
((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)HytaleAssetStore.builder(
ItemAttitudeGroup.class, new IndexedLookupTableAssetMap<>(ItemAttitudeGroup[]::new)
)
.setPath("NPC/Attitude/Items"))
.setCodec(ItemAttitudeGroup.CODEC))
.setKeyFunction(ItemAttitudeGroup::getId))
.setReplaceOnRemove(ItemAttitudeGroup::new))
.loadsAfter(Item.class))
.build()
);
AssetRegistry.register(
((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)HytaleAssetStore.builder(
BalanceAsset.class, new DefaultAssetMap()
)
.setPath("NPC/Balancing"))
.setCodec(BalanceAsset.CODEC))
.setKeyFunction(BalanceAsset::getId))
.loadsAfter(Condition.class))
.build()
);
AssetRegistry.register(
((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)HytaleAssetStore.builder(
Condition.class, new IndexedLookupTableAssetMap<>(Condition[]::new)
)
.setPath("NPC/DecisionMaking/Conditions"))
.setCodec(Condition.CODEC))
.setKeyFunction(Condition::getId))
.setReplaceOnRemove(Condition::getAlwaysTrueFor))
.loadsAfter(ResponseCurve.class, NPCGroup.class, EntityStatType.class))
.build()
);
this.getEntityRegistry().registerEntity("NPC", NPCEntity.class, NPCEntity::new, NPCEntity.CODEC);
Interaction.CODEC.register("ContextualUseNPC", ContextualUseNPCInteraction.class, ContextualUseNPCInteraction.CODEC);
Interaction.CODEC.register("UseNPC", UseNPCInteraction.class, UseNPCInteraction.CODEC);
Interaction.CODEC.register("SpawnNPC", SpawnNPCInteraction.class, SpawnNPCInteraction.CODEC);
Interaction.getAssetStore().loadAssets("Hytale:Hytale", List.of(new UseNPCInteraction("*UseNPC")));
RootInteraction.getAssetStore().loadAssets("Hytale:Hytale", List.of(UseNPCInteraction.DEFAULT_ROOT));
MigrationModule.get().register("spawnMarkers", RenameSpawnMarkerMigration::new);
this.setupNPCLoading();
this.blackboardResourceType = entityStoreRegistry.registerResource(Blackboard.class, Blackboard::new);
this.combatDataPoolResourceType = entityStoreRegistry.registerResource(CombatViewSystems.CombatDataPool.class, CombatViewSystems.CombatDataPool::new);
this.roleChangeQueueResourceType = entityStoreRegistry.registerResource(RoleChangeSystem.RoleChangeQueue.class, RoleChangeSystem.RoleChangeQueue::new);
this.newSpawnStartTickingQueueResourceType = entityStoreRegistry.registerResource(
NewSpawnStartTickingSystem.QueueResource.class, NewSpawnStartTickingSystem.QueueResource::new
);
this.sortBufferProviderResourceResourceType = entityStoreRegistry.registerResource(SortBufferProviderResource.class, SortBufferProviderResource::new);
this.aStarNodePoolProviderSimpleResourceType = entityStoreRegistry.registerResource(AStarNodePoolProviderSimple.class, AStarNodePoolProviderSimple::new);
this.npcSpatialResource = entityStoreRegistry.registerSpatialResource(() -> new KDTree<>(Ref::isValid));
this.combatDataComponentType = entityStoreRegistry.registerComponent(CombatViewSystems.CombatData.class, CombatViewSystems.CombatData::new);
this.npcTestDataComponentType = entityStoreRegistry.registerComponent(NPCRunTestsCommand.NPCTestData.class, NPCRunTestsCommand.NPCTestData::new);
this.beaconSupportComponentType = entityStoreRegistry.registerComponent(BeaconSupport.class, BeaconSupport::new);
this.npcBlockEventSupportComponentType = entityStoreRegistry.registerComponent(NPCBlockEventSupport.class, NPCBlockEventSupport::new);
this.playerBlockEventSupportComponentType = entityStoreRegistry.registerComponent(PlayerBlockEventSupport.class, PlayerBlockEventSupport::new);
this.npcEntityEventSupportComponentType = entityStoreRegistry.registerComponent(NPCEntityEventSupport.class, NPCEntityEventSupport::new);
this.playerEntityEventSupportComponentType = entityStoreRegistry.registerComponent(PlayerEntityEventSupport.class, PlayerEntityEventSupport::new);
this.stepComponentType = entityStoreRegistry.registerComponent(StepComponent.class, () -> {
throw new UnsupportedOperationException("Not implemented");
});
this.failedSpawnComponentType = entityStoreRegistry.registerComponent(FailedSpawnComponent.class, FailedSpawnComponent::new);
this.timersComponentType = entityStoreRegistry.registerComponent(Timers.class, () -> {
throw new UnsupportedOperationException("Not implemented");
});
this.stateEvaluatorComponentType = entityStoreRegistry.registerComponent(StateEvaluator.class, () -> {
throw new UnsupportedOperationException("Not implemented");
});
this.valueStoreComponentType = entityStoreRegistry.registerComponent(ValueStore.class, () -> {
throw new UnsupportedOperationException("Not implemented");
});
ComponentType<EntityStore, NPCEntity> npcComponentType = NPCEntity.getComponentType();
entityStoreRegistry.registerSystem(new BlackboardSystems.InitSystem(this.blackboardResourceType));
entityStoreRegistry.registerSystem(new BlackboardSystems.TickingSystem(this.blackboardResourceType));
entityStoreRegistry.registerSystem(new BlackboardSystems.DamageBlockEventSystem());
entityStoreRegistry.registerSystem(new BlackboardSystems.BreakBlockEventSystem());
entityStoreRegistry.registerSystem(new CombatViewSystems.Ensure(this.combatDataComponentType));
entityStoreRegistry.registerSystem(new CombatViewSystems.EntityRemoved(this.combatDataComponentType, this.combatDataPoolResourceType));
entityStoreRegistry.registerSystem(new CombatViewSystems.Ticking(this.combatDataComponentType, this.combatDataPoolResourceType));
entityStoreRegistry.registerSystem(new NPCSystems.ModelChangeSystem());
entityStoreRegistry.registerSystem(new RoleBuilderSystem());
entityStoreRegistry.registerSystem(new BalancingInitialisationSystem());
entityStoreRegistry.registerSystem(new RoleSystems.RoleActivateSystem(npcComponentType));
entityStoreRegistry.registerSystem(new PositionCacheSystems.RoleActivateSystem(npcComponentType, this.stateEvaluatorComponentType));
entityStoreRegistry.registerSystem(new NPCInteractionSystems.AddSimulationManagerSystem(npcComponentType));
entityStoreRegistry.registerSystem(new NPCInteractionSystems.TickHeldInteractionsSystem(npcComponentType));
entityStoreRegistry.registerSystem(new FailedSpawnSystem());
entityStoreRegistry.registerSystem(new NPCSystems.AddedSystem(npcComponentType));
entityStoreRegistry.registerSystem(new NPCSystems.AddedFromExternalSystem(npcComponentType));
entityStoreRegistry.registerSystem(new NPCSystems.AddedFromWorldGenSystem());
entityStoreRegistry.registerSystem(new NPCSystems.AddSpawnEntityEffectSystem(npcComponentType));
entityStoreRegistry.registerSystem(new RoleSystems.BehaviourTickSystem(npcComponentType, this.stepComponentType));
entityStoreRegistry.registerSystem(new RoleSystems.PreBehaviourSupportTickSystem(npcComponentType));
entityStoreRegistry.registerSystem(new StateEvaluatorSystem(this.stateEvaluatorComponentType, npcComponentType));
entityStoreRegistry.registerSystem(new PositionCacheSystems.UpdateSystem(npcComponentType, this.npcSpatialResource));
entityStoreRegistry.registerSystem(new NPCPreTickSystem(npcComponentType));
Set<Dependency<EntityStore>> postBehaviourDependency = Set.of(new SystemDependency<>(Order.AFTER, RoleSystems.PostBehaviourSupportTickSystem.class));
entityStoreRegistry.registerSystem(new AvoidanceSystem(npcComponentType));
entityStoreRegistry.registerSystem(new SteeringSystem(npcComponentType));
entityStoreRegistry.registerSystem(new RoleSystems.PostBehaviourSupportTickSystem(npcComponentType));
entityStoreRegistry.registerSystem(new RoleSystems.RoleDebugSystem(npcComponentType, postBehaviourDependency));
entityStoreRegistry.registerSystem(new TimerSystem(this.timersComponentType, postBehaviourDependency));
entityStoreRegistry.registerSystem(new ComputeVelocitySystem(npcComponentType, EntityModule.get().getVelocityComponentType(), postBehaviourDependency));
entityStoreRegistry.registerSystem(
new MovementStatesSystem(npcComponentType, EntityModule.get().getVelocityComponentType(), EntityModule.get().getMovementStatesComponentType())
);
entityStoreRegistry.registerSystem(new MessageSupportSystem.BeaconSystem(this.beaconSupportComponentType, postBehaviourDependency));
entityStoreRegistry.registerSystem(new MessageSupportSystem.NPCBlockEventSystem(this.npcBlockEventSupportComponentType, postBehaviourDependency));
entityStoreRegistry.registerSystem(new MessageSupportSystem.PlayerBlockEventSystem(this.playerBlockEventSupportComponentType, postBehaviourDependency));
entityStoreRegistry.registerSystem(new MessageSupportSystem.NPCEntityEventSystem(this.npcEntityEventSupportComponentType, postBehaviourDependency));
entityStoreRegistry.registerSystem(new MessageSupportSystem.PlayerEntityEventSystem(this.playerEntityEventSupportComponentType, postBehaviourDependency));
entityStoreRegistry.registerSystem(new StepCleanupSystem(this.stepComponentType));
entityStoreRegistry.registerSystem(new NewSpawnStartTickingSystem(this.newSpawnStartTickingQueueResourceType));
entityStoreRegistry.registerSystem(
new RoleChangeSystem(
this.roleChangeQueueResourceType,
this.beaconSupportComponentType,
this.playerBlockEventSupportComponentType,
this.npcBlockEventSupportComponentType,
this.playerEntityEventSupportComponentType,
this.npcEntityEventSupportComponentType,
this.timersComponentType,
this.stateEvaluatorComponentType,
this.valueStoreComponentType
)
);
entityStoreRegistry.registerSystem(new NPCSpatialSystem(this.npcSpatialResource));
entityStoreRegistry.registerSystem(new NPCDeathSystems.NPCKillsEntitySystem());
entityStoreRegistry.registerSystem(new NPCDeathSystems.EntityViewSystem());
entityStoreRegistry.registerSystem(new NPCDamageSystems.FilterDamageSystem());
entityStoreRegistry.registerSystem(new NPCDamageSystems.DamageReceivedSystem());
entityStoreRegistry.registerSystem(new NPCDamageSystems.DamageDealtSystem());
entityStoreRegistry.registerSystem(new NPCDamageSystems.DamageReceivedEventViewSystem());
entityStoreRegistry.registerSystem(new NPCDamageSystems.DropDeathItems());
entityStoreRegistry.registerSystem(new NPCSystems.OnTeleportSystem());
entityStoreRegistry.registerSystem(new NPCSystems.OnDeathSystem());
entityStoreRegistry.registerSystem(new NPCSystems.LegacyWorldGenId());
entityStoreRegistry.registerSystem(new NPCSystems.KillFeedKillerEventSystem());
entityStoreRegistry.registerSystem(new NPCSystems.KillFeedDecedentEventSystem());
entityStoreRegistry.registerSystem(new NPCSystems.PrefabPlaceEntityEventSystem());
entityStoreRegistry.registerSystem(new NPCVelocityInstructionSystem());
this.getEntityStoreRegistry().registerSystem(new NPCPlugin.NPCEntityRegenerateStatsSystem());
}
public void onSchemaGenerate(@Nonnull GenerateSchemaEvent event) {
Schema schema = this.builderManager.generateSchema(event.getContext());
event.addSchema("NPCRole.json", schema);
event.addSchemaLink("NPCRole", List.of("NPC/Roles/*.json", "NPC/Roles/**/*.json"), null);
Schema.HytaleMetadata hytale = schema.getHytale();
hytale.setPath("NPC/Roles");
hytale.setExtension(".json");
schema.setId("NPCRole.json");
schema.setTitle("NPCRole");
}
@Override
protected void start() {
NPCPlugin.NPCConfig config = this.config.get();
if (config.isGenerateDescriptors()) {
this.generateDescriptors();
if (config.isGenerateDescriptorsFile()) {
this.saveDescriptors();
}
}
}
public ResourceType<EntityStore, Blackboard> getBlackboardResourceType() {
return this.blackboardResourceType;
}
public ResourceType<EntityStore, CombatViewSystems.CombatDataPool> getCombatDataPoolResourceType() {
return this.combatDataPoolResourceType;
}
public ResourceType<EntityStore, RoleChangeSystem.RoleChangeQueue> getRoleChangeQueueResourceType() {
return this.roleChangeQueueResourceType;
}
public ResourceType<EntityStore, NewSpawnStartTickingSystem.QueueResource> getNewSpawnStartTickingQueueResourceType() {
return this.newSpawnStartTickingQueueResourceType;
}
public ResourceType<EntityStore, SortBufferProviderResource> getSortBufferProviderResourceResourceType() {
return this.sortBufferProviderResourceResourceType;
}
public ResourceType<EntityStore, AStarNodePoolProviderSimple> getAStarNodePoolProviderSimpleResourceType() {
return this.aStarNodePoolProviderSimpleResourceType;
}
public ResourceType<EntityStore, SpatialResource<Ref<EntityStore>, EntityStore>> getNpcSpatialResource() {
return this.npcSpatialResource;
}
public ComponentType<EntityStore, CombatViewSystems.CombatData> getCombatDataComponentType() {
return this.combatDataComponentType;
}
public ComponentType<EntityStore, NPCRunTestsCommand.NPCTestData> getNpcTestDataComponentType() {
return this.npcTestDataComponentType;
}
public ComponentType<EntityStore, BeaconSupport> getBeaconSupportComponentType() {
return this.beaconSupportComponentType;
}
public ComponentType<EntityStore, NPCBlockEventSupport> getNpcBlockEventSupportComponentType() {
return this.npcBlockEventSupportComponentType;
}
public ComponentType<EntityStore, PlayerBlockEventSupport> getPlayerBlockEventSupportComponentType() {
return this.playerBlockEventSupportComponentType;
}
public ComponentType<EntityStore, NPCEntityEventSupport> getNpcEntityEventSupportComponentType() {
return this.npcEntityEventSupportComponentType;
}
public ComponentType<EntityStore, PlayerEntityEventSupport> getPlayerEntityEventSupportComponentType() {
return this.playerEntityEventSupportComponentType;
}
public ComponentType<EntityStore, StepComponent> getStepComponentType() {
return this.stepComponentType;
}
public ComponentType<EntityStore, FailedSpawnComponent> getFailedSpawnComponentType() {
return this.failedSpawnComponentType;
}
public ComponentType<EntityStore, Timers> getTimersComponentType() {
return this.timersComponentType;
}
public ComponentType<EntityStore, StateEvaluator> getStateEvaluatorComponentType() {
return this.stateEvaluatorComponentType;
}
public ComponentType<EntityStore, ValueStore> getValueStoreComponentType() {
return this.valueStoreComponentType;
}
public void setupNPCLoading() {
this.builderManager.addCategory(FACTORY_CLASS_ROLE, Role.class);
this.builderManager.addCategory(FACTORY_CLASS_BODY_MOTION, BodyMotion.class);
this.builderManager.addCategory(FACTORY_CLASS_HEAD_MOTION, HeadMotion.class);
this.builderManager.addCategory(FACTORY_CLASS_ACTION, Action.class);
this.builderManager.addCategory(FACTORY_CLASS_SENSOR, Sensor.class);
this.builderManager.addCategory(FACTORY_CLASS_INSTRUCTION, Instruction.class);
this.builderManager.addCategory(FACTORY_CLASS_TRANSIENT_PATH, TransientPathDefinition.class);
this.builderManager.addCategory(FACTORY_CLASS_ACTION_LIST, ActionList.class);
this.registerCoreFactories();
this.registerCoreComponentType("Nothing", BuilderBodyMotionNothing::new)
.registerCoreComponentType("Wander", BuilderBodyMotionWander::new)
.registerCoreComponentType("WanderInCircle", BuilderBodyMotionWanderInCircle::new)
.registerCoreComponentType("WanderInRect", BuilderBodyMotionWanderInRect::new)
.registerCoreComponentType("Timer", BuilderBodyMotionTimer::new)
.registerCoreComponentType("Sequence", BuilderBodyMotionSequence::new)
.registerCoreComponentType("Flee", BuilderBodyMotionMoveAway::new)
.registerCoreComponentType("Seek", BuilderBodyMotionFind::new)
.registerCoreComponentType("Leave", BuilderBodyMotionLeave::new)
.registerCoreComponentType("Path", BuilderBodyMotionPath::new)
.registerCoreComponentType("TakeOff", BuilderBodyMotionTakeOff::new)
.registerCoreComponentType("TestProbe", BuilderBodyMotionTestProbe::new)
.registerCoreComponentType("Teleport", BuilderBodyMotionTeleport::new)
.registerCoreComponentType("Land", BuilderBodyMotionLand::new)
.registerCoreComponentType("MatchLook", BuilderBodyMotionMatchLook::new)
.registerCoreComponentType("MaintainDistance", BuilderBodyMotionMaintainDistance::new)
.registerCoreComponentType("AimCharge", BuilderBodyMotionAimCharge::new);
this.registerCoreComponentType("Aim", BuilderHeadMotionAim::new)
.registerCoreComponentType("Watch", BuilderHeadMotionWatch::new)
.registerCoreComponentType("Observe", BuilderHeadMotionObserve::new)
.registerCoreComponentType("Sequence", BuilderHeadMotionSequence::new)
.registerCoreComponentType("Timer", BuilderHeadMotionTimer::new)
.registerCoreComponentType("Nothing", BuilderHeadMotionNothing::new);
this.registerCoreComponentType("Appearance", BuilderActionAppearance::new)
.registerCoreComponentType("Timeout", BuilderActionTimeout::new)
.registerCoreComponentType("Spawn", BuilderActionSpawn::new)
.registerCoreComponentType("Nothing", BuilderActionNothing::new)
.registerCoreComponentType("Attack", BuilderActionAttack::new)
.registerCoreComponentType("State", BuilderActionState::new)
.registerCoreComponentType("ReleaseTarget", BuilderActionReleaseTarget::new)
.registerCoreComponentType("SetMarkedTarget", BuilderActionSetMarkedTarget::new)
.registerCoreComponentType("Inventory", BuilderActionInventory::new)
.registerCoreComponentType("DisplayName", BuilderActionDisplayName::new)
.registerCoreComponentType("Sequence", BuilderActionSequence::new)
.registerCoreComponentType("Random", BuilderActionRandom::new)
.registerCoreComponentType("Beacon", BuilderActionBeacon::new)
.registerCoreComponentType("SetLeashPosition", BuilderActionSetLeashPosition::new)
.registerCoreComponentType("PlaySound", BuilderActionPlaySound::new)
.registerCoreComponentType("Despawn", BuilderActionDespawn::new)
.registerCoreComponentType("PlayAnimation", BuilderActionPlayAnimation::new)
.registerCoreComponentType("DelayDespawn", BuilderActionDelayDespawn::new)
.registerCoreComponentType("SpawnParticles", BuilderActionSpawnParticles::new)
.registerCoreComponentType("Crouch", BuilderActionCrouch::new)
.registerCoreComponentType("TimerStart", BuilderActionTimerStart::new)
.registerCoreComponentType("TimerContinue", BuilderActionTimerContinue::new)
.registerCoreComponentType("TimerPause", BuilderActionTimerPause::new)
.registerCoreComponentType("TimerModify", BuilderActionTimerModify::new)
.registerCoreComponentType("TimerStop", BuilderActionTimerStop::new)
.registerCoreComponentType("TimerRestart", BuilderActionTimerRestart::new)
.registerCoreComponentType("Test", BuilderActionTest::new)
.registerCoreComponentType("Log", BuilderActionLog::new)
.registerCoreComponentType("Role", BuilderActionRole::new)
.registerCoreComponentType("SetFlag", BuilderActionSetFlag::new)
.registerCoreComponentType("DropItem", BuilderActionDropItem::new)
.registerCoreComponentType("PickUpItem", BuilderActionPickUpItem::new)
.registerCoreComponentType("ResetInstructions", BuilderActionResetInstructions::new)
.registerCoreComponentType("ParentState", BuilderActionParentState::new)
.registerCoreComponentType("Notify", BuilderActionNotify::new)
.registerCoreComponentType("TriggerSpawners", BuilderActionTriggerSpawners::new)
.registerCoreComponentType("ResetBlockSensors", BuilderActionResetBlockSensors::new)
.registerCoreComponentType("MakePath", BuilderActionMakePath::new)
.registerCoreComponentType("OverrideAttitude", BuilderActionOverrideAttitude::new)
.registerCoreComponentType("SetInteractable", BuilderActionSetInteractable::new)
.registerCoreComponentType("LockOnInteractionTarget", BuilderActionLockOnInteractionTarget::new)
.registerCoreComponentType("StorePosition", BuilderActionStorePosition::new)
.registerCoreComponentType("SetBlockToPlace", BuilderActionSetBlockToPlace::new)
.registerCoreComponentType("PlaceBlock", BuilderActionPlaceBlock::new)
.registerCoreComponentType("RecomputePath", BuilderActionRecomputePath::new)
.registerCoreComponentType("IgnoreForAvoidance", BuilderActionIgnoreForAvoidance::new)
.registerCoreComponentType("ModelAttachment", BuilderActionModelAttachment::new)
.registerCoreComponentType("SetAlarm", BuilderActionSetAlarm::new)
.registerCoreComponentType("ToggleStateEvaluator", BuilderActionToggleStateEvaluator::new)
.registerCoreComponentType("OverrideAltitude", BuilderActionOverrideAltitude::new)
.registerCoreComponentType("ResetSearchRays", BuilderActionResetSearchRays::new)
.registerCoreComponentType("Die", BuilderActionDie::new)
.registerCoreComponentType("Remove", BuilderActionRemove::new)
.registerCoreComponentType("ApplyEntityEffect", BuilderActionApplyEntityEffect::new)
.registerCoreComponentType("ResetPath", BuilderActionResetPath::new)
.registerCoreComponentType("SetStat", BuilderActionSetStat::new);
this.registerCoreComponentType("Any", BuilderSensorAny::new)
.registerCoreComponentType("And", BuilderSensorAnd::new)
.registerCoreComponentType("Or", BuilderSensorOr::new)
.registerCoreComponentType("Not", BuilderSensorNot::new)
.registerCoreComponentType("Player", BuilderSensorPlayer::new)
.registerCoreComponentType("Mob", BuilderSensorEntity::new)
.registerCoreComponentType("State", BuilderSensorState::new)
.registerCoreComponentType("InAir", BuilderSensorInAir::new)
.registerCoreComponentType("OnGround", BuilderSensorOnGround::new)
.registerCoreComponentType("Eval", BuilderSensorEval::new)
.registerCoreComponentType("Damage", BuilderSensorDamage::new)
.registerCoreComponentType("IsBackingAway", BuilderSensorIsBackingAway::new)
.registerCoreComponentType("Kill", BuilderSensorKill::new)
.registerCoreComponentType("Beacon", BuilderSensorBeacon::new)
.registerCoreComponentType("MotionController", BuilderSensorMotionController::new)
.registerCoreComponentType("Leash", BuilderSensorLeash::new)
.registerCoreComponentType("Time", BuilderSensorTime::new)
.registerCoreComponentType("Count", BuilderSensorCount::new)
.registerCoreComponentType("Target", BuilderSensorTarget::new)
.registerCoreComponentType("Timer", BuilderSensorTimer::new)
.registerCoreComponentType("Switch", BuilderSensorSwitch::new)
.registerCoreComponentType("Light", BuilderSensorLight::new)
.registerCoreComponentType("Age", BuilderSensorAge::new)
.registerCoreComponentType("Flag", BuilderSensorFlag::new)
.registerCoreComponentType("DroppedItem", BuilderSensorDroppedItem::new)
.registerCoreComponentType("Path", BuilderSensorPath::new)
.registerCoreComponentType("Weather", BuilderSensorWeather::new)
.registerCoreComponentType("Block", BuilderSensorBlock::new)
.registerCoreComponentType("BlockChange", BuilderSensorBlockChange::new)
.registerCoreComponentType("EntityEvent", BuilderSensorEntityEvent::new)
.registerCoreComponentType("Random", BuilderSensorRandom::new)
.registerCoreComponentType("CanInteract", BuilderSensorCanInteract::new)
.registerCoreComponentType("HasInteracted", BuilderSensorHasInteracted::new)
.registerCoreComponentType("ReadPosition", BuilderSensorReadPosition::new)
.registerCoreComponentType("Animation", BuilderSensorAnimation::new)
.registerCoreComponentType("CanPlaceBlock", BuilderSensorCanPlace::new)
.registerCoreComponentType("Nav", BuilderSensorNav::new)
.registerCoreComponentType("InWater", BuilderSensorInWater::new)
.registerCoreComponentType("IsBusy", BuilderSensorIsBusy::new)
.registerCoreComponentType("InteractionContext", BuilderSensorInteractionContext::new)
.registerCoreComponentType("Alarm", BuilderSensorAlarm::new)
.registerCoreComponentType("AdjustPosition", BuilderSensorAdjustPosition::new)
.registerCoreComponentType("SearchRay", BuilderSensorSearchRay::new)
.registerCoreComponentType("BlockType", BuilderSensorBlockType::new)
.registerCoreComponentType("Self", BuilderSensorSelf::new)
.registerCoreComponentType("ValueProviderWrapper", BuilderSensorValueProviderWrapper::new);
this.registerCoreComponentType("Attitude", BuilderEntityFilterAttitude::new)
.registerCoreComponentType("LineOfSight", BuilderEntityFilterLineOfSight::new)
.registerCoreComponentType("HeightDifference", BuilderEntityFilterHeightDifference::new)
.registerCoreComponentType("ViewSector", BuilderEntityFilterViewSector::new)
.registerCoreComponentType("Combat", BuilderEntityFilterCombat::new)
.registerCoreComponentType("ItemInHand", BuilderEntityFilterItemInHand::new)
.registerCoreComponentType("NPCGroup", BuilderEntityFilterNPCGroup::new)
.registerCoreComponentType("MovementState", BuilderEntityFilterMovementState::new)
.registerCoreComponentType("SpotsMe", BuilderEntityFilterSpotsMe::new)
.registerCoreComponentType("StandingOnBlock", BuilderEntityFilterStandingOnBlock::new)
.registerCoreComponentType("Stat", BuilderEntityFilterStat::new)
.registerCoreComponentType("Inventory", BuilderEntityFilterInventory::new)
.registerCoreComponentType("Not", BuilderEntityFilterNot::new)
.registerCoreComponentType("And", BuilderEntityFilterAnd::new)
.registerCoreComponentType("Or", BuilderEntityFilterOr::new)
.registerCoreComponentType("Altitude", BuilderEntityFilterAltitude::new)
.registerCoreComponentType("InsideBlock", BuilderEntityFilterInsideBlock::new);
this.registerCoreComponentType("Attitude", BuilderSensorEntityPrioritiserAttitude::new);
NPCPlugin.NPCConfig config = this.config.get();
this.autoReload = config.isAutoReload();
this.validateBuilder = config.isValidateBuilder();
this.maxBlackboardBlockCountPerType = config.getMaxBlackboardBlockType();
this.logFailingTestErrors = config.isLogFailingTestErrors();
this.presetCoverageTestNPCs = config.getPresetCoverageTestNPCs();
}
public String[] getPresetCoverageTestNPCs() {
return this.presetCoverageTestNPCs;
}
@Nullable
public Pair<Ref<EntityStore>, INonPlayerCharacter> spawnNPC(
@Nonnull Store<EntityStore> store, @Nonnull String npcType, @Nullable String groupType, @Nonnull Vector3d position, @Nonnull Vector3f rotation
) {
int roleIndex = this.getIndex(npcType);
if (roleIndex < 0) {
return null;
} else {
Pair<Ref<EntityStore>, NPCEntity> npcPair = this.spawnEntity(store, roleIndex, position, rotation, null, null);
FlockAsset flockDefinition = groupType != null ? FlockAsset.getAssetMap().getAsset(groupType) : null;
if (npcPair != null) {
Ref<EntityStore> npcRef = (Ref<EntityStore>)npcPair.first();
NPCEntity npcComponent = (NPCEntity)npcPair.second();
FlockPlugin.trySpawnFlock(npcRef, npcComponent, store, roleIndex, position, rotation, flockDefinition, null);
return Pair.of((Ref)npcPair.first(), (INonPlayerCharacter)npcPair.second());
} else {
return null;
}
}
}
public static void reloadNPCsWithRole(int roleIndex) {
Universe.get()
.getWorlds()
.forEach(
(s, world) -> world.execute(() -> world.getEntityStore().getStore().forEachChunk(NPCEntity.getComponentType(), (archetypeChunk, commandBuffer) -> {
for (int index = 0; index < archetypeChunk.size(); index++) {
NPCEntity npc = archetypeChunk.getComponent(index, NPCEntity.getComponentType());
if (npc.getRoleIndex() == roleIndex && !npc.getRole().isRoleChangeRequested()) {
RoleChangeSystem.requestRoleChange(archetypeChunk.getReferenceTo(index), npc.getRole(), roleIndex, true, world.getEntityStore().getStore());
}
}
}))
);
}
protected void onNPCGroupsLoaded(LoadedAssetsEvent<String, NPCGroup, AssetMap<String, NPCGroup>> event) {
this.putNPCGroups();
}
protected void onNPCGroupsRemoved(RemovedAssetsEvent<String, NPCGroup, AssetMap<String, NPCGroup>> event) {
this.putNPCGroups();
}
protected void onAttitudeGroupsLoaded(@Nonnull LoadedAssetsEvent<String, AttitudeGroup, AssetMap<String, AttitudeGroup>> event) {
if (this.attitudeMap == null) {
this.putAttitudeGroups();
} else {
Map<String, AttitudeGroup> loadedAssets = event.getLoadedAssets();
IndexedLookupTableAssetMap<String, AttitudeGroup> assets = AttitudeGroup.getAssetMap();
int attitudeGroupCount = this.attitudeMap.getAttitudeGroupCount();
for (String id : loadedAssets.keySet()) {
int index = assets.getIndex(id);
if (index == Integer.MIN_VALUE) {
throw new IllegalArgumentException("Unknown key! " + id);
}
if (index >= attitudeGroupCount) {
this.putAttitudeGroups();
return;
}
}
loadedAssets.forEach((idx, group) -> {
int indexx = assets.getIndex(idx);
if (indexx == Integer.MIN_VALUE) {
throw new IllegalArgumentException("Unknown key! " + idx);
} else {
this.attitudeMap.updateAttitudeGroup(indexx, group);
}
});
}
}
protected void onAttitudeGroupsRemoved(RemovedAssetsEvent<String, AttitudeGroup, AssetMap<String, AttitudeGroup>> event) {
this.putAttitudeGroups();
}
protected void onItemAttitudeGroupsLoaded(@Nonnull LoadedAssetsEvent<String, ItemAttitudeGroup, AssetMap<String, ItemAttitudeGroup>> event) {
if (this.itemAttitudeMap == null) {
this.putItemAttitudeGroups();
} else {
Map<String, ItemAttitudeGroup> loadedAssets = event.getLoadedAssets();
IndexedLookupTableAssetMap<String, ItemAttitudeGroup> assets = ItemAttitudeGroup.getAssetMap();
int attitudeGroupCount = this.itemAttitudeMap.getAttitudeGroupCount();
for (String id : loadedAssets.keySet()) {
int index = assets.getIndex(id);
if (index == Integer.MIN_VALUE) {
throw new IllegalArgumentException("Unknown key! " + id);
}
if (index >= attitudeGroupCount) {
this.putItemAttitudeGroups();
return;
}
}
loadedAssets.forEach((idx, group) -> {
int indexx = assets.getIndex(idx);
if (indexx == Integer.MIN_VALUE) {
throw new IllegalArgumentException("Unknown key! " + idx);
} else {
this.itemAttitudeMap.updateAttitudeGroup(indexx, group);
}
});
}
}
protected void onItemAttitudeGroupsRemoved(RemovedAssetsEvent<String, ItemAttitudeGroup, AssetMap<String, ItemAttitudeGroup>> event) {
this.putItemAttitudeGroups();
}
private void putItemAttitudeGroups() {
ItemAttitudeMap.Builder builder = new ItemAttitudeMap.Builder();
builder.addAttitudeGroups(ItemAttitudeGroup.getAssetMap().getAssetMap());
this.itemAttitudeMap = builder.build();
}
protected void onPathChange(WorldPathChangedEvent event) {
this.pathChangeRevision.getAndIncrement();
}
public int getPathChangeRevision() {
return this.pathChangeRevision.get();
}
protected void onNPCsLoaded(AllNPCsLoadedEvent event) {
this.putNPCGroups();
}
private void putNPCGroups() {
IndexedLookupTableAssetMap<String, NPCGroup> indexedAssetMap = NPCGroup.getAssetMap();
Object2IntOpenHashMap<String> tagSetIndexMap = new Object2IntOpenHashMap();
indexedAssetMap.getAssetMap().forEach((name, group) -> {
int index = indexedAssetMap.getIndex(name);
if (index == Integer.MIN_VALUE) {
throw new IllegalArgumentException("Unknown key! " + name);
} else {
tagSetIndexMap.put(name, index);
}
});
TagSetPlugin.get(NPCGroup.class).putAssetSets(indexedAssetMap.getAssetMap(), tagSetIndexMap, this.builderManager.getNameToIndexMap());
this.putAttitudeGroups();
}
private void putAttitudeGroups() {
AttitudeMap.Builder builder = new AttitudeMap.Builder();
builder.addAttitudeGroups(AttitudeGroup.getAssetMap().getAssetMap());
this.attitudeMap = builder.build();
}
@Nullable
public String getName(int builderIndex) {
return this.builderManager.lookupName(builderIndex);
}
public int getIndex(String builderName) {
return this.builderManager.getIndex(builderName);
}
@Nullable
public Builder<Role> tryGetCachedValidRole(int roleIndex) {
return this.builderManager.tryGetCachedValidRole(roleIndex);
}
@Nullable
public BuilderInfo getBuilderInfo(Builder<?> builder) {
return this.builderManager.getBuilderInfo(builder);
}
public List<String> getRoleTemplateNames(boolean spawnableOnly) {
return this.builderManager
.collectMatchingBuilders(
new ObjectArrayList(),
entry -> entry.getBuilder().category() == Role.class && (!spawnableOnly || entry.getBuilder().isSpawnable()),
(builderInfo, objects) -> objects.add(builderInfo.getKeyName())
);
}
public boolean hasRoleName(String roleName) {
return this.getRoleBuilderInfo(this.getIndex(roleName)) != null;
}
public void validateSpawnableRole(String roleName) {
BuilderInfo builder = this.getRoleBuilderInfo(this.getIndex(roleName));
if (builder == null) {
throw new SkipSentryException(new IllegalArgumentException(roleName + " does not exist as a role!"));
} else if (!builder.getBuilder().isSpawnable()) {
throw new SkipSentryException(new IllegalArgumentException(roleName + " is an abstract role type and cannot be spawned directly!"));
}
}
@Nullable
public BuilderInfo getRoleBuilderInfo(int roleIndex) {
BuilderInfo builderInfo = this.builderManager.tryGetBuilderInfo(roleIndex);
return builderInfo != null && builderInfo.getBuilder().category() == Role.class ? builderInfo : null;
}
public void setBuilderInvalid(int builderIndex) {
BuilderInfo builderInfo = this.builderManager.tryGetBuilderInfo(builderIndex);
if (builderInfo != null) {
builderInfo.setNeedsReload();
}
}
public AttitudeMap getAttitudeMap() {
return this.attitudeMap;
}
public ItemAttitudeMap getItemAttitudeMap() {
return this.itemAttitudeMap;
}
public boolean testAndValidateRole(@Nullable BuilderInfo builderInfo) {
return builderInfo != null
&& builderInfo.getBuilder() != null
&& builderInfo.getBuilder().category() == Role.class
&& this.builderManager.validateBuilder(builderInfo);
}
public void forceValidation(int builderIndex) {
this.builderManager.forceValidation(builderIndex);
}
@Nullable
public Pair<Ref<EntityStore>, NPCEntity> spawnEntity(
@Nonnull Store<EntityStore> store,
int roleIndex,
@Nonnull Vector3d position,
Vector3f rotation,
Model spawnModel,
TriConsumer<NPCEntity, Ref<EntityStore>, Store<EntityStore>> postSpawn
) {
return this.spawnEntity(store, roleIndex, position, rotation, spawnModel, null, postSpawn);
}
@Nullable
public Pair<Ref<EntityStore>, NPCEntity> spawnEntity(
@Nonnull Store<EntityStore> store,
int roleIndex,
@Nonnull Vector3d position,
@Nullable Vector3f rotation,
@Nullable Model spawnModel,
@Nullable TriConsumer<NPCEntity, Holder<EntityStore>, Store<EntityStore>> preAddToWorld,
@Nullable TriConsumer<NPCEntity, Ref<EntityStore>, Store<EntityStore>> postSpawn
) {
WorldTimeResource worldTimeResource = store.getResource(WorldTimeResource.getResourceType());
NPCEntity npcComponent = new NPCEntity();
npcComponent.setSpawnInstant(worldTimeResource.getGameTime());
if (rotation == null) {
rotation = NULL_ROTATION;
}
npcComponent.saveLeashInformation(position, rotation);
String roleName = this.getName(roleIndex);
if (roleName == null) {
get().getLogger().at(Level.WARNING).log("Unable to spawn entity with invalid role index: %s!", roleIndex);
return null;
} else {
npcComponent.setRoleName(roleName);
npcComponent.setRoleIndex(roleIndex);
Holder<EntityStore> holder = EntityStore.REGISTRY.newHolder();
holder.addComponent(NPCEntity.getComponentType(), npcComponent);
holder.addComponent(TransformComponent.getComponentType(), new TransformComponent(position, rotation));
holder.addComponent(HeadRotation.getComponentType(), new HeadRotation(rotation));
DisplayNameComponent displayNameComponent = new DisplayNameComponent(Message.raw(roleName));
holder.addComponent(DisplayNameComponent.getComponentType(), displayNameComponent);
holder.ensureComponent(UUIDComponent.getComponentType());
if (spawnModel != null) {
npcComponent.setInitialModelScale(spawnModel.getScale());
holder.addComponent(ModelComponent.getComponentType(), new ModelComponent(spawnModel));
holder.addComponent(PersistentModel.getComponentType(), new PersistentModel(spawnModel.toReference()));
}
if (preAddToWorld != null) {
preAddToWorld.accept(npcComponent, holder, store);
}
Ref<EntityStore> ref = store.addEntity(holder, AddReason.SPAWN);
if (ref == null) {
get().getLogger().at(Level.WARNING).log("Unable to handle non-spawned entity: %s!", this.getName(roleIndex));
return null;
} else {
if (postSpawn != null) {
postSpawn.accept(npcComponent, ref, store);
}
return Pair.of(ref, npcComponent);
}
}
}
@Nonnull
public BuilderInfo prepareRoleBuilderInfo(int roleIndex) {
try {
BuilderInfo builderInfo = this.builderManager.getCachedBuilderInfo(roleIndex, Role.class);
if (this.validateBuilder) {
if (!builderInfo.isValidated()) {
this.builderManager.validateBuilder(builderInfo);
}
if (!builderInfo.isValid()) {
throw new SkipSentryException(new IllegalStateException("Builder " + builderInfo.getKeyName() + " failed validation!"));
}
}
return builderInfo;
} catch (RuntimeException var4) {
throw new SkipSentryException(
new RuntimeException(String.format("Cannot use role template '%s' (%s): %s", this.getName(roleIndex), roleIndex, var4.getMessage()), var4)
);
}
}
@Nonnull
public static Role buildRole(@Nonnull Builder<Role> roleBuilder, @Nonnull BuilderInfo builderInfo, @Nonnull BuilderSupport builderSupport, int roleIndex) {
Role role;
try {
StdScope scope = roleBuilder.getBuilderParameters().createScope();
builderSupport.setScope(scope);
builderSupport.setGlobalScope(scope);
role = roleBuilder.build(builderSupport);
role.postRoleBuilt(builderSupport);
} catch (Throwable var6) {
builderInfo.setNeedsReload();
throw new SkipSentryException(var6);
}
role.setRoleIndex(roleIndex, builderInfo.getKeyName());
return role;
}
protected void onModelsChanged(@Nonnull LoadedAssetsEvent<String, ModelAsset, DefaultAssetMap<String, ModelAsset>> event) {
Map<String, ModelAsset> loadedModelAssets = event.getLoadedAssets();
Universe.get()
.getWorlds()
.values()
.forEach(
world -> world.execute(
() -> {
Store<EntityStore> store = world.getEntityStore().getStore();
store.forEachEntityParallel(
NPCEntity.getComponentType(),
(index, archetypeChunk, commandBuffer) -> {
ModelComponent entityModelComponent = archetypeChunk.getComponent(index, ModelComponent.getComponentType());
if (entityModelComponent != null) {
Model oldModel = entityModelComponent.getModel();
ModelAsset newModelAsset = loadedModelAssets.get(oldModel.getModelAssetId());
if (newModelAsset != null) {
Ref<EntityStore> entityReference = archetypeChunk.getReferenceTo(index);
commandBuffer.putComponent(
entityReference,
ModelComponent.getComponentType(),
new ModelComponent(Model.createScaledModel(newModelAsset, oldModel.getScale(), oldModel.getRandomAttachmentIds()))
);
}
}
}
);
}
)
);
}
protected void generateDescriptors() {
this.getLogger().at(Level.INFO).log("===== Generating descriptors for NPC!");
this.builderDescriptors = this.builderManager.generateDescriptors();
}
protected void saveDescriptors() {
this.getLogger().at(Level.INFO).log("===== Saving descriptors for NPC!");
Path path = Path.of("npc_descriptors.json");
BuilderManager.saveDescriptors(this.builderDescriptors, path);
this.getLogger().at(Level.INFO).log("Saved NPC descriptors to: %s", path);
}
public BuilderManager getBuilderManager() {
return this.builderManager;
}
public int getMaxBlackboardBlockCountPerType() {
return this.maxBlackboardBlockCountPerType;
}
public boolean isLogFailingTestErrors() {
return this.logFailingTestErrors;
}
public boolean startRoleBenchmark(double seconds, @Nonnull Consumer<Int2ObjectMap<TimeDistributionRecorder>> onFinished) {
this.benchmarkLock.lock();
label37: {
boolean var4;
try {
if (!this.isBenchmarking()) {
this.roleTickDistribution = new Int2ObjectOpenHashMap();
this.roleTickDistributionAll = new TimeDistributionRecorder(0.01, 1.0E-5);
this.roleTickDistribution.put(-1, this.roleTickDistributionAll);
break label37;
}
var4 = false;
} finally {
this.benchmarkLock.unlock();
}
return var4;
}
new CompletableFuture().completeOnTimeout(null, Math.round(seconds * 1000.0), TimeUnit.MILLISECONDS).thenRunAsync(() -> {
Int2ObjectMap<TimeDistributionRecorder> distribution = this.roleTickDistribution;
this.benchmarkLock.lock();
try {
this.roleTickDistribution = null;
this.roleTickDistributionAll = null;
} finally {
this.benchmarkLock.unlock();
}
onFinished.accept(distribution);
});
return true;
}
public void collectRoleTick(int roleIndex, long nanos) {
if (this.benchmarkLock.tryLock()) {
try {
if (this.roleTickDistribution != null) {
((TimeDistributionRecorder)this.roleTickDistribution.computeIfAbsent(roleIndex, i -> new TimeDistributionRecorder(0.01, 1.0E-5)))
.recordNanos(nanos);
this.roleTickDistributionAll.recordNanos(nanos);
}
} finally {
this.benchmarkLock.unlock();
}
}
}
public boolean isBenchmarkingRole() {
return this.roleTickDistribution != null;
}
public boolean startSensorSupportBenchmark(double seconds, @Nonnull Consumer<Int2ObjectMap<SensorSupportBenchmark>> onFinished) {
this.benchmarkLock.lock();
label37: {
boolean var4;
try {
if (!this.isBenchmarking()) {
this.roleSensorSupportDistribution = new Int2ObjectOpenHashMap();
this.roleSensorSupportDistributionAll = new SensorSupportBenchmark();
this.roleSensorSupportDistribution.put(-1, this.roleSensorSupportDistributionAll);
break label37;
}
var4 = false;
} finally {
this.benchmarkLock.unlock();
}
return var4;
}
new CompletableFuture().completeOnTimeout(null, Math.round(seconds * 1000.0), TimeUnit.MILLISECONDS).thenRunAsync(() -> {
Int2ObjectMap<SensorSupportBenchmark> distribution = this.roleSensorSupportDistribution;
this.benchmarkLock.lock();
try {
this.roleSensorSupportDistribution = null;
this.roleSensorSupportDistributionAll = null;
} finally {
this.benchmarkLock.unlock();
}
onFinished.accept(distribution);
});
return true;
}
public boolean isBenchmarkingSensorSupport() {
return this.roleSensorSupportDistributionAll != null;
}
protected boolean isBenchmarking() {
return this.isBenchmarkingRole() || this.isBenchmarkingSensorSupport();
}
public void collectSensorSupportPlayerList(
int roleIndex, long getNanos, double maxPlayerDistanceSorted, double maxPlayerDistance, double maxPlayerDistanceAvoidance, int numPlayers
) {
if (this.benchmarkLock.tryLock()) {
try {
if (this.roleSensorSupportDistribution != null) {
((SensorSupportBenchmark)this.roleSensorSupportDistribution.computeIfAbsent(roleIndex, i -> new SensorSupportBenchmark()))
.collectPlayerList(getNanos, maxPlayerDistanceSorted, maxPlayerDistance, maxPlayerDistanceAvoidance, numPlayers);
this.roleSensorSupportDistributionAll
.collectPlayerList(getNanos, maxPlayerDistanceSorted, maxPlayerDistance, maxPlayerDistanceAvoidance, numPlayers);
}
} finally {
this.benchmarkLock.unlock();
}
}
}
public void collectSensorSupportEntityList(
int roleIndex, long getNanos, double maxEntityDistanceSorted, double maxEntityDistance, double maxEntityDistanceAvoidance, int numEntities
) {
if (this.benchmarkLock.tryLock()) {
try {
if (this.roleSensorSupportDistribution != null) {
((SensorSupportBenchmark)this.roleSensorSupportDistribution.computeIfAbsent(roleIndex, i -> new SensorSupportBenchmark()))
.collectEntityList(getNanos, maxEntityDistanceSorted, maxEntityDistance, maxEntityDistanceAvoidance, numEntities);
this.roleSensorSupportDistributionAll
.collectEntityList(getNanos, maxEntityDistanceSorted, maxEntityDistance, maxEntityDistanceAvoidance, numEntities);
}
} finally {
this.benchmarkLock.unlock();
}
}
}
public void collectSensorSupportLosTest(int roleIndex, boolean cacheHit, long time) {
if (this.isBenchmarkingSensorSupport() && this.benchmarkLock.tryLock()) {
try {
if (this.roleSensorSupportDistribution != null) {
((SensorSupportBenchmark)this.roleSensorSupportDistribution.computeIfAbsent(roleIndex, i -> new SensorSupportBenchmark()))
.collectLosTest(cacheHit, time);
this.roleSensorSupportDistributionAll.collectLosTest(cacheHit, time);
}
} finally {
this.benchmarkLock.unlock();
}
}
}
public void collectSensorSupportInverseLosTest(int roleIndex, boolean cacheHit) {
if (this.isBenchmarkingSensorSupport() && this.benchmarkLock.tryLock()) {
try {
if (this.roleSensorSupportDistribution != null) {
((SensorSupportBenchmark)this.roleSensorSupportDistribution.computeIfAbsent(roleIndex, i -> new SensorSupportBenchmark()))
.collectInverseLosTest(cacheHit);
this.roleSensorSupportDistributionAll.collectInverseLosTest(cacheHit);
}
} finally {
this.benchmarkLock.unlock();
}
}
}
public void collectSensorSupportFriendlyBlockingTest(int roleIndex, boolean cacheHit) {
if (this.isBenchmarkingSensorSupport() && this.benchmarkLock.tryLock()) {
try {
if (this.roleSensorSupportDistribution != null) {
((SensorSupportBenchmark)this.roleSensorSupportDistribution.computeIfAbsent(roleIndex, i -> new SensorSupportBenchmark()))
.collectFriendlyBlockingTest(cacheHit);
this.roleSensorSupportDistributionAll.collectFriendlyBlockingTest(cacheHit);
}
} finally {
this.benchmarkLock.unlock();
}
}
}
public void collectSensorSupportTickDone(int roleIndex) {
if (this.isBenchmarkingSensorSupport() && this.benchmarkLock.tryLock()) {
try {
if (this.roleSensorSupportDistribution != null) {
((SensorSupportBenchmark)this.roleSensorSupportDistribution.computeIfAbsent(roleIndex, i -> new SensorSupportBenchmark())).tickDone();
this.roleSensorSupportDistributionAll.tickDone();
}
} finally {
this.benchmarkLock.unlock();
}
}
}
@Nonnull
public <T> NPCPlugin registerCoreComponentType(String name, @Nonnull Supplier<Builder<T>> builder) {
BuilderFactory<T> factory = this.builderManager.getFactory(builder.get().category());
factory.add(name, builder);
return this;
}
public void setRoleBuilderNeedsReload(Builder<?> builder) {
BuilderInfo builderInfo = this.getBuilderInfo(builder);
Objects.requireNonNull(builderInfo, "Have builder but can't get builderInfo for it");
builderInfo.setNeedsReload();
}
protected void registerCoreFactories() {
BuilderFactory<Role> roleFactory = new BuilderFactory<>(Role.class, "Type");
roleFactory.add("Generic", BuilderRole::new);
roleFactory.add("Abstract", BuilderRoleAbstract::new);
roleFactory.add("Variant", BuilderRoleVariant::new);
this.builderManager.registerFactory(roleFactory);
BuilderFactory<MotionController> motionControllerFactory = new BuilderFactory<>(MotionController.class, "Type");
motionControllerFactory.add("Walk", BuilderMotionControllerWalk::new);
motionControllerFactory.add("Fly", BuilderMotionControllerFly::new);
motionControllerFactory.add("Dive", BuilderMotionControllerDive::new);
this.builderManager.registerFactory(motionControllerFactory);
BuilderFactory<Map<String, MotionController>> motionControllerMapFactory = new BuilderFactory<>(
BuilderMotionControllerMapUtil.CLASS_REFERENCE, "Type", BuilderMotionControllerMap::new
);
this.builderManager.registerFactory(motionControllerMapFactory);
BuilderFactory<ActionList> actionListFactory = new BuilderFactory<>(ActionList.class, "Type", BuilderActionList::new);
this.builderManager.registerFactory(actionListFactory);
BuilderFactory<Instruction> instructionFactory = new BuilderFactory<>(Instruction.class, "Type", BuilderInstruction::new);
instructionFactory.add("Random", BuilderInstructionRandomized::new);
instructionFactory.add("Reference", BuilderInstructionReference::new);
this.builderManager.registerFactory(instructionFactory);
BuilderFactory<TransientPathDefinition> transientPathFactory = new BuilderFactory<>(
TransientPathDefinition.class, "Type", BuilderTransientPathDefinition::new
);
this.builderManager.registerFactory(transientPathFactory);
BuilderFactory<RelativeWaypointDefinition> relativeWaypointFactory = new BuilderFactory<>(
RelativeWaypointDefinition.class, "Type", BuilderRelativeWaypointDefinition::new
);
this.builderManager.registerFactory(relativeWaypointFactory);
BuilderFactory<WeightedAction> weightedActionFactory = new BuilderFactory<>(WeightedAction.class, "Type", BuilderWeightedAction::new);
this.builderManager.registerFactory(weightedActionFactory);
BuilderFactory<BuilderValueToParameterMapping.ValueToParameterMapping> valueToParameterMappingFactory = new BuilderFactory<>(
BuilderValueToParameterMapping.ValueToParameterMapping.class, "Type", BuilderValueToParameterMapping::new
);
this.builderManager.registerFactory(valueToParameterMappingFactory);
StateTransitionController.registerFactories(this.builderManager);
this.builderManager.registerFactory(new BuilderFactory<>(BodyMotion.class, "Type"));
this.builderManager.registerFactory(new BuilderFactory<>(HeadMotion.class, "Type"));
this.builderManager.registerFactory(new BuilderFactory<>(Action.class, "Type"));
this.builderManager.registerFactory(new BuilderFactory<>(Sensor.class, "Type"));
this.builderManager.registerFactory(new BuilderFactory<>(IEntityFilter.class, "Type"));
this.builderManager.registerFactory(new BuilderFactory<>(ISensorEntityPrioritiser.class, "Type"));
this.builderManager.registerFactory(new BuilderFactory<>(ISensorEntityCollector.class, "Type"));
}
protected static void onBalanceAssetsChanged(@Nonnull LoadedAssetsEvent<String, BalanceAsset, DefaultAssetMap<String, BalanceAsset>> event) {
Map<String, BalanceAsset> loadedAssets = event.getLoadedAssets();
Universe.get()
.getWorlds()
.forEach(
(name, world) -> world.execute(
() -> world.getEntityStore().getStore().forEachChunk(NPCEntity.getComponentType(), (archetypeChunk, commandBuffer) -> {
for (int index = 0; index < archetypeChunk.size(); index++) {
NPCEntity npcComponent = archetypeChunk.getComponent(index, NPCEntity.getComponentType());
assert npcComponent != null;
if (loadedAssets.containsKey(npcComponent.getRole().getBalanceAsset())) {
Ref<EntityStore> ref = archetypeChunk.getReferenceTo(index);
RoleChangeSystem.requestRoleChange(ref, npcComponent.getRole(), npcComponent.getRoleIndex(), false, world.getEntityStore().getStore());
}
}
})
)
);
}
protected static void onBalanceAssetsRemoved(@Nonnull RemovedAssetsEvent<String, BalanceAsset, DefaultAssetMap<String, BalanceAsset>> event) {
Set<String> removedAssets = event.getRemovedAssets();
Universe.get()
.getWorlds()
.forEach(
(name, world) -> world.execute(
() -> world.getEntityStore().getStore().forEachChunk(NPCEntity.getComponentType(), (archetypeChunk, commandBuffer) -> {
for (int index = 0; index < archetypeChunk.size(); index++) {
NPCEntity npcComponent = archetypeChunk.getComponent(index, NPCEntity.getComponentType());
assert npcComponent != null;
if (removedAssets.contains(npcComponent.getRole().getBalanceAsset())) {
Ref<EntityStore> ref = archetypeChunk.getReferenceTo(index);
commandBuffer.removeEntity(ref, RemoveReason.REMOVE);
}
}
})
)
);
}
public static class NPCConfig {
public static final BuilderCodec<NPCPlugin.NPCConfig> CODEC = BuilderCodec.builder(NPCPlugin.NPCConfig.class, NPCPlugin.NPCConfig::new)
.append(new KeyedCodec<>("Descriptors", Codec.BOOLEAN), (o, i) -> o.generateDescriptors = i, o -> o.generateDescriptors)
.add()
.append(new KeyedCodec<>("DescriptorsFile", Codec.BOOLEAN), (o, i) -> o.generateDescriptorsFile = i, o -> o.generateDescriptorsFile)
.add()
.append(new KeyedCodec<>("AutoReload", Codec.BOOLEAN), (o, i) -> o.autoReload = i, o -> o.autoReload)
.add()
.append(new KeyedCodec<>("ValidateBuilders", Codec.BOOLEAN), (o, i) -> o.validateBuilder = i, o -> o.validateBuilder)
.add()
.append(new KeyedCodec<>("MaxBlackboardBlockType", Codec.INTEGER), (o, i) -> o.maxBlackboardBlockType = i, o -> o.maxBlackboardBlockType)
.add()
.append(new KeyedCodec<>("LogFailingTestErrors", Codec.BOOLEAN), (o, i) -> o.logFailingTestErrors = i, o -> o.logFailingTestErrors)
.add()
.append(new KeyedCodec<>("PresetCoverageTestNPCs", Codec.STRING_ARRAY), (o, i) -> o.presetCoverageTestNPCs = i, o -> o.presetCoverageTestNPCs)
.add()
.build();
private boolean generateDescriptors;
private boolean generateDescriptorsFile;
private boolean autoReload = true;
private boolean validateBuilder = true;
private int maxBlackboardBlockType = 20;
private boolean logFailingTestErrors;
private String[] presetCoverageTestNPCs = new String[]{
"Test_Bird",
"Test_Block_Sensor",
"Test_Attack_Bow",
"Test_Combat_Sensor_Sheep",
"Test_Bow_Charge",
"Test_OffHand_Swap",
"Test_Patrol_Path",
"Test_Flock_Mixed#4",
"Test_Group_Sheep",
"Test_Attack_Flying_Ranged",
"Test_Interaction_Complete_Task",
"Test_Hotbar_Weapon_Swap",
"Test_Inventory_Contents",
"Test_Dive_Flee",
"Test_Jumping",
"Test_Walk_Leave",
"Test_Walk_Seek",
"Test_Watch",
"Test_Chained_Path",
"Test_Spawn_Action",
"Test_State_Evaluator_Toggle",
"Test_State_Evaluator_Sleep",
"Test_Alarm",
"Test_Timer_Repeating",
"Test_Action_Model_Attachment",
"Test_Animation_State_Change",
"Test_Block_Change",
"Test_Crouch",
"Test_Drop_Item",
"Test_Entity_Damage_Event",
"Test_Hover_Parrot",
"Test_In_Water",
"Test_Light_Sensor",
"Test_Model_Change",
"Test_Particle_Emotions",
"Test_Place_Blocks",
"Test_Position_Adjustment_Wrapper",
"Test_Probe",
"Test_Sensor_Age",
"Test_Sensor_DroppedItem",
"Test_Shoot_At_Block",
"Test_Species_Attitude",
"Test_Standing_On_Block_Sensor",
"Test_Teleport",
"Test_Throw_NPC",
"Test_Trigger_Spawners",
"Test_Weather_Sensor",
"Test_Bird_Land"
};
public boolean isGenerateDescriptors() {
return this.generateDescriptors;
}
public boolean isGenerateDescriptorsFile() {
return this.generateDescriptorsFile;
}
public boolean isAutoReload() {
return this.autoReload;
}
public boolean isValidateBuilder() {
return this.validateBuilder;
}
public int getMaxBlackboardBlockType() {
return this.maxBlackboardBlockType;
}
public boolean isLogFailingTestErrors() {
return this.logFailingTestErrors;
}
public String[] getPresetCoverageTestNPCs() {
return this.presetCoverageTestNPCs;
}
}
public static class NPCEntityRegenerateStatsSystem extends EntityStatsSystems.Regenerate<NPCEntity> {
public NPCEntityRegenerateStatsSystem() {
super(EntityStatMap.getComponentType(), NPCEntity.getComponentType());
}
}
}