This commit is contained in:
Flotschispielt
2026-02-07 13:11:53 +01:00
10 changed files with 332 additions and 45 deletions

View File

@@ -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<EntityStore> 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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}

View File

@@ -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<ChunkStore> {
public static final BuilderCodec<EnergySourceComponent> CODEC = BuilderCodec.builder(EnergySourceComponent.class, EnergySourceComponent::new).build();
private final HytaleLogger Logger = HytaleLogger.getLogger();
private long energyRatePerTick = 5;
public static ComponentType<ChunkStore, EnergySourceComponent> getComponentType() {
return SolarCellPlugin.get().getSolarCellComponentType();
}
private EnergySourceComponent copyFrom(EnergySourceComponent other) {
this.energyRatePerTick = other.energyRatePerTick;
return this;
}
@NullableDecl
@Override
public Component<ChunkStore> 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;
}
}

View File

@@ -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);
}
}

View File

@@ -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<ChunkStore, EnergySourceComponent> 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<ChunkStore, EnergySourceComponent> getSolarCellComponentType() {
return solarCellComponentType;
}
}

View File

@@ -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<ChunkStore> {
private final HytaleLogger LOGGER = HytaleLogger.getLogger();
@Override
public void tick(float v, int i, @NonNullDecl ArchetypeChunk<ChunkStore> archetypeChunk, @NonNullDecl Store<ChunkStore> store, @NonNullDecl CommandBuffer<ChunkStore> 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<ChunkStore> getQuery() {
return Query.and(BlockSection.getComponentType(), ChunkSection.getComponentType());
}
}

View File

@@ -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<ChunkStore> {
@Override
public void onEntityAdded(@NonNullDecl Ref<ChunkStore> ref, @NonNullDecl AddReason addReason, @NonNullDecl Store<ChunkStore> store, @NonNullDecl CommandBuffer<ChunkStore> 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<ChunkStore> getQuery() {
return Query.and(EnergySourceComponent.getComponentType(), BlockModule.BlockStateInfo.getComponentType());
}
}

View File

@@ -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"
}

View File

@@ -14,7 +14,8 @@
"Website": "https://github.com/KainTim/hytale-solar-cell-plugin",
"ServerVersion": "*",
"Dependencies": {
"Hytale:EntityModule": "*",
"Hytale:BlockModule": "*"
},
"OptionalDependencies": {