diff --git a/src/main/java/org/KaiFlo/SolarCell/ExampleCommand.java b/src/main/java/org/KaiFlo/SolarCell/Commands/ExampleCommand.java similarity index 57% rename from src/main/java/org/KaiFlo/SolarCell/ExampleCommand.java rename to src/main/java/org/KaiFlo/SolarCell/Commands/ExampleCommand.java index a303e6a..73b4ebc 100644 --- a/src/main/java/org/KaiFlo/SolarCell/ExampleCommand.java +++ b/src/main/java/org/KaiFlo/SolarCell/Commands/ExampleCommand.java @@ -1,38 +1,23 @@ -package org.KaiFlo.SolarCell; +package org.KaiFlo.SolarCell.Commands; -import com.hypixel.hytale.component.Archetype; -import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.logger.HytaleLogger; -import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.math.vector.Vector3i; -import com.hypixel.hytale.protocol.BlockPlacementSettings; import com.hypixel.hytale.protocol.GameMode; import com.hypixel.hytale.server.core.Message; -import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; import com.hypixel.hytale.server.core.command.system.CommandContext; -import com.hypixel.hytale.server.core.command.system.arguments.system.ArgWrapper; import com.hypixel.hytale.server.core.command.system.arguments.system.OptionalArg; -import com.hypixel.hytale.server.core.command.system.arguments.system.WrappedArg; import com.hypixel.hytale.server.core.command.system.arguments.types.ArgTypes; import com.hypixel.hytale.server.core.command.system.basecommands.CommandBase; import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; import com.hypixel.hytale.server.core.universe.Universe; import com.hypixel.hytale.server.core.universe.world.World; -import com.hypixel.hytale.server.core.universe.world.accessor.ChunkAccessor; -import com.hypixel.hytale.server.core.universe.world.chunk.BlockChunk; -import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk; -import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; -import it.unimi.dsi.fastutil.longs.LongSet; +import org.KaiFlo.SolarCell.Helpers.BlockHelper; import javax.annotation.Nonnull; import java.util.Objects; -import java.util.stream.Collectors; -/** - * This is an example command that will simply print the name of the plugin in chat when used. - */ public class ExampleCommand extends CommandBase { private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); @@ -51,18 +36,16 @@ public class ExampleCommand extends CommandBase { @Override protected void executeSync(@Nonnull CommandContext ctx) { ctx.sendMessage(Message.raw("Hello from the " + pluginName + " v" + pluginVersion + " plugin!")); - World defaultWorld = Universe.get().getDefaultWorld(); - var chunkStore = Objects.requireNonNull(defaultWorld).getChunkStore(); - LongSet chunkIndexes = chunkStore.getChunkIndexes(); + World defaultWorld = Objects.requireNonNull(Universe.get().getDefaultWorld()); defaultWorld.execute(() -> { Store store = defaultWorld.getEntityStore().getStore(); - Vector3i position = Objects.requireNonNull(store.getComponent(Objects.requireNonNull(ctx.senderAsPlayerRef()), TransformComponent.getComponentType())) - .getPosition() - .toVector3i(); + var playerRef = ctx.senderAsPlayerRef(); + var playerTransform = store.getComponent(Objects.requireNonNull(playerRef), TransformComponent.getComponentType()); + Vector3i playerPosition = Objects.requireNonNull(playerTransform).getPosition().toVector3i(); var size = sizeArg.get(ctx); if (size == null) size = 5; - executeForCubeAround(position.x, position.y, position.z, size, (x, y, z) -> { + BlockHelper.executeForCubeAround(playerPosition.x, playerPosition.y, playerPosition.z, size,true, (x, y, z) -> { // BlockType blockType = defaultWorld.getBlockType(x, y, z); // if (blockType != null) { // LOGGER.atInfo().log(blockType.getId() + " at " + x + "," + y + "," + z); @@ -80,17 +63,4 @@ public class ExampleCommand extends CommandBase { }); } - void executeForCubeAround(int x, int y, int z, int size, Callback callback) { - for (int x1 = x - size / 2; x1 < x + size / 2; x1++) { - for (int y1 = y - size / 2; y1 < y + size / 2; y1++) { - for (int z1 = z - size / 2; z1 < z + size / 2; z1++) { - callback.onBlockPosition(x1, y1, z1); - } - } - } - } - - interface Callback { - void onBlockPosition(int x, int y, int z); - } -} \ No newline at end of file +} diff --git a/src/main/java/org/KaiFlo/SolarCell/Components/EnergySource/AbstractEnergySource.java b/src/main/java/org/KaiFlo/SolarCell/Components/EnergySource/AbstractEnergySource.java new file mode 100644 index 0000000..7cf3d26 --- /dev/null +++ b/src/main/java/org/KaiFlo/SolarCell/Components/EnergySource/AbstractEnergySource.java @@ -0,0 +1,18 @@ +package org.KaiFlo.SolarCell.Components.EnergySource; + +public class AbstractEnergySource implements IEnergySource{ + @Override + public boolean isEndless() { + return true; + } + + @Override + public long getEnergyCapacity() { + return -1; + } + + @Override + public long getEnergyRatePerTick() { + return 1; + } +} diff --git a/src/main/java/org/KaiFlo/SolarCell/Components/EnergySource/IEnergySource.java b/src/main/java/org/KaiFlo/SolarCell/Components/EnergySource/IEnergySource.java new file mode 100644 index 0000000..628f2fc --- /dev/null +++ b/src/main/java/org/KaiFlo/SolarCell/Components/EnergySource/IEnergySource.java @@ -0,0 +1,19 @@ +package org.KaiFlo.SolarCell.Components.EnergySource; + +public interface IEnergySource { + + /** + * @return True if energy source is endless, False otherwise + */ + boolean isEndless(); + + /** + * @return If the energy source is not endless, returns the Capacity of the energy source, otherwise -1 + */ + long getEnergyCapacity(); + + /** + * @return The amount of energy the source produces per Tick + */ + long getEnergyRatePerTick(); +} diff --git a/src/main/java/org/KaiFlo/SolarCell/Components/EnergySource/Implementations/EnergySourceComponent.java b/src/main/java/org/KaiFlo/SolarCell/Components/EnergySource/Implementations/EnergySourceComponent.java new file mode 100644 index 0000000..1a0fcd2 --- /dev/null +++ b/src/main/java/org/KaiFlo/SolarCell/Components/EnergySource/Implementations/EnergySourceComponent.java @@ -0,0 +1,46 @@ +package org.KaiFlo.SolarCell.Components.EnergySource.Implementations; + +import com.hypixel.hytale.codec.builder.BuilderCodec; +import com.hypixel.hytale.component.Component; +import com.hypixel.hytale.component.ComponentType; +import com.hypixel.hytale.logger.HytaleLogger; +import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; +import org.KaiFlo.SolarCell.Components.EnergySource.AbstractEnergySource; +import org.KaiFlo.SolarCell.SolarCellPlugin; +import org.checkerframework.checker.nullness.compatqual.NullableDecl; + +public class EnergySourceComponent extends AbstractEnergySource implements Component { + public static final BuilderCodec CODEC = BuilderCodec.builder(EnergySourceComponent.class, EnergySourceComponent::new).build(); + + private final HytaleLogger Logger = HytaleLogger.getLogger(); + private long energyRatePerTick = 5; + + public static ComponentType getComponentType() { + return SolarCellPlugin.get().getSolarCellComponentType(); + } + + private EnergySourceComponent copyFrom(EnergySourceComponent other) { + this.energyRatePerTick = other.energyRatePerTick; + return this; + } + + @NullableDecl + @Override + public Component clone() { + try { + super.clone(); + } catch (CloneNotSupportedException e) { + Logger.atWarning().log("Cloning of " + this.getClass().getName() + " failed."); + } + return new EnergySourceComponent().copyFrom(this); + } + + @Override + public long getEnergyRatePerTick() { + return energyRatePerTick; + } + + public void setEnergyRatePerTick(long energyRatePerTick) { + this.energyRatePerTick = energyRatePerTick; + } +} diff --git a/src/main/java/org/KaiFlo/SolarCell/Helpers/BlockHelper.java b/src/main/java/org/KaiFlo/SolarCell/Helpers/BlockHelper.java new file mode 100644 index 0000000..83f60f2 --- /dev/null +++ b/src/main/java/org/KaiFlo/SolarCell/Helpers/BlockHelper.java @@ -0,0 +1,24 @@ +package org.KaiFlo.SolarCell.Helpers; + +public class BlockHelper { + + public static void executeForCubeAround(int x, int y, int z, int size, boolean own, Callback callback) { + for (int x1 = x - size / 2; x1 < x + size / 2; x1++) { + for (int y1 = y - size / 2; y1 < y + size / 2; y1++) { + for (int z1 = z - size / 2; z1 < z + size / 2; z1++) { + if (!(x1 == x && y1 == y && z1 == z)) { + callback.accept(x1, y1, z1); + } + else if (own) { + callback.accept(x1, y1, z1); + } + } + } + } + } + public interface Callback { + void accept(int x, int y, int z); + } +} + + diff --git a/src/main/java/org/KaiFlo/SolarCell/SolarCellPlugin.java b/src/main/java/org/KaiFlo/SolarCell/SolarCellPlugin.java index 17a9734..8bfa2ed 100644 --- a/src/main/java/org/KaiFlo/SolarCell/SolarCellPlugin.java +++ b/src/main/java/org/KaiFlo/SolarCell/SolarCellPlugin.java @@ -1,21 +1,29 @@ package org.KaiFlo.SolarCell; +import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.server.core.plugin.JavaPlugin; import com.hypixel.hytale.server.core.plugin.JavaPluginInit; +import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; +import org.KaiFlo.SolarCell.Commands.ExampleCommand; +import org.KaiFlo.SolarCell.Components.EnergySource.Implementations.EnergySourceComponent; +import org.KaiFlo.SolarCell.Systems.EnergySource.EnergySourceInitializerSystem; +import org.KaiFlo.SolarCell.Systems.EnergySource.EnergyProducerTickingSystem; import javax.annotation.Nonnull; -/** - * This class serves as the entrypoint for your plugin. Use the setup method to register into game registries or add - * event listeners. - */ - -@SuppressWarnings("unused") public class SolarCellPlugin extends JavaPlugin { + protected static SolarCellPlugin instance; + + public static SolarCellPlugin get() { + return instance; + } + private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); + private ComponentType solarCellComponentType; + public SolarCellPlugin(@Nonnull JavaPluginInit init) { super(init); LOGGER.atInfo().log("Hello from " + this.getName() + " version " + this.getManifest().getVersion().toString()); @@ -23,7 +31,19 @@ public class SolarCellPlugin extends JavaPlugin { @Override protected void setup() { + instance = this; LOGGER.atInfo().log("Setting up plugin " + this.getName()); + + solarCellComponentType = this.getChunkStoreRegistry().registerComponent(EnergySourceComponent.class, "SolarCell", EnergySourceComponent.CODEC); + this.getCommandRegistry().registerCommand(new ExampleCommand(this.getName(), this.getManifest().getVersion().toString())); + + this.getChunkStoreRegistry().registerSystem(new EnergySourceInitializerSystem()); + this.getChunkStoreRegistry().registerSystem(new EnergyProducerTickingSystem()); + + } + + public ComponentType getSolarCellComponentType() { + return solarCellComponentType; } } \ No newline at end of file diff --git a/src/main/java/org/KaiFlo/SolarCell/Systems/EnergySource/EnergyProducerTickingSystem.java b/src/main/java/org/KaiFlo/SolarCell/Systems/EnergySource/EnergyProducerTickingSystem.java new file mode 100644 index 0000000..21b6106 --- /dev/null +++ b/src/main/java/org/KaiFlo/SolarCell/Systems/EnergySource/EnergyProducerTickingSystem.java @@ -0,0 +1,74 @@ +package org.KaiFlo.SolarCell.Systems.EnergySource; + +import com.hypixel.hytale.component.ArchetypeChunk; +import com.hypixel.hytale.component.CommandBuffer; +import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.component.query.Query; +import com.hypixel.hytale.component.system.tick.EntityTickingSystem; +import com.hypixel.hytale.logger.HytaleLogger; +import com.hypixel.hytale.math.util.ChunkUtil; +import com.hypixel.hytale.server.core.asset.type.blocktick.BlockTickStrategy; +import com.hypixel.hytale.server.core.universe.world.chunk.BlockComponentChunk; +import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk; +import com.hypixel.hytale.server.core.universe.world.chunk.section.BlockSection; +import com.hypixel.hytale.server.core.universe.world.chunk.section.ChunkSection; +import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; +import dev.zkiller.energystorage.components.EnergyStorageBlockComponent; +import org.KaiFlo.SolarCell.Components.EnergySource.Implementations.EnergySourceComponent; +import org.KaiFlo.SolarCell.Helpers.BlockHelper; +import org.checkerframework.checker.nullness.compatqual.NonNullDecl; +import org.checkerframework.checker.nullness.compatqual.NullableDecl; + +public class EnergyProducerTickingSystem extends EntityTickingSystem { + private final HytaleLogger LOGGER = HytaleLogger.getLogger(); + + @Override + public void tick(float v, int i, @NonNullDecl ArchetypeChunk archetypeChunk, @NonNullDecl Store store, @NonNullDecl CommandBuffer commandBuffer) { + var blockSection = archetypeChunk.getComponent(i, BlockSection.getComponentType()); + if (blockSection == null || blockSection.getTickingBlocksCount() != 0) return; + + var chunkSection = archetypeChunk.getComponent(i, ChunkSection.getComponentType()); + if (chunkSection == null) return; + + var blockComponentChunk = commandBuffer.getComponent(chunkSection.getChunkColumnReference(), BlockComponentChunk.getComponentType()); + var worldChunk = commandBuffer.getComponent(chunkSection.getChunkColumnReference(), WorldChunk.getComponentType()); + if (blockComponentChunk == null || worldChunk == null) return; + + blockSection.forEachTicking(blockComponentChunk, commandBuffer, chunkSection.getY(), + (blockCompChunk, _, localX, localY, localZ, _) -> { + var blockRef = blockCompChunk.getEntityReference(ChunkUtil.indexBlockInColumn(localX, localY, localZ)); + if (blockRef == null) return BlockTickStrategy.IGNORED; + var thisEnergySourceComponent = commandBuffer.getComponent(blockRef, EnergySourceComponent.getComponentType()); + var thisEnergyStorageComponent = commandBuffer.getComponent(blockRef, EnergyStorageBlockComponent.getComponentType()); + if (thisEnergySourceComponent == null || thisEnergyStorageComponent == null) + return BlockTickStrategy.IGNORED; + + int globalX = localX + (worldChunk.getX() * 32); + int globalZ = localZ + (worldChunk.getZ() * 32); + + BlockHelper.executeForCubeAround(globalX, localY, globalZ, 5, false, (x, y, z) -> { + var index = ChunkUtil.indexBlockInColumn(x, y, z); + var targetRef = blockCompChunk.getEntityReference(index); + if (targetRef == null) return; + var targetEnergySource = commandBuffer.getComponent(targetRef, EnergySourceComponent.getComponentType()); + var targetEnergyStorage = commandBuffer.getComponent(targetRef, EnergyStorageBlockComponent.getComponentType()); + if (targetEnergySource == null || targetEnergyStorage == null) return; + + var energy = targetEnergyStorage.extractEnergy(targetEnergySource.getEnergyRatePerTick(), false); + var inserted = thisEnergyStorageComponent.receiveEnergy(energy, false); + LOGGER.atInfo().log("Inserted " + inserted + "/" + energy + " |" + targetEnergyStorage.getEnergyStored() + "| into storage" + + " at Block " + globalX + ", " + localY + ", " + globalZ + ", " + + thisEnergyStorageComponent.getEnergyStored() + "/" + thisEnergyStorageComponent.getMaxEnergyStored()); + }); + + return BlockTickStrategy.CONTINUE; + }); + + } + + @NullableDecl + @Override + public Query getQuery() { + return Query.and(BlockSection.getComponentType(), ChunkSection.getComponentType()); + } +} diff --git a/src/main/java/org/KaiFlo/SolarCell/Systems/EnergySource/EnergySourceInitializerSystem.java b/src/main/java/org/KaiFlo/SolarCell/Systems/EnergySource/EnergySourceInitializerSystem.java new file mode 100644 index 0000000..1a5a24e --- /dev/null +++ b/src/main/java/org/KaiFlo/SolarCell/Systems/EnergySource/EnergySourceInitializerSystem.java @@ -0,0 +1,43 @@ +package org.KaiFlo.SolarCell.Systems.EnergySource; + +import com.hypixel.hytale.component.*; +import com.hypixel.hytale.component.query.Query; +import com.hypixel.hytale.component.system.RefSystem; +import com.hypixel.hytale.logger.HytaleLogger; +import com.hypixel.hytale.math.util.ChunkUtil; +import com.hypixel.hytale.server.core.modules.block.BlockModule; +import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk; +import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; +import org.KaiFlo.SolarCell.Components.EnergySource.Implementations.EnergySourceComponent; +import org.checkerframework.checker.nullness.compatqual.NonNullDecl; +import org.checkerframework.checker.nullness.compatqual.NullableDecl; + +public class EnergySourceInitializerSystem extends RefSystem { + @Override + public void onEntityAdded(@NonNullDecl Ref ref, @NonNullDecl AddReason addReason, @NonNullDecl Store store, @NonNullDecl CommandBuffer commandBuffer) { + BlockModule.BlockStateInfo blockInfo = commandBuffer.getComponent(ref, BlockModule.BlockStateInfo.getComponentType()); + if(blockInfo == null) return; + + WorldChunk worldChunk = commandBuffer.getComponent(blockInfo.getChunkRef(), WorldChunk.getComponentType()); + if(worldChunk == null) return; + + int x = ChunkUtil.xFromBlockInColumn(blockInfo.getIndex()); + int y = ChunkUtil.yFromBlockInColumn(blockInfo.getIndex()); + int z = ChunkUtil.zFromBlockInColumn(blockInfo.getIndex()); + + worldChunk.setTicking(x, y, z, true); + HytaleLogger.getLogger().atInfo().log(String.valueOf(worldChunk.isTicking(x, y, z))); + } + + + @Override + public void onEntityRemove(@NonNullDecl Ref ref, @NonNullDecl RemoveReason removeReason, @NonNullDecl Store store, @NonNullDecl CommandBuffer commandBuffer) { + //Nothing to do yet + } + + @NullableDecl + @Override + public Query getQuery() { + return Query.and(EnergySourceComponent.getComponentType(), BlockModule.BlockStateInfo.getComponentType()); + } +} diff --git a/src/main/resources/Server/Item/Items/SolarCell.json b/src/main/resources/Server/Item/Items/SolarCell.json new file mode 100644 index 0000000..1eead07 --- /dev/null +++ b/src/main/resources/Server/Item/Items/SolarCell.json @@ -0,0 +1,72 @@ +{ + "TranslationProperties": { + "Name": "server.items.Rock_Stone.name" + }, + "ItemLevel": 10, + "MaxStack": 100, + "Icon": "Icons/ItemsGenerated/Rock_Stone_Stalactite_Small.png", + "Categories": [ + "Blocks.Rocks" + ], + "PlayerAnimationsId": "Block", + "Set": "Rock_Stone", + "BlockType": { + "Material": "Solid", + "DrawType": "Cube", + "Group": "Stone", + "Flags": {}, + "Gathering": { + "Breaking": { + "GatherType": "Rocks", + "ItemId": "Rock_Stone_Cobble" + } + }, + "BlockParticleSetId": "Stone", + "Textures": [ + { + "All": "BlockTextures/Rock_Stone.png", + "Weight": 2 + }, + { + "All": "BlockTextures/Rock_Stone_2.png", + "Weight": 1 + }, + { + "All": "BlockTextures/Rock_Stone_3.png", + "Weight": 1 + } + ], + "ParticleColor": "#737055", + "BlockSoundSetId": "Stone", + "Aliases": [ + "stone", + "stone00" + ], + "BlockBreakingDecalId": "Breaking_Decals_Rock", + "BlockEntity": { + "Components": { + "SolarCell": {}, + "EnergyStorageComponent": { + "EnergyStored": 5, + "MaxEnergy": 80000, + "MaxReceive": 1000, + "MaxExtract": 1000 + } + } + } + }, + "ResourceTypes": [ + { + "Id": "Rock" + }, + { + "Id": "Rock_Stone" + } + ], + "Tags": { + "Type": [ + "Rock" + ] + }, + "ItemSoundSetId": "ISS_Blocks_Stone" +} diff --git a/src/main/resources/manifest.json b/src/main/resources/manifest.json index 0773ced..675ff8e 100644 --- a/src/main/resources/manifest.json +++ b/src/main/resources/manifest.json @@ -14,7 +14,8 @@ "Website": "https://github.com/KainTim/hytale-solar-cell-plugin", "ServerVersion": "*", "Dependencies": { - + "Hytale:EntityModule": "*", + "Hytale:BlockModule": "*" }, "OptionalDependencies": {