package com.hypixel.hytale.server.core.modules.entity;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.component.Archetype;
import com.hypixel.hytale.component.ArchetypeChunk;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.ComponentType;
import com.hypixel.hytale.component.DisableProcessingAssert;
import com.hypixel.hytale.component.Holder;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.RemoveReason;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.component.SystemGroup;
import com.hypixel.hytale.component.query.Query;
import com.hypixel.hytale.component.system.HolderSystem;
import com.hypixel.hytale.component.system.tick.EntityTickingSystem;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.math.shape.Box;
import com.hypixel.hytale.protocol.ComponentUpdate;
import com.hypixel.hytale.protocol.ComponentUpdateType;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.server.core.entity.entities.BlockEntity;
import com.hypixel.hytale.server.core.modules.entity.component.BoundingBox;
import com.hypixel.hytale.server.core.modules.entity.component.EntityScaleComponent;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import com.hypixel.hytale.server.core.modules.entity.tracker.EntityTrackerSystems;
import com.hypixel.hytale.server.core.modules.entity.tracker.NetworkId;
import com.hypixel.hytale.server.core.modules.physics.SimplePhysicsProvider;
import com.hypixel.hytale.server.core.modules.physics.component.Velocity;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import java.util.Map;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class BlockEntitySystems {
private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass();
public BlockEntitySystems() {
}
public static class BlockEntitySetupSystem extends HolderSystem<EntityStore> {
private final ComponentType<EntityStore, BlockEntity> blockEntityComponentType;
public BlockEntitySetupSystem(ComponentType<EntityStore, BlockEntity> blockEntityComponentType) {
this.blockEntityComponentType = blockEntityComponentType;
}
public void onEntityAdd(@Nonnull Holder<EntityStore> holder, @Nonnull AddReason reason, @Nonnull Store<EntityStore> store) {
if (!holder.getArchetype().contains(NetworkId.getComponentType())) {
holder.addComponent(NetworkId.getComponentType(), new NetworkId(((EntityStore)store.getExternalData()).takeNextNetworkId()));
}
BlockEntity blockEntityComponent = (BlockEntity)holder.getComponent(this.blockEntityComponentType);
BoundingBox boundingBoxComponent = blockEntityComponent.createBoundingBoxComponent();
if (boundingBoxComponent == null) {
BlockEntitySystems.LOGGER.at(Level.SEVERE).log("Bounding box could not be initialized properly, defaulting to 1x1x1 dimensions for Block Entity bounding box");
boundingBoxComponent = new BoundingBox(Box.horizontallyCentered(1.0, 1.0, 1.0));
}
holder.putComponent(BoundingBox.getComponentType(), boundingBoxComponent);
SimplePhysicsProvider simplePhysicsProvider = blockEntityComponent.initPhysics(boundingBoxComponent);
simplePhysicsProvider.setMoveOutOfSolid(false);
}
public void onEntityRemoved(@Nonnull Holder<EntityStore> holder, @Nonnull RemoveReason reason, @Nonnull Store<EntityStore> store) {
}
public Query<EntityStore> getQuery() {
return this.blockEntityComponentType;
}
}
public static class BlockEntityTrackerSystem extends EntityTickingSystem<EntityStore> {
private final ComponentType<EntityStore, EntityTrackerSystems.Visible> visibleComponentType;
private final ComponentType<EntityStore, BlockEntity> blockEntityComponentType;
@Nonnull
private final Query<EntityStore> query;
public BlockEntityTrackerSystem(ComponentType<EntityStore, EntityTrackerSystems.Visible> visibleComponentType, ComponentType<EntityStore, BlockEntity> blockEntityComponentType) {
this.visibleComponentType = visibleComponentType;
this.blockEntityComponentType = blockEntityComponentType;
this.query = Query.<EntityStore>and(visibleComponentType, blockEntityComponentType);
}
@Nullable
public SystemGroup<EntityStore> getGroup() {
return EntityTrackerSystems.QUEUE_UPDATE_GROUP;
}
@Nonnull
public Query<EntityStore> getQuery() {
return this.query;
}
public boolean isParallel(int archetypeChunkSize, int taskCount) {
return EntityTickingSystem.maybeUseParallel(archetypeChunkSize, taskCount);
}
public void tick(float dt, int index, @Nonnull ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull Store<EntityStore> store, @Nonnull CommandBuffer<EntityStore> commandBuffer) {
EntityTrackerSystems.Visible visible = (EntityTrackerSystems.Visible)archetypeChunk.getComponent(index, this.visibleComponentType);
BlockEntity blockEntity = (BlockEntity)archetypeChunk.getComponent(index, this.blockEntityComponentType);
assert blockEntity != null;
float entityScale = 2.0F;
boolean scaleOutdated = false;
EntityScaleComponent entityScaleComponent = (EntityScaleComponent)archetypeChunk.getComponent(index, EntityScaleComponent.getComponentType());
if (entityScaleComponent != null) {
entityScale = entityScaleComponent.getScale();
scaleOutdated = entityScaleComponent.consumeNetworkOutdated();
}
boolean blockIdOutdated = blockEntity.consumeBlockIdNetworkOutdated();
if (!blockIdOutdated && !scaleOutdated) {
if (!visible.newlyVisibleTo.isEmpty()) {
queueUpdatesFor(archetypeChunk.getReferenceTo(index), blockEntity, visible.newlyVisibleTo, entityScale);
}
} else {
queueUpdatesFor(archetypeChunk.getReferenceTo(index), blockEntity, visible.visibleTo, entityScale);
}
}
private static void queueUpdatesFor(Ref<EntityStore> ref, @Nonnull BlockEntity entity, @Nonnull Map<Ref<EntityStore>, EntityTrackerSystems.EntityViewer> visibleTo, float entityScale) {
ComponentUpdate update = new ComponentUpdate();
update.type = ComponentUpdateType.Block;
String key = entity.getBlockTypeKey();
int index = BlockType.getAssetMap().getIndex(key);
if (index == -2147483648) {
throw new IllegalArgumentException("Unknown key! " + key);
} else {
update.blockId = index;
update.entityScale = entityScale;
for(EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) {
viewer.queueUpdate(ref, update);
}
}
}
}
public static class Ticking extends EntityTickingSystem<EntityStore> implements DisableProcessingAssert {
private final ComponentType<EntityStore, TransformComponent> transformComponentType = TransformComponent.getComponentType();
private final ComponentType<EntityStore, BlockEntity> blockEntityComponentType;
private final Archetype<EntityStore> archetype;
public Ticking(@Nonnull ComponentType<EntityStore, BlockEntity> blockEntityComponentType) {
this.blockEntityComponentType = blockEntityComponentType;
this.archetype = Archetype.of(this.transformComponentType, blockEntityComponentType, Velocity.getComponentType());
}
public Query<EntityStore> getQuery() {
return this.archetype;
}
public void tick(float dt, int index, @Nonnull ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull Store<EntityStore> store, @Nonnull CommandBuffer<EntityStore> commandBuffer) {
TransformComponent transformComponent = (TransformComponent)archetypeChunk.getComponent(index, this.transformComponentType);
assert transformComponent != null;
BlockEntity blockEntityComponent = (BlockEntity)archetypeChunk.getComponent(index, this.blockEntityComponentType);
assert blockEntityComponent != null;
Velocity velocityComponent = (Velocity)archetypeChunk.getComponent(index, Velocity.getComponentType());
assert velocityComponent != null;
try {
blockEntityComponent.getSimplePhysicsProvider().tick((double)dt, velocityComponent, ((EntityStore)store.getExternalData()).getWorld(), transformComponent, archetypeChunk.getReferenceTo(index), commandBuffer);
} catch (Throwable throwable) {
((HytaleLogger.Api)BlockEntitySystems.LOGGER.at(Level.SEVERE).withCause(throwable)).log("Exception while ticking entity. Removing entity %s", blockEntityComponent);
commandBuffer.removeEntity(archetypeChunk.getReferenceTo(index), RemoveReason.REMOVE);
}
}
}
}