Compare commits
75 Commits
471921c774
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| a65cb6f261 | |||
| d5202067d1 | |||
| a362658371 | |||
| 97ed29fc23 | |||
| 1c03653fee | |||
| c016cebb0f | |||
| 885f594ca0 | |||
| 45831b780a | |||
| 6b0c4468ec | |||
| d15b34939e | |||
| 3f95944314 | |||
| 21493fec04 | |||
| 42331390e7 | |||
| cdb98bd85e | |||
| 7f58fdf55b | |||
| 17bc614eb9 | |||
| b78cc44d89 | |||
| 4d37483057 | |||
| 4d84ec2ed4 | |||
| 5249832bd6 | |||
| e9885940e2 | |||
| c63912c1f3 | |||
| 323d213291 | |||
| b8968942f8 | |||
| 0eee9f5163 | |||
| 9fd6ea8881 | |||
| c6fc9ed9e9 | |||
| 9ea3727dfb | |||
| 21516ee923 | |||
| d8e79d8719 | |||
| 5dbd0b8734 | |||
| 710547a014 | |||
| 424f77ba10 | |||
| 02c0c5d60c | |||
| 0b33eda8a8 | |||
| cd909dbd80 | |||
| 8fb4921e30 | |||
| 86b3486622 | |||
| 9a733e0a81 | |||
| 740318c020 | |||
| 149cfec3ed | |||
| 4d2cb14e45 | |||
| 7c27955c14 | |||
| 71899c0013 | |||
| ced17282f9 | |||
| a57fca82e5 | |||
| 3b7e2b02b6 | |||
| c968b97faf | |||
| 6ef6826483 | |||
| ba826b47a8 | |||
| 02114fc02a | |||
| 9ac53a0f0e | |||
| 1f1a456f1d | |||
| 43255b1caf | |||
| 464584877c | |||
| 79053b277a | |||
| 80130a68e1 | |||
| fc8a4aaa58 | |||
| cb380880e4 | |||
| 26ec989a4c | |||
| 883833351c | |||
| 400a773a04 | |||
| 6532fea543 | |||
| b39d016feb | |||
| 477abfd80b | |||
| 8edd36124b | |||
| ed6ddddf98 | |||
| 83749bf3ba | |||
| f3280f83d1 | |||
| 88ffaf7a22 | |||
| 8004658a0a | |||
| a8b45c6565 | |||
| ab0a484021 | |||
| f9ddc36611 | |||
| a591c9da6f |
35
TODO.md
Normal file
35
TODO.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Networking
|
||||
> All that is left is optimization
|
||||
|
||||
## Mergeable device nodes
|
||||
|
||||
For optimization of screen grouping and cables, we should add a system that allows merging nodes
|
||||
|
||||
## Copy the networking optimizations of OC
|
||||
> https://github.com/MightyPirates/OpenComputers/blob/master-MC1.7.10/src/main/scala/li/cil/oc/server/network/Network.scala
|
||||
|
||||
We should implement this, as it not only makes behavior match better, but also optimizes
|
||||
it a lot. We do need to replace the NEIGHBORS rule with implementing the SOME visibility.
|
||||
A direct port is not needed, just taking heavy inspiration from OC.
|
||||
|
||||
## Optimize power balancing
|
||||
|
||||
Use a smarter algorithm to prevent N storage nodes from iterating N^2 nodes each tick
|
||||
to balance power.
|
||||
|
||||
# Computation
|
||||
> Pretty important for a computer mod
|
||||
|
||||
## JNI
|
||||
|
||||
We need the JNI system so we can salvage our hard labor thrown into NeoNucleus.
|
||||
Also because it is a capable engine and has a good API for architectures, and NCL is very capable.
|
||||
|
||||
## Worker threads
|
||||
|
||||
Computers need worker threads for running non-synchronized code, because otherwise we're cooked
|
||||
|
||||
## Entities as machines
|
||||
|
||||
Aside from blocks like cases and robots, we should also support entities like drones.
|
||||
Not only for OC parity, but also as addons would def love that.
|
||||
@@ -26,9 +26,16 @@ base {
|
||||
archivesName.set("${mod.id}-$loader")
|
||||
}
|
||||
|
||||
//val foid = ["forge", "fabric", "neoforge"]
|
||||
//architectury.common(foid)
|
||||
//architectury.common(["forge", "fabric"])
|
||||
//println(stonecutter.current.project.split('-').subList(1, 2))
|
||||
//architectury.common(stonecutter.current.project.split('-').subList(1, 2))
|
||||
//architectury.common(stonecutter.current.version)
|
||||
architectury.common(stonecutter.tree.branches.mapNotNull {
|
||||
if (stonecutter.current.project !in it) null
|
||||
else it.prop("loom.platform")
|
||||
// println(stonecutter.current.project !in it)
|
||||
if (stonecutter.current.project !in it) return null
|
||||
else return it.prop("loom.platform")
|
||||
})
|
||||
|
||||
repositories {
|
||||
@@ -118,8 +125,8 @@ dependencies {
|
||||
// }
|
||||
// })
|
||||
|
||||
if (minecraft=="1.21.9" || minecraft=="1.21.11") modApi("dev.architectury:architectury-neoforge:${archversion}")
|
||||
else modApi("dev.architectury:architectury-forge:${archversion}") // NOTE: this could be wrong
|
||||
if (minecraft=="1.21.1" || minecraft=="1.21.9" || minecraft=="1.21.11") modApi("dev.architectury:architectury-neoforge:${archversion}")
|
||||
else modApi("dev.architectury:architectury-neoforge:${archversion}") // NOTE: this could be wrong
|
||||
implementation("thedarkcolour:kotlinforforge-neoforge:6.0.0")
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ stonecutter {
|
||||
mc("forge", "1.20.1")
|
||||
//WARNING: neoforge uses mods.toml instead of neoforge.mods.toml for versions 1.20.4 (?) and earlier
|
||||
//mc("neoforge", "1.20.4", "1.21.1", "1.21.3", "1.21.4", "1.21.5", "1.21.6", "1.21.7", "1.21.8", "1.21.9", "1.21.10", "1.21.11")
|
||||
mc("neoforge", "1.20.4", "1.21.9", "1.21.11")
|
||||
mc("neoforge", "1.20.4", "1.21.1", "1.21.9", "1.21.11")
|
||||
}
|
||||
create(rootProject)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//? if fabric {
|
||||
package org.neoflock.neocomputers.platforms.fabric;
|
||||
/*package org.neoflock.neocomputers.platforms.fabric;
|
||||
|
||||
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
|
||||
import com.terraformersmc.modmenu.api.ModMenuApi;
|
||||
@@ -10,4 +10,4 @@ public class ModMenuIntegration implements ModMenuApi {
|
||||
return ConfigScreen::createConfigScreen;
|
||||
}
|
||||
}
|
||||
//?}
|
||||
*///?}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//? if fabric {
|
||||
package org.neoflock.neocomputers.platforms.fabric;
|
||||
/*package org.neoflock.neocomputers.platforms.fabric;
|
||||
|
||||
import org.neoflock.neocomputers.ModPlatform;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
@@ -24,4 +24,4 @@ public class NeoComputersFabric implements ModInitializer {
|
||||
}
|
||||
}
|
||||
}
|
||||
//?}
|
||||
*///?}
|
||||
@@ -1,15 +1,37 @@
|
||||
package org.neoflock.neocomputers.platforms.fabric.client;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry;
|
||||
import net.minecraft.client.color.item.ItemColor;
|
||||
import net.minecraft.client.color.item.ItemColors;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.DyeColor;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import org.neoflock.neocomputers.NeoComputers;
|
||||
import org.neoflock.neocomputers.block.Blocks;
|
||||
import org.neoflock.neocomputers.block.CableBlock;
|
||||
import org.neoflock.neocomputers.entity.BlockEntities;
|
||||
import org.neoflock.neocomputers.gui.render.CaseEntityRenderer;
|
||||
import org.neoflock.neocomputers.gui.render.ScreenEntityRenderer;
|
||||
import org.neoflock.neocomputers.entity.render.*;
|
||||
import org.neoflock.neocomputers.item.Items;
|
||||
import org.neoflock.neocomputers.platforms.fabric.client.model.ModelLoader;
|
||||
|
||||
public class NeoComputersFabricClient implements ClientModInitializer {
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
BlockEntityRenderers.register(BlockEntities.INSTANCE.getSCREEN_ENTITY().get(), ScreenEntityRenderer::new);
|
||||
BlockEntityRenderers.register(BlockEntities.INSTANCE.getCASE_ENTITY().get(), CaseEntityRenderer::new);
|
||||
ModelLoadingPlugin.register(new ModelLoader());
|
||||
|
||||
ColorProviderRegistry.BLOCK.register((state, world, pos, index) -> {
|
||||
if (index == 0) {
|
||||
return state.getValue(CableBlock.Companion.getCOLOR()).getTextureDiffuseColor();
|
||||
} else {
|
||||
return 0xFFFFFF;
|
||||
}
|
||||
}, Blocks.INSTANCE.getCABLE_BLOCK().get());
|
||||
|
||||
ColorProviderRegistry.ITEM.register((stack, index)-> {
|
||||
return DyeColor.LIGHT_GRAY.getTextureDiffuseColor();
|
||||
}, Items.INSTANCE.getITEMS().getRegistrar().get(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "cable")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package org.neoflock.neocomputers.platforms.fabric.client.model;
|
||||
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
|
||||
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||
import net.fabricmc.fabric.impl.renderer.VanillaModelEncoder;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlas;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.resources.model.*;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.neoflock.neocomputers.NeoComputers;
|
||||
import org.neoflock.neocomputers.block.model.AbstractModel;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class FabricModelWrapper implements FabricBakedModel, UnbakedModel {
|
||||
private AbstractModel model;
|
||||
|
||||
public FabricModelWrapper(AbstractModel model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier<RandomSource> randomSupplier, RenderContext context) {
|
||||
VanillaModelEncoder.emitBlockQuads(model, state, randomSupplier, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitItemQuads(ItemStack stack, Supplier<RandomSource> randomSupplier, RenderContext context) {
|
||||
VanillaModelEncoder.emitItemQuads(model, null, randomSupplier, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourceLocation> getDependencies() {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolveParents(Function<ResourceLocation, UnbakedModel> resolver) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable BakedModel bake(ModelBaker baker, Function<Material, TextureAtlasSprite> spriteGetter, ModelState state) {
|
||||
// NeoComputers.INSTANCE.getLOGGER().info("{}", spriteGetter.apply(new Material()));
|
||||
model._bake(spriteGetter);
|
||||
// model.bake((Function1<? super ResourceLocation, ? extends TextureAtlasSprite>) Minecraft.getInstance().getTextureAtlas(TextureAtlas.LOCATION_BLOCKS));
|
||||
return model;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.neoflock.neocomputers.platforms.fabric.client.model;
|
||||
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.neoflock.neocomputers.NeoComputers;
|
||||
import org.neoflock.neocomputers.block.model.RobotModel;
|
||||
|
||||
public class ModelLoader implements ModelLoadingPlugin {
|
||||
public static final ResourceLocation ROBOT = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "robot");
|
||||
|
||||
@Override
|
||||
public void onInitializeModelLoader(Context pluginContext) {
|
||||
pluginContext.modifyModelOnLoad().register((original, context) -> {
|
||||
final ModelResourceLocation id = context.topLevelId();
|
||||
if (id != null && id.id().equals(ROBOT)) {
|
||||
return new FabricModelWrapper(new RobotModel());
|
||||
}
|
||||
return original;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//? if neoforge {
|
||||
/*package org.neoflock.neocomputers.platforms.neoforge;
|
||||
package org.neoflock.neocomputers.platforms.neoforge;
|
||||
|
||||
import org.neoflock.neocomputers.ConfigScreen;
|
||||
import org.neoflock.neocomputers.ModPlatform;
|
||||
@@ -8,8 +8,8 @@ import net.neoforged.fml.ModLoadingContext;
|
||||
import net.neoforged.fml.common.Mod;
|
||||
import org.neoflock.neocomputers.NeoComputers;
|
||||
//? if <1.21 {
|
||||
/^import net.neoforged.neoforge.client.ConfigScreenHandler;
|
||||
^///?} else {
|
||||
/*import net.neoforged.neoforge.client.ConfigScreenHandler;
|
||||
*///?} else {
|
||||
import net.neoforged.neoforge.client.gui.IConfigScreenFactory;
|
||||
//?}
|
||||
@Mod("neocomputers")
|
||||
@@ -18,11 +18,11 @@ public class NeoComputersNeoForge {
|
||||
NeoComputers.INSTANCE.entrypoint(new NeoForgePlatform());
|
||||
ModLoadingContext.get().registerExtensionPoint(
|
||||
//? if <1.21 {
|
||||
/^ConfigScreenHandler.ConfigScreenFactory.class,
|
||||
/*ConfigScreenHandler.ConfigScreenFactory.class,
|
||||
() -> new ConfigScreenHandler.ConfigScreenFactory(
|
||||
((client, parent) -> ConfigScreen.createConfigScreen(parent))
|
||||
)
|
||||
^///?} else {
|
||||
*///?} else {
|
||||
IConfigScreenFactory.class,
|
||||
() -> (client, parent) -> ConfigScreen.createConfigScreen(parent)
|
||||
//?}
|
||||
@@ -40,4 +40,4 @@ public class NeoComputersNeoForge {
|
||||
}
|
||||
}
|
||||
}
|
||||
*///?}
|
||||
//?}
|
||||
@@ -1,7 +1,5 @@
|
||||
package org.neoflock.neocomputers
|
||||
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat
|
||||
import com.mojang.blaze3d.vertex.VertexFormat
|
||||
import dev.architectury.event.events.client.ClientLifecycleEvent
|
||||
import dev.architectury.event.events.common.LifecycleEvent
|
||||
import dev.architectury.event.events.common.PlayerEvent
|
||||
@@ -15,24 +13,22 @@ import org.neoflock.neocomputers.gui.menu.Menus
|
||||
import dev.architectury.utils.Env
|
||||
import dev.architectury.utils.EnvExecutor
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.renderer.RenderStateShard
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderers
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import org.neoflock.neocomputers.block.NodeBlockEntity
|
||||
import org.neoflock.neocomputers.block.NodeSynchronizer
|
||||
import org.neoflock.neocomputers.gui.buffer.BufferRenderer
|
||||
import org.neoflock.neocomputers.block.DeviceBlockEntity
|
||||
import org.neoflock.neocomputers.entity.render.EntityRenderers
|
||||
import org.neoflock.neocomputers.gui.render.ScreenRenderer
|
||||
import org.neoflock.neocomputers.gui.widget.ComponentRoles
|
||||
import org.neoflock.neocomputers.item.GPUCard
|
||||
import org.neoflock.neocomputers.item.Items
|
||||
import org.neoflock.neocomputers.item.Tabs
|
||||
import org.neoflock.neocomputers.network.DeviceNode
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
import org.neoflock.neocomputers.network.NodeSynchronizer
|
||||
import org.neoflock.neocomputers.sounds.Sounds
|
||||
import org.neoflock.neocomputers.utils.FontProvider
|
||||
import org.neoflock.neocomputers.utils.GenericContainerScreen
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.nio.Buffer
|
||||
|
||||
object NeoComputers {
|
||||
const val MODID: String = "neocomputers"
|
||||
@@ -58,22 +54,17 @@ object NeoComputers {
|
||||
Tabs.TABS.register()
|
||||
Sounds.SOUNDS.register()
|
||||
ComponentRoles.mapDefaultTextures()
|
||||
// i dont know why architectury wants two lambdas but whatever
|
||||
// I don't know why architectury wants two lambdas but whatever
|
||||
EnvExecutor.runInEnv(Env.CLIENT) {{
|
||||
ClientLifecycleEvent.CLIENT_SETUP.register {
|
||||
Menus.registerScreens()
|
||||
Networking.allNodes.remove()
|
||||
Networking.wirelessNodes.remove()
|
||||
Networking.channels.remove()
|
||||
EntityRenderers.registerBlockEntityRenderers()
|
||||
}
|
||||
ClientLifecycleEvent.CLIENT_STARTED.register {
|
||||
FontProvider.load(ResourceLocation.fromNamespaceAndPath(MODID, "font/unscii.hex"))
|
||||
ScreenRenderer.genUnboundTex();
|
||||
|
||||
var buffer: MutableList<BufferRenderer.GPUChar> = mutableListOf(BufferRenderer.GPUChar('h'), BufferRenderer.GPUChar('i'))
|
||||
for (i in 0..398) {
|
||||
buffer.add(BufferRenderer.GPUChar(' '))
|
||||
}
|
||||
|
||||
var renderer: BufferRenderer = BufferRenderer(20, 20, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "screen/test"), buffer)
|
||||
renderer.drawBuffer()
|
||||
}
|
||||
|
||||
ClientLifecycleEvent.CLIENT_STOPPING.register {
|
||||
@@ -96,12 +87,6 @@ object NeoComputers {
|
||||
Networking.channels.remove()
|
||||
}
|
||||
|
||||
ClientLifecycleEvent.CLIENT_STARTED.register {
|
||||
Networking.allNodes.remove()
|
||||
Networking.wirelessNodes.remove()
|
||||
Networking.channels.remove()
|
||||
}
|
||||
|
||||
PlayerEvent.CLOSE_MENU.register {
|
||||
player, menu ->
|
||||
if(player is ServerPlayer) NodeSynchronizer.playerScreenClosed(player)
|
||||
@@ -120,19 +105,35 @@ object NeoComputers {
|
||||
packet, ctx ->
|
||||
val player = ctx.player
|
||||
if(player is ServerPlayer) {
|
||||
NodeSynchronizer.screenMap[player]?.processScreenInteraction(player, packet.buffer)
|
||||
val ent = NodeSynchronizer.screenMap[player]
|
||||
if(ent is DeviceNode) {
|
||||
ent.processScreenInteraction(player, packet.buffer)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
NetworkManager.registerReceiver(NetworkManager.c2s(),NodeSynchronizer.DeviceBlockStateRequest.TYPE, NodeSynchronizer.DeviceBlockStateRequest.CODEC, {
|
||||
packet, ctx ->
|
||||
val player = ctx.player
|
||||
val level = player.level()
|
||||
val dist = packet.blockPos.center.distanceTo(player.position())
|
||||
if(player is ServerPlayer && dist <= NodeSynchronizer.MAX_STATE_DISTANCE_ALLOWED) {
|
||||
val ent = level.getBlockEntity(packet.blockPos)
|
||||
if(ent is DeviceBlockEntity) {
|
||||
ent.sendStateToPlayer(player)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// we have to do this because the datagen task runs in the physical server
|
||||
EnvExecutor.runInEnv(Env.CLIENT) {{
|
||||
NetworkManager.registerReceiver(NetworkManager.s2c(),NodeSynchronizer.StatePayload.TYPE, NodeSynchronizer.StatePayload.CODEC, {
|
||||
NetworkManager.registerReceiver(NetworkManager.s2c(),NodeSynchronizer.DeviceBlockStatePayload.TYPE, NodeSynchronizer.DeviceBlockStatePayload.CODEC, {
|
||||
packet, ctx ->
|
||||
val level = ctx.player.level()
|
||||
val ent = level.getBlockEntity(packet.blockPos)
|
||||
if(ent is NodeBlockEntity) {
|
||||
ent.syncWithUpstream(packet.buffer)
|
||||
if(ent is DeviceBlockEntity) {
|
||||
ent.processCommits(packet.buffers)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -152,7 +153,7 @@ object NeoComputers {
|
||||
}}
|
||||
EnvExecutor.runInEnv(Env.SERVER) {{
|
||||
// https://github.com/architectury/architectury-api/issues/518
|
||||
NetworkManager.registerS2CPayloadType(NodeSynchronizer.StatePayload.TYPE, NodeSynchronizer.StatePayload.CODEC)
|
||||
NetworkManager.registerS2CPayloadType(NodeSynchronizer.DeviceBlockStatePayload.TYPE, NodeSynchronizer.DeviceBlockStatePayload.CODEC)
|
||||
NetworkManager.registerS2CPayloadType(NodeSynchronizer.ScreenPayload.TYPE, NodeSynchronizer.ScreenPayload.CODEC)
|
||||
NetworkManager.registerS2CPayloadType(NodeSynchronizer.BeepDataPayload.TYPE, NodeSynchronizer.BeepDataPayload.CODEC)
|
||||
}}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.neoflock.neocomputers.block
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.level.block.EntityBlock
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import org.neoflock.neocomputers.entity.AssemblerEntity
|
||||
|
||||
class AssemblerBlock : BaseBlock(), EntityBlock { // TODO: component stuff
|
||||
override fun newBlockEntity(
|
||||
pos: BlockPos,
|
||||
state: BlockState
|
||||
): BlockEntity? {
|
||||
return AssemblerEntity(pos, state)
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import dev.architectury.registry.registries.DeferredRegister
|
||||
import dev.architectury.registry.registries.Registrar
|
||||
import dev.architectury.registry.registries.RegistrarManager
|
||||
import dev.architectury.registry.registries.RegistrySupplier
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.resources.ResourceKey
|
||||
@@ -33,6 +34,11 @@ object Blocks {
|
||||
val COMBUSTGEN_BLOCK: RegistrySupplier<Block> = BaseBlock.register("combustgen") { CombustionGeneratorBlock() }
|
||||
val CASE_BLOCK: RegistrySupplier<Block> = BaseBlock.register("case") { CaseBlock() }
|
||||
val REDSTONEIO_BLOCK: RegistrySupplier<Block> = BaseBlock.register("redio") { RedstoneIOBlock() }
|
||||
val CABLE_BLOCK: RegistrySupplier<Block> = BaseBlock.register("cable") { CableBlock() }
|
||||
val RELAY_BLOCK: RegistrySupplier<Block> = BaseBlock.register("relay") { RelayBlock() }
|
||||
val ROBOT_BLOCK: RegistrySupplier<Block> = BaseBlock.register("robot") { RobotBlock() }
|
||||
val RACK_BLOCK: RegistrySupplier<Block> = BaseBlock.register("rack") { RackBlock() }
|
||||
val ASSEMBLER_BLOCK: RegistrySupplier<Block> = BaseBlock.register("assembler") { AssemblerBlock() }
|
||||
|
||||
fun registerBlockItems() {
|
||||
BLOCKS.forEach(Consumer { sup: RegistrySupplier<Block> ->
|
||||
|
||||
176
src/main/kotlin/org/neoflock/neocomputers/block/CableBlock.kt
Normal file
176
src/main/kotlin/org/neoflock/neocomputers/block/CableBlock.kt
Normal file
@@ -0,0 +1,176 @@
|
||||
package org.neoflock.neocomputers.block
|
||||
|
||||
import net.minecraft.client.renderer.blockentity.PistonHeadRenderer
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.ItemInteractionResult
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.DyeColor
|
||||
import net.minecraft.world.item.DyeItem
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.EntityBlock
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.StateDefinition
|
||||
import net.minecraft.world.level.block.state.properties.BooleanProperty
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import net.minecraft.world.phys.shapes.BooleanOp
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.entity.CableEntity
|
||||
|
||||
class CableBlock() : DeviceBlock(Properties.of()), EntityBlock {
|
||||
companion object {
|
||||
val NORTH = BooleanProperty.create("north")
|
||||
val EAST = BooleanProperty.create("east")
|
||||
val WEST = BooleanProperty.create("west")
|
||||
val SOUTH = BooleanProperty.create("south")
|
||||
val UP = BooleanProperty.create("up")
|
||||
val DOWN = BooleanProperty.create("down")
|
||||
|
||||
val COLOR = EnumProperty<DyeColor>.create("color", DyeColor::class.java)
|
||||
|
||||
val MIN = 0.375
|
||||
val MAX = 1-MIN
|
||||
|
||||
val shapeCache: Array<VoxelShape?> = arrayOfNulls(Direction.entries.size*Direction.entries.size*Direction.entries.size*Direction.entries.size*Direction.entries.size*Direction.entries.size)
|
||||
|
||||
fun calcIdx(north: Boolean, south: Boolean, east: Boolean, west: Boolean, up: Boolean, down: Boolean): Int {
|
||||
var idx = if (down) 1 else 0
|
||||
idx += 2*(if (up) 1 else 0)
|
||||
idx += 4*(if (west) 1 else 0)
|
||||
idx += 8*(if (east) 1 else 0)
|
||||
idx += 16*(if (south) 1 else 0)
|
||||
idx += 32*(if (north) 1 else 0)
|
||||
return idx
|
||||
}
|
||||
|
||||
fun makeShapes() {
|
||||
NeoComputers.LOGGER.info("[CABLE] recomputing shapes")
|
||||
for (north in arrayOf(false, true)) { // shut up
|
||||
for (south in arrayOf(false, true)) {
|
||||
for (east in arrayOf(false, true)) {
|
||||
for (west in arrayOf(false, true)) {
|
||||
for (up in arrayOf(false, true)) {
|
||||
for (down in arrayOf(false, true)) {
|
||||
val shape = makeShape(north, south, east, west, up, down)
|
||||
val idx = calcIdx(north, south, east,west, up, down)
|
||||
shapeCache[idx] = shape;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun makeShape(north: Boolean, south: Boolean, east: Boolean, west: Boolean, up: Boolean, down: Boolean): VoxelShape {
|
||||
var shape = Shapes.box(MIN, MIN, MIN, MAX, MAX, MAX)
|
||||
if (north) shape = Shapes.join(shape, Shapes.box(MIN, MIN, 0.0, MAX, MAX, MIN ), BooleanOp.OR)
|
||||
if (south) shape = Shapes.join(shape, Shapes.box(MIN, MIN, MAX, MAX, MAX, 1.0 ), BooleanOp.OR)
|
||||
if (east) shape = Shapes.join(shape, Shapes.box(MAX, MIN, MIN, 1.0, MAX, MAX), BooleanOp.OR)
|
||||
if (west) shape = Shapes.join(shape, Shapes.box(0.0, MIN, MIN, MIN, MAX, MAX ), BooleanOp.OR)
|
||||
if (up) shape = Shapes.join(shape, Shapes.box(MIN, MAX, MIN, MAX, 1.0, MAX), BooleanOp.OR)
|
||||
if (down) shape = Shapes.join(shape, Shapes.box(MIN, 0.0, MIN, MAX, MIN, MAX ), BooleanOp.OR)
|
||||
return shape
|
||||
}
|
||||
|
||||
fun getPropByDirection(direction: Direction): BooleanProperty {
|
||||
return when (direction) {
|
||||
Direction.NORTH -> NORTH
|
||||
Direction.SOUTH -> SOUTH
|
||||
Direction.WEST -> WEST
|
||||
Direction.EAST -> EAST
|
||||
Direction.UP -> UP
|
||||
Direction.DOWN -> DOWN
|
||||
}
|
||||
}
|
||||
fun shouldConnect(pos: BlockPos, npos: BlockPos, level: Level): Boolean {
|
||||
val ent = level.getBlockEntity(npos)
|
||||
val blockState = level.getBlockState(pos)
|
||||
val theirState = level.getBlockState(npos)
|
||||
|
||||
val universal = DyeColor.LIGHT_GRAY
|
||||
if(ent is CableEntity) {
|
||||
val ourColor = blockState.getValue(COLOR)
|
||||
val theirColor = theirState.getValue(COLOR)
|
||||
|
||||
if(ourColor.equals(universal)) return true
|
||||
if(theirColor.equals(universal)) return true
|
||||
if(ourColor.equals(theirColor)) return true
|
||||
return false
|
||||
}
|
||||
|
||||
return ent is DeviceBlockEntity
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
registerDefaultState(stateDefinition.any()
|
||||
.setValue(NORTH, false)
|
||||
.setValue(EAST, false)
|
||||
.setValue(WEST, false)
|
||||
.setValue(SOUTH, false)
|
||||
.setValue(UP, false)
|
||||
.setValue(DOWN, false)
|
||||
.setValue(COLOR, DyeColor.LIGHT_GRAY)
|
||||
)
|
||||
makeShapes()
|
||||
}
|
||||
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block?, BlockState?>) {
|
||||
super.createBlockStateDefinition(builder
|
||||
.add(NORTH)
|
||||
.add(EAST)
|
||||
.add(SOUTH)
|
||||
.add(WEST)
|
||||
.add(UP)
|
||||
.add(DOWN)
|
||||
.add(COLOR))
|
||||
}
|
||||
|
||||
override fun newBlockEntity(pos: BlockPos, state: BlockState) = CableEntity(pos, state)
|
||||
|
||||
override fun getShape(state: BlockState, level: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape? {
|
||||
val idx = calcIdx(state.getValue(NORTH), state.getValue(SOUTH), state.getValue(EAST), state.getValue(WEST), state.getValue(UP), state.getValue(DOWN))
|
||||
return shapeCache[idx];
|
||||
// return makeShape(state.getValue(NORTH), state.getValue(SOUTH), state.getValue(EAST), state.getValue(WEST), state.getValue(UP), state.getValue(DOWN))
|
||||
}
|
||||
|
||||
override fun neighborChanged(state: BlockState, level: Level, pos: BlockPos, neighborBlock: Block, neighborPos: BlockPos, movedByPiston: Boolean) {
|
||||
// val neighbors = getNeighbourEntities(blockPos, level)
|
||||
// for (dir in Direction.entries) {
|
||||
// val ent = level.getBlockEntity(blockPos.relative(dir))
|
||||
// level.setBlockAndUpdate(blockPos, blockState.setValue(getPropByDirection(dir), (ent is NodeBlockEntity || ent is CableEntity)))
|
||||
// }
|
||||
super.neighborChanged(state, level, pos, neighborBlock, neighborPos, movedByPiston)
|
||||
val diff = pos.subtract(neighborPos)
|
||||
val dir = Direction.fromDelta(diff.x, diff.y, diff.z)!!.opposite
|
||||
val ent = level.getBlockEntity(neighborPos)
|
||||
// val value = ent is NodeBlockEntity || (ent is CableEntity && (level.getBlockState(neighborPos).getValue(COLOR).equals(state.getValue(COLOR)) || state.getValue(COLOR).equals(DyeColor.LIGHT_GRAY)))
|
||||
level.setBlockAndUpdate(pos, state.setValue(getPropByDirection(dir), shouldConnect(pos, neighborPos, level)))
|
||||
}
|
||||
|
||||
override fun useItemOn(stack: ItemStack, state: BlockState, level: Level, pos: BlockPos, player: Player, hand: InteractionHand, hitResult: BlockHitResult): ItemInteractionResult? {
|
||||
// return super.useItemOn(stack, state, level, pos, player, hand, hitResult)
|
||||
if (stack.item is DyeItem) {
|
||||
val dyeitem = stack.item as DyeItem
|
||||
level.setBlockAndUpdate(pos, state.setValue(COLOR, dyeitem.dyeColor))
|
||||
val ent = level.getBlockEntity(pos)
|
||||
if(ent is CableEntity) {
|
||||
ent.connectionsAreDirty = true
|
||||
}
|
||||
return ItemInteractionResult.SUCCESS
|
||||
}
|
||||
return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION
|
||||
}
|
||||
}
|
||||
@@ -1,41 +1,53 @@
|
||||
package org.neoflock.neocomputers.block
|
||||
|
||||
import net.minecraft.client.player.LocalPlayer
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.HolderLookup
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.network.chat.ChatType
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.chat.OutgoingChatMessage
|
||||
import net.minecraft.network.chat.PlayerChatMessage
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import org.neoflock.neocomputers.entity.BlockEntities
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
import org.neoflock.neocomputers.network.DeviceNode
|
||||
import org.neoflock.neocomputers.network.PowerRole
|
||||
import kotlin.math.min
|
||||
|
||||
open class CapacitorEntity(val capacity: Long, type: BlockEntityType<*>, pos: BlockPos, state: BlockState) : NodeBlockEntity(type, pos, state) {
|
||||
open class CapacitorEntity(val capacity: Long, type: BlockEntityType<*>, pos: BlockPos, state: BlockState) : DeviceBlockEntity(type, pos, state) {
|
||||
|
||||
override val node = object : Networking.Node() {
|
||||
val deviceNode = object : DeviceNode() {
|
||||
override var powerRole = PowerRole.STORAGE
|
||||
override var energyCapacity: Long = capacity
|
||||
|
||||
override fun writeFullStateCommit(buf: FriendlyByteBuf) {
|
||||
super.writeFullStateCommit(buf)
|
||||
buf.writeVarLong(energy)
|
||||
}
|
||||
|
||||
override fun processCommit(buf: FriendlyByteBuf) {
|
||||
super.processCommit(buf)
|
||||
energy = buf.readVarLong()
|
||||
}
|
||||
}
|
||||
|
||||
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
|
||||
super.loadAdditional(compoundTag, provider)
|
||||
node.energy = min(compoundTag.getLong("energy"), node.energyCapacity)
|
||||
// TODO: cache list
|
||||
override fun getDeviceNodes() = listOf(deviceNode)
|
||||
override fun getNodeFromSide(directionToRequester: Direction) = deviceNode
|
||||
|
||||
override fun loadAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
|
||||
super.loadAdditional(tag, registries)
|
||||
deviceNode.energy = min(tag.getLong("energy"), deviceNode.energyCapacity)
|
||||
}
|
||||
|
||||
override fun saveAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
|
||||
super.saveAdditional(compoundTag, provider)
|
||||
compoundTag.putLong("energy", node.energy)
|
||||
compoundTag.putLong("energy", deviceNode.energy)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +55,7 @@ class CapacitorEntityTier1(pos: BlockPos, state: BlockState): CapacitorEntity(20
|
||||
class CapacitorEntityTier2(pos: BlockPos, state: BlockState): CapacitorEntity(50000, BlockEntities.CAPACITOR2_ENTITY.get(), pos, state)
|
||||
class CapacitorEntityTier3(pos: BlockPos, state: BlockState): CapacitorEntity(100000, BlockEntities.CAPACITOR3_ENTITY.get(), pos, state)
|
||||
|
||||
class CapacitorBlock(val tier: Int) : NodeBlock() {
|
||||
class CapacitorBlock(val tier: Int) : DeviceBlock() {
|
||||
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity {
|
||||
val cap: CapacitorEntity = when(tier) {
|
||||
1 -> CapacitorEntityTier1(blockPos, blockState)
|
||||
@@ -51,7 +63,7 @@ class CapacitorBlock(val tier: Int) : NodeBlock() {
|
||||
3 -> CapacitorEntityTier3(blockPos, blockState)
|
||||
else -> throw UnsupportedOperationException("unsupported tier: $tier")
|
||||
}
|
||||
return cap.initNetworking()
|
||||
return cap
|
||||
}
|
||||
|
||||
override fun useWithoutItem(
|
||||
@@ -62,12 +74,11 @@ class CapacitorBlock(val tier: Int) : NodeBlock() {
|
||||
blockHitResult: BlockHitResult
|
||||
): InteractionResult {
|
||||
if(level.isClientSide()) {
|
||||
val p = player as LocalPlayer
|
||||
val ent = level.getBlockEntity(blockPos)
|
||||
if(ent is CapacitorEntity) {
|
||||
if(p.isCrouching) ent.node.giveEnergy(1)
|
||||
val msg = PlayerChatMessage.system("energy: ${ent.node.energy} / ${ent.capacity} (${ent.computeEdges().size} edges, ${ent.node.getReachable().size} connected)")
|
||||
p.sendSystemMessage(OutgoingChatMessage.create(msg).content())
|
||||
if(player.isCrouching) ent.deviceNode.giveEnergy(1)
|
||||
val msg = PlayerChatMessage.system("energy: ${ent.deviceNode.energy} / ${ent.capacity} (${ent.deviceNode.connections.size} connections, ${ent.deviceNode.getReachable().size} reachable)")
|
||||
player.sendSystemMessage(OutgoingChatMessage.create(msg).content())
|
||||
}
|
||||
}
|
||||
return InteractionResult.SUCCESS
|
||||
|
||||
@@ -3,37 +3,25 @@ package org.neoflock.neocomputers.block;
|
||||
import dev.architectury.registry.menu.MenuRegistry
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import net.minecraft.sounds.SoundSource
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.world.Containers
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.context.BlockPlaceContext
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.EntityBlock
|
||||
import net.minecraft.world.level.block.FurnaceBlock
|
||||
import net.minecraft.world.level.block.SoundType
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.StateDefinition
|
||||
import net.minecraft.world.level.block.state.properties.BooleanProperty
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.block.CombustionGeneratorBlock.Companion.COMBUSTGEN_ACTIVE
|
||||
import org.neoflock.neocomputers.entity.BlockEntities
|
||||
import org.neoflock.neocomputers.entity.CaseBlockEntity
|
||||
import org.neoflock.neocomputers.entity.MachineEntity
|
||||
import org.neoflock.neocomputers.sounds.Sounds
|
||||
import org.neoflock.neocomputers.network.NodeSynchronizer
|
||||
|
||||
class CaseBlock() : NodeBlock(Properties.of().sound(SoundType.METAL).lightLevel(CaseBlock::getLuminance)) { // placeholder stuff
|
||||
class CaseBlock() : DeviceBlock(Properties.of().sound(SoundType.METAL).lightLevel(CaseBlock::getLuminance).noOcclusion()) { // placeholder stuff
|
||||
companion object {
|
||||
val FACING: EnumProperty<Direction> = EnumProperty.create<Direction>("facing", Direction::class.java)
|
||||
val COMPUTER_RUNNING = BooleanProperty.create("running")!!
|
||||
@@ -47,7 +35,7 @@ class CaseBlock() : NodeBlock(Properties.of().sound(SoundType.METAL).lightLevel(
|
||||
registerDefaultState(stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(COMPUTER_RUNNING, false))
|
||||
}
|
||||
|
||||
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState) = CaseBlockEntity(blockPos, blockState).initNetworking()
|
||||
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState) = CaseBlockEntity(blockPos, blockState)
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block?, BlockState?>) {
|
||||
builder.add(COMPUTER_RUNNING)
|
||||
@@ -58,17 +46,19 @@ class CaseBlock() : NodeBlock(Properties.of().sound(SoundType.METAL).lightLevel(
|
||||
return level.getBlockEntity(blockPos) as CaseBlockEntity
|
||||
}
|
||||
|
||||
override fun isSignalSource(state: BlockState): Boolean = true
|
||||
|
||||
override fun getSignal(
|
||||
blockState: BlockState,
|
||||
blockGetter: BlockGetter,
|
||||
blockPos: BlockPos,
|
||||
direction: Direction
|
||||
): Int {
|
||||
return getMachine(blockGetter, blockPos).redstoneOut[dirToIdx(direction.opposite)]
|
||||
return getMachine(blockGetter, blockPos).redstoneOut[direction.opposite.ordinal]
|
||||
}
|
||||
|
||||
override fun onPlace(
|
||||
blockState: BlockState,
|
||||
state: BlockState,
|
||||
level: Level,
|
||||
blockPos: BlockPos,
|
||||
blockState2: BlockState,
|
||||
@@ -78,7 +68,7 @@ class CaseBlock() : NodeBlock(Properties.of().sound(SoundType.METAL).lightLevel(
|
||||
level.updateNeighborsAt(blockPos, this)
|
||||
getMachine(level, blockPos).refetchAllRedstone()
|
||||
}
|
||||
super.onPlace(blockState, level, blockPos, blockState2, bl)
|
||||
super.onPlace(state, level, blockPos, blockState2, bl)
|
||||
}
|
||||
|
||||
override fun getStateForPlacement(context: BlockPlaceContext): BlockState? {
|
||||
@@ -115,7 +105,7 @@ class CaseBlock() : NodeBlock(Properties.of().sound(SoundType.METAL).lightLevel(
|
||||
} else {
|
||||
// Open menu
|
||||
MenuRegistry.openMenu(player as ServerPlayer, ent)
|
||||
NodeSynchronizer.registerPlayerScreen(player, ent)
|
||||
NodeSynchronizer.registerPlayerScreen(player, ent.deviceNode)
|
||||
}
|
||||
}
|
||||
return InteractionResult.SUCCESS
|
||||
|
||||
254
src/main/kotlin/org/neoflock/neocomputers/block/DeviceBlock.kt
Normal file
254
src/main/kotlin/org/neoflock/neocomputers/block/DeviceBlock.kt
Normal file
@@ -0,0 +1,254 @@
|
||||
package org.neoflock.neocomputers.block
|
||||
|
||||
import dev.architectury.networking.NetworkManager
|
||||
import io.netty.buffer.Unpooled
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.multiplayer.ClientLevel
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.HolderLookup
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.EntityBlock
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTicker
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.network.DeviceNode
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
import org.neoflock.neocomputers.network.NodeSynchronizer
|
||||
|
||||
abstract class SingleDeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: BlockState): DeviceBlockEntity(type, pos, state) {
|
||||
abstract val deviceNode: DeviceNode
|
||||
|
||||
override fun getDeviceNodes() = listOf(deviceNode)
|
||||
override fun getNodeFromSide(directionToRequester: Direction): DeviceNode? = deviceNode
|
||||
}
|
||||
|
||||
abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: BlockState): BlockEntity(type, pos, state) {
|
||||
val connetionsInDir = MutableList<DeviceNode?>(Direction.entries.size) { null }
|
||||
val nodesInDir = MutableList<DeviceNode?>(Direction.entries.size) { null }
|
||||
var alreadySetup = false
|
||||
var receivedServerState = false
|
||||
var connectionsAreDirty = true
|
||||
|
||||
abstract fun getDeviceNodes(): List<DeviceNode>
|
||||
|
||||
// Gets, if applicable, the node from a direction.
|
||||
// The direction is from this block entity to the original requester,
|
||||
// so it is Direction.UP if we asked from the one on the top side.
|
||||
abstract fun getNodeFromSide(directionToRequester: Direction): DeviceNode?
|
||||
|
||||
open fun processCommits(commits: Iterable<FriendlyByteBuf>) {
|
||||
receivedServerState = true
|
||||
val devs = getDeviceNodes()
|
||||
for (buf in commits) {
|
||||
val idx = buf.readVarInt()
|
||||
if(idx >= 0 && idx < devs.size) {
|
||||
devs[idx].processCommit(buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open fun initNetworking(): DeviceBlockEntity {
|
||||
if(hasLevel()) {
|
||||
alreadySetup = true
|
||||
Networking.addNodes(getDeviceNodes())
|
||||
Direction.entries.forEach { handleConnectionsFor(it) }
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
// Cables are 1 node
|
||||
open fun getCurrentlyConnectedNodeIn(direction: Direction): DeviceNode? {
|
||||
val ent = level?.getBlockEntity(blockPos.relative(direction))
|
||||
if(ent is DeviceBlockEntity) {
|
||||
return ent.getNodeFromSide(direction.opposite)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
open fun handleConnectionsFor(direction: Direction) {
|
||||
// refuse connections on no node to reduce CPU load
|
||||
val node = getNodeFromSide(direction)
|
||||
val oldNode = nodesInDir[direction.ordinal]
|
||||
nodesInDir[direction.ordinal] = node
|
||||
val old = connetionsInDir[direction.ordinal]
|
||||
val now = getCurrentlyConnectedNodeIn(direction)
|
||||
if(node == null) {
|
||||
if(old != null) oldNode?.disconnectFrom(old)
|
||||
if(now != null) oldNode?.disconnectFrom(now)
|
||||
return
|
||||
}
|
||||
if(oldNode != null && oldNode.address != node.address) {
|
||||
if(old != null) oldNode.disconnectFrom(old)
|
||||
if(now != null) oldNode.disconnectFrom(now)
|
||||
}
|
||||
|
||||
if(old?.address != now?.address || oldNode == null) {
|
||||
if(old != null) node.disconnectFrom(old)
|
||||
if(now != null) node.connectTo(now)
|
||||
}
|
||||
// bullshit hack
|
||||
if(now != null) {
|
||||
node.connectTo(now)
|
||||
}
|
||||
connetionsInDir[direction.ordinal] = now
|
||||
}
|
||||
|
||||
// TODO: optimize this sometime before our test computers melt
|
||||
open fun tickDevice(level: Level) {
|
||||
// Handles device connections
|
||||
|
||||
// we do it like this because stinky MC will call stuff before world is fully setup
|
||||
// and then not notify us of neighbour changes
|
||||
// this is because MC is considered shit
|
||||
if(!alreadySetup) {
|
||||
initNetworking()
|
||||
}
|
||||
if(connectionsAreDirty) {
|
||||
connectionsAreDirty = false
|
||||
Direction.entries.forEach { handleConnectionsFor(it) }
|
||||
}
|
||||
}
|
||||
|
||||
open fun sendCommitsToClient(level: Level) {
|
||||
if(level !is ServerLevel) return
|
||||
// synchronization!
|
||||
val commits = mutableListOf<FriendlyByteBuf>()
|
||||
val devs = getDeviceNodes()
|
||||
for((i, dev) in devs.withIndex()) {
|
||||
if(dev.outOfSync) {
|
||||
dev.outOfSync = false
|
||||
val buf = FriendlyByteBuf(Unpooled.buffer())
|
||||
buf.writeVarInt(i)
|
||||
dev.writeFullStateCommit(buf)
|
||||
commits.addLast(buf)
|
||||
}
|
||||
}
|
||||
if(commits.isNotEmpty()) {
|
||||
level.players().forEach {
|
||||
val dist = it.position().distanceTo(blockPos.center)
|
||||
if(dist < 100) NetworkManager.sendToPlayer(it, NodeSynchronizer.DeviceBlockStatePayload(blockPos, commits))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open fun sendStateToPlayer(player: ServerPlayer) {
|
||||
val world = level!!
|
||||
if(world !is ServerLevel) return
|
||||
// synchronization!
|
||||
val commits = mutableListOf<FriendlyByteBuf>()
|
||||
val devs = getDeviceNodes()
|
||||
for((i, dev) in devs.withIndex()) {
|
||||
val buf = FriendlyByteBuf(Unpooled.buffer())
|
||||
buf.writeVarInt(i)
|
||||
dev.writeFullStateCommit(buf)
|
||||
commits.addLast(buf)
|
||||
}
|
||||
if(commits.isNotEmpty()) {
|
||||
world.players().forEach {
|
||||
val dist = it.position().distanceTo(blockPos.center)
|
||||
if(dist <= NodeSynchronizer.MAX_STATE_DISTANCE_ALLOWED) NetworkManager.sendToPlayer(it, NodeSynchronizer.DeviceBlockStatePayload(blockPos, commits))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open fun requestServerState() {
|
||||
// no point
|
||||
if(receivedServerState) return
|
||||
// we're the server bro :sob:
|
||||
if(level?.isClientSide != true) return
|
||||
val player = Minecraft.getInstance().player ?: return
|
||||
// we assume the player will just reject, so we save on bandwidth
|
||||
if(player.position().distanceTo(blockPos.center) > NodeSynchronizer.MAX_STATE_DISTANCE_ALLOWED) return
|
||||
NetworkManager.sendToServer(NodeSynchronizer.DeviceBlockStateRequest(blockPos))
|
||||
}
|
||||
|
||||
override fun setRemoved() {
|
||||
super.setRemoved()
|
||||
alreadySetup = false
|
||||
Networking.removeNodes(getDeviceNodes())
|
||||
}
|
||||
|
||||
override fun loadAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
|
||||
super.loadAdditional(tag, registries)
|
||||
for (node in getDeviceNodes()) {
|
||||
node.markChanged()
|
||||
}
|
||||
connectionsAreDirty = true
|
||||
receivedServerState = false
|
||||
}
|
||||
}
|
||||
|
||||
abstract class DeviceBlock(properties: Properties = Properties.of()): BaseBlock(properties), EntityBlock {
|
||||
override fun <T : BlockEntity?> getTicker(
|
||||
level: Level,
|
||||
state: BlockState,
|
||||
blockEntityType: BlockEntityType<T?>
|
||||
): BlockEntityTicker<T> {
|
||||
return object : BlockEntityTicker<T> {
|
||||
override fun tick(level: Level, blockPos: BlockPos, blockState: BlockState, blockEntity: T & Any) {
|
||||
if(blockEntity !is DeviceBlockEntity) return
|
||||
blockEntity.tickDevice(level)
|
||||
blockEntity.sendCommitsToClient(level)
|
||||
if(level.isClientSide) {
|
||||
blockEntity.requestServerState()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPlace(state: BlockState, level: Level, pos: BlockPos, oldState: BlockState, movedByPiston: Boolean) {
|
||||
super.onPlace(state, level, pos, oldState, movedByPiston)
|
||||
val ent = level.getBlockEntity(pos)
|
||||
if(ent is DeviceBlockEntity) {
|
||||
ent.initNetworking()
|
||||
ent.connectionsAreDirty = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun useWithoutItem(
|
||||
state: BlockState,
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
player: Player,
|
||||
hitResult: BlockHitResult
|
||||
): InteractionResult? {
|
||||
val ent = level.getBlockEntity(pos)
|
||||
if(ent is DeviceBlockEntity && player is ServerPlayer) {
|
||||
val dir = hitResult.direction
|
||||
val node = ent.getNodeFromSide(dir)
|
||||
if(node == null) {
|
||||
player.sendSystemMessage(Component.literal("no node for dir $dir"))
|
||||
} else {
|
||||
player.sendSystemMessage(Component.literal("dir: $dir, address: ${node.address}, connections: ${node.connections.joinToString(", ")}"))
|
||||
}
|
||||
}
|
||||
return super.useWithoutItem(state, level, pos, player, hitResult)
|
||||
}
|
||||
|
||||
override fun neighborChanged(
|
||||
state: BlockState,
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
neighborBlock: Block,
|
||||
neighborPos: BlockPos,
|
||||
movedByPiston: Boolean
|
||||
) {
|
||||
super.neighborChanged(state, level, pos, neighborBlock, neighborPos, movedByPiston)
|
||||
val ent = level.getBlockEntity(pos)
|
||||
if(ent is DeviceBlockEntity) {
|
||||
ent.handleConnectionsFor(Direction.getNearest(neighborPos.center.subtract(pos.center)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,13 +23,14 @@ import net.minecraft.world.phys.BlockHitResult
|
||||
import org.neoflock.neocomputers.entity.BlockEntities
|
||||
import org.neoflock.neocomputers.entity.SolarGeneratorBlockEntity
|
||||
import org.neoflock.neocomputers.entity.CombustionGeneratorBlockEntity
|
||||
import org.neoflock.neocomputers.network.NodeSynchronizer
|
||||
|
||||
class SolarGeneratorBlock : NodeBlock(), EntityBlock {
|
||||
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity = SolarGeneratorBlockEntity(blockPos, blockState).initNetworking()
|
||||
class SolarGeneratorBlock : DeviceBlock(), EntityBlock {
|
||||
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity = SolarGeneratorBlockEntity(blockPos, blockState)
|
||||
}
|
||||
|
||||
// TODO: make it glow when burning
|
||||
class CombustionGeneratorBlock : NodeBlock, EntityBlock {
|
||||
class CombustionGeneratorBlock : DeviceBlock, EntityBlock {
|
||||
companion object {
|
||||
val COMBUSTGEN_ACTIVE = BooleanProperty.create("active")
|
||||
|
||||
@@ -42,7 +43,7 @@ class CombustionGeneratorBlock : NodeBlock, EntityBlock {
|
||||
registerDefaultState(defaultBlockState().setValue(COMBUSTGEN_ACTIVE, false))
|
||||
}
|
||||
|
||||
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity = CombustionGeneratorBlockEntity(blockPos, blockState).initNetworking()
|
||||
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity = CombustionGeneratorBlockEntity(blockPos, blockState)
|
||||
|
||||
override fun useWithoutItem(
|
||||
blockState: BlockState,
|
||||
@@ -54,7 +55,7 @@ class CombustionGeneratorBlock : NodeBlock, EntityBlock {
|
||||
if(!level.isClientSide()) {
|
||||
val sp = player as ServerPlayer
|
||||
val ent = level.getBlockEntity(blockPos, BlockEntities.COMBUSTGEN_ENTITY.get()).get()
|
||||
NodeSynchronizer.registerPlayerScreen(sp, ent)
|
||||
NodeSynchronizer.registerPlayerScreen(sp, ent.deviceNode)
|
||||
MenuRegistry.openMenu(sp, ent)
|
||||
}
|
||||
return InteractionResult.SUCCESS
|
||||
|
||||
@@ -1,307 +0,0 @@
|
||||
package org.neoflock.neocomputers.block
|
||||
|
||||
import dev.architectury.networking.NetworkManager
|
||||
import io.netty.buffer.Unpooled
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.HolderLookup
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.network.codec.StreamCodec
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.EntityBlock
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTicker
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
import org.neoflock.neocomputers.network.PowerRole
|
||||
import java.time.Duration
|
||||
|
||||
object NodeSynchronizer {
|
||||
class StatePayload(var blockPos: BlockPos, var buffer: FriendlyByteBuf): CustomPacketPayload {
|
||||
companion object {
|
||||
val NODE_SYNC_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "node_sync")
|
||||
val TYPE = CustomPacketPayload.Type<StatePayload>(NODE_SYNC_ID)
|
||||
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, StatePayload> {
|
||||
override fun decode(buf: RegistryFriendlyByteBuf): StatePayload {
|
||||
val blockPos = buf.readBlockPos()
|
||||
val buffer = FriendlyByteBuf(buf.copy(buf.readerIndex(), buf.readableBytes()))
|
||||
return StatePayload(blockPos, buffer)
|
||||
}
|
||||
|
||||
override fun encode(buf: RegistryFriendlyByteBuf, payload: StatePayload) {
|
||||
buf.writeBlockPos(payload.blockPos)
|
||||
buf.writeBytes(payload.buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun type() = TYPE
|
||||
}
|
||||
|
||||
class ScreenPayload(var entityTypeWireID: String, var buffer: FriendlyByteBuf): CustomPacketPayload {
|
||||
companion object {
|
||||
val SCREEN_SYNC_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "screen_sync")
|
||||
val TYPE = CustomPacketPayload.Type<ScreenPayload>(SCREEN_SYNC_ID)
|
||||
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, ScreenPayload> {
|
||||
override fun decode(buf: RegistryFriendlyByteBuf): ScreenPayload {
|
||||
val id = buf.readByteArray().decodeToString()
|
||||
val buffer = FriendlyByteBuf(buf.copy(buf.readerIndex(), buf.readableBytes()))
|
||||
return ScreenPayload(id, buffer)
|
||||
}
|
||||
|
||||
override fun encode(buf: RegistryFriendlyByteBuf, payload: ScreenPayload) {
|
||||
buf.writeByteArray(payload.entityTypeWireID.encodeToByteArray())
|
||||
buf.writeBytes(payload.buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun type() = TYPE
|
||||
}
|
||||
|
||||
class ScreenDataPayload(var entityTypeWireID: String, var buffer: FriendlyByteBuf): CustomPacketPayload {
|
||||
companion object {
|
||||
val SCREEN_DATA_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "screen_data")
|
||||
val TYPE = CustomPacketPayload.Type<ScreenDataPayload>(SCREEN_DATA_ID)
|
||||
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, ScreenDataPayload> {
|
||||
override fun decode(buf: RegistryFriendlyByteBuf): ScreenDataPayload {
|
||||
val id = buf.readByteArray().decodeToString()
|
||||
val buffer = FriendlyByteBuf(buf.copy(buf.readerIndex(), buf.readableBytes()))
|
||||
return ScreenDataPayload(id, buffer)
|
||||
}
|
||||
|
||||
override fun encode(buf: RegistryFriendlyByteBuf, payload: ScreenDataPayload) {
|
||||
buf.writeByteArray(payload.entityTypeWireID.encodeToByteArray())
|
||||
buf.writeBytes(payload.buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun type() = TYPE
|
||||
}
|
||||
|
||||
class BeepDataPayload(val pos: BlockPos, val pattern: String, val freq: Int, val duration: Duration, val volume: Double): CustomPacketPayload {
|
||||
companion object {
|
||||
val BEEP_DATA_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "beep_data")
|
||||
val TYPE = CustomPacketPayload.Type<BeepDataPayload>(BEEP_DATA_ID)
|
||||
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, BeepDataPayload> {
|
||||
override fun decode(buf: RegistryFriendlyByteBuf): BeepDataPayload {
|
||||
val pos = buf.readBlockPos()
|
||||
val pattern = buf.readUtf()
|
||||
val freq = buf.readVarInt()
|
||||
val duration = buf.readVarLong()
|
||||
val volume = buf.readDouble()
|
||||
return BeepDataPayload(pos, pattern, freq, Duration.ofMillis(duration), volume)
|
||||
}
|
||||
|
||||
override fun encode(buf: RegistryFriendlyByteBuf, payload: BeepDataPayload) {
|
||||
buf.writeBlockPos(payload.pos)
|
||||
buf.writeUtf(payload.pattern)
|
||||
buf.writeVarInt(payload.freq)
|
||||
buf.writeVarLong(payload.duration.toMillis())
|
||||
buf.writeDouble(payload.volume)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun type() = TYPE
|
||||
}
|
||||
|
||||
val screenMap = mutableMapOf<ServerPlayer, NodeBlockEntity>()
|
||||
|
||||
fun playerScreenClosed(player: ServerPlayer) {
|
||||
screenMap.remove(player)
|
||||
}
|
||||
|
||||
fun nodeTypeToWireID(nodeType: BlockEntityType<*>): String = nodeType.javaClass.canonicalName
|
||||
|
||||
fun registerPlayerScreen(player: ServerPlayer, entity: NodeBlockEntity) {
|
||||
screenMap[player] = entity
|
||||
}
|
||||
|
||||
fun syncScreens() {
|
||||
for((player, ent) in screenMap) {
|
||||
val buf = FriendlyByteBuf(Unpooled.buffer())
|
||||
ent.encodeScreenData(player, buf)
|
||||
NetworkManager.sendToPlayer(player, ScreenPayload(nodeTypeToWireID(ent.type), buf))
|
||||
}
|
||||
}
|
||||
|
||||
fun sendScreenInteraction(friendlyByteBuf: FriendlyByteBuf) {
|
||||
NetworkManager.sendToServer(ScreenDataPayload("", friendlyByteBuf))
|
||||
}
|
||||
|
||||
fun emitBeep(level: Level, beepDataPayload: BeepDataPayload) {
|
||||
if(level is ServerLevel) {
|
||||
level.players().forEach {
|
||||
NetworkManager.sendToPlayer(it, beepDataPayload)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class NodeBlockEntity(blockEntityType: BlockEntityType<*>, blockPos: BlockPos, blockState: BlockState) : BlockEntity(blockEntityType, blockPos, blockState) {
|
||||
abstract val node: Networking.Node
|
||||
|
||||
fun initNetworking(): NodeBlockEntity {
|
||||
Networking.addNode(node)
|
||||
invalidateNodeState()
|
||||
return this
|
||||
}
|
||||
|
||||
// runs on the server, meant to encode state to send to all players
|
||||
open fun encodeDownstreamData(packet: FriendlyByteBuf) {
|
||||
packet.writeUUID(node.address)
|
||||
packet.writeLong(node.energy)
|
||||
packet.writeLong(node.energyCapacity)
|
||||
packet.writeEnum(node.reachability)
|
||||
packet.writeEnum(node.powerRole)
|
||||
}
|
||||
|
||||
// runs on the client, meant to decode server state packets to synchronize client state
|
||||
open fun syncWithUpstream(packet: FriendlyByteBuf) {
|
||||
Networking.changeNodeAddress(node, packet.readUUID())
|
||||
node.energy = packet.readLong()
|
||||
node.energyCapacity = packet.readLong()
|
||||
node.reachability = packet.readEnum(node.reachability.javaClass)
|
||||
node.powerRole = packet.readEnum(node.powerRole.javaClass)
|
||||
}
|
||||
|
||||
// Encodes data meant for the associated screen of a player
|
||||
open fun encodeScreenData(player: ServerPlayer, packet: FriendlyByteBuf) {}
|
||||
|
||||
open fun processScreenInteraction(player: ServerPlayer, packet: FriendlyByteBuf) {}
|
||||
|
||||
private var stateIsDirty = true
|
||||
|
||||
open fun getNeighbourEntities(): List<BlockEntity> {
|
||||
val subpos = listOf(
|
||||
blockPos.offset(0, 0, 1),
|
||||
blockPos.offset(0, 0, -1),
|
||||
blockPos.offset(0, 1, 0),
|
||||
blockPos.offset(0, -1, 0),
|
||||
blockPos.offset(1, 0, 0),
|
||||
blockPos.offset(-1, 0, 0),
|
||||
)
|
||||
|
||||
return subpos.mapNotNull { pos -> level?.getBlockEntity(pos) }
|
||||
}
|
||||
|
||||
open fun computeEdges(): Set<NodeBlockEntity> {
|
||||
val s = mutableSetOf<NodeBlockEntity>()
|
||||
val neighbours = getNeighbourEntities()
|
||||
for(neighbour in neighbours) {
|
||||
if(neighbour is NodeBlockEntity) s.add(neighbour);
|
||||
// TODO: handle cable entities
|
||||
}
|
||||
s.remove(this)
|
||||
return s
|
||||
}
|
||||
|
||||
open fun invalidateNodeState() {
|
||||
stateIsDirty = true
|
||||
}
|
||||
|
||||
open fun needsSynchronization() = stateIsDirty
|
||||
|
||||
open fun tickNode(level: Level) {
|
||||
if(!level.isClientSide) {
|
||||
val l = level as ServerLevel
|
||||
val packetBuf = FriendlyByteBuf(Unpooled.buffer())
|
||||
encodeDownstreamData(packetBuf)
|
||||
l.players().forEach {
|
||||
if(it.level().isLoaded(blockPos)) NetworkManager.sendToPlayer(it, NodeSynchronizer.StatePayload(blockPos, packetBuf))
|
||||
}
|
||||
}
|
||||
if(!stateIsDirty) return
|
||||
stateIsDirty = false
|
||||
computeEdges().forEach {
|
||||
node.connectTo(it.node)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setChanged() {
|
||||
invalidateNodeState()
|
||||
computeEdges().forEach { it.invalidateNodeState() }
|
||||
super.setChanged()
|
||||
}
|
||||
|
||||
override fun setRemoved() {
|
||||
super.setRemoved()
|
||||
Networking.removeNode(node)
|
||||
}
|
||||
|
||||
override fun clearRemoved() {
|
||||
super.clearRemoved()
|
||||
initNetworking()
|
||||
}
|
||||
|
||||
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
|
||||
super.loadAdditional(compoundTag, provider)
|
||||
invalidateNodeState()
|
||||
computeEdges().forEach { it.invalidateNodeState() }
|
||||
}
|
||||
}
|
||||
|
||||
abstract class NodeBlock(properties: Properties = Properties.of()): BaseBlock(properties), EntityBlock {
|
||||
override fun <T : BlockEntity> getTicker(
|
||||
level: Level,
|
||||
blockState: BlockState,
|
||||
blockEntityType: BlockEntityType<T>
|
||||
): BlockEntityTicker<T>? {
|
||||
return object : BlockEntityTicker<T> {
|
||||
override fun tick(level: Level, blockPos: BlockPos, blockState: BlockState, blockEntity: T) {
|
||||
if(blockEntity !is NodeBlockEntity) return
|
||||
if(Networking.getNode(blockEntity.node.address) == null) blockEntity.initNetworking()
|
||||
blockEntity.tickNode(level)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPlace(
|
||||
blockState: BlockState,
|
||||
level: Level,
|
||||
blockPos: BlockPos,
|
||||
blockState2: BlockState,
|
||||
bl: Boolean
|
||||
) {
|
||||
super.onPlace(blockState, level, blockPos, blockState2, bl)
|
||||
if(!level.isClientSide) {
|
||||
val ent = level.getBlockEntity(blockPos)
|
||||
if(ent is NodeBlockEntity) {
|
||||
ent.invalidateNodeState()
|
||||
ent.computeEdges().forEach { it.invalidateNodeState() }
|
||||
}
|
||||
level.updateNeighborsAt(blockPos, this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun neighborChanged(
|
||||
blockState: BlockState,
|
||||
level: Level,
|
||||
blockPos: BlockPos,
|
||||
block: Block,
|
||||
blockPos2: BlockPos,
|
||||
bl: Boolean
|
||||
) {
|
||||
super.neighborChanged(blockState, level, blockPos, block, blockPos2, bl)
|
||||
if(!level.isClientSide) {
|
||||
val ent = level.getBlockEntity(blockPos)
|
||||
if(ent is NodeBlockEntity) {
|
||||
ent.invalidateNodeState()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
69
src/main/kotlin/org/neoflock/neocomputers/block/RackBlock.kt
Normal file
69
src/main/kotlin/org/neoflock/neocomputers/block/RackBlock.kt
Normal file
@@ -0,0 +1,69 @@
|
||||
package org.neoflock.neocomputers.block
|
||||
|
||||
import dev.architectury.registry.menu.MenuRegistry
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.MenuProvider
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.EntityBlock
|
||||
import net.minecraft.world.level.block.RenderShape
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.entity.BlockEntities
|
||||
import org.neoflock.neocomputers.entity.RackEntity
|
||||
import org.neoflock.neocomputers.network.NodeSynchronizer
|
||||
|
||||
class RackBlock : DeviceBlock(Properties.of().noOcclusion()), EntityBlock {
|
||||
override fun newBlockEntity(
|
||||
pos: BlockPos,
|
||||
state: BlockState
|
||||
): BlockEntity? {
|
||||
return RackEntity(pos, state)
|
||||
}
|
||||
|
||||
// override fun getShape(
|
||||
// state: BlockState,
|
||||
// level: BlockGetter,
|
||||
// pos: BlockPos,
|
||||
// context: CollisionContext
|
||||
// ): VoxelShape? {
|
||||
// return Shapes.box(0.0,0.0,0.0,0.01,0.01,0.01)
|
||||
// }
|
||||
|
||||
// override fun getRenderShape(state: BlockState): RenderShape? {
|
||||
// return RenderShape
|
||||
// }
|
||||
|
||||
|
||||
override fun useWithoutItem(state: BlockState, level: Level, pos: BlockPos, player: Player, hitResult: BlockHitResult): InteractionResult? {
|
||||
val res = hitResult.location
|
||||
val ent = level.getBlockEntity(pos, BlockEntities.RACK_ENTITY.get()).get()
|
||||
if(res.x == 18.0) { // TODO: handle rotation
|
||||
NeoComputers.LOGGER.info("{} > {} > {}, {} > {} > {}", pos.z+15/16f, res.z, pos.z+1/16f, pos.y+14/16f, res.y, pos.y+2/16f)
|
||||
if (pos.z + 15 / 16f > res.z && res.z > pos.z + 1 / 16f && pos.y + 14 / 16f > res.y && res.y > pos.y + 2 / 16f) {
|
||||
var rack = 0
|
||||
rack += if(res.y < pos.y+5/16f) 1 else 0
|
||||
rack += if(res.y < pos.y+8/16f) 1 else 0
|
||||
rack += if(res.y < pos.y+12/16f) 1 else 0
|
||||
|
||||
player.sendSystemMessage(Component.literal(String.format("Hit server #%d", rack))) // TODO: call some RackItem method
|
||||
return InteractionResult.SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
if (!level.isClientSide) {
|
||||
MenuRegistry.openExtendedMenu(player as ServerPlayer, ent)
|
||||
NodeSynchronizer.registerPlayerScreen(player as ServerPlayer, ent.node)
|
||||
}
|
||||
return InteractionResult.SUCCESS
|
||||
}
|
||||
}
|
||||
@@ -7,30 +7,27 @@ import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.RedStoneWireBlock
|
||||
import net.minecraft.world.level.block.RedstoneTorchBlock
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.entity.BlockEntities
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
import org.neoflock.neocomputers.network.DeviceNode
|
||||
|
||||
fun dirToIdx(direction: Direction) = Direction.entries.indexOf(direction)
|
||||
|
||||
class RedstoneIOEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEntity(BlockEntities.REDSTONEIO_ENTITY.get(), blockPos, blockState) {
|
||||
class RedstoneIOEntity(blockPos: BlockPos, blockState: BlockState): SingleDeviceBlockEntity(BlockEntities.REDSTONEIO_ENTITY.get(), blockPos, blockState) {
|
||||
val redstoneIn = Array<Int>(Direction.entries.size) {0}
|
||||
val redstoneOut = Array<Int>(Direction.entries.size) {0}
|
||||
|
||||
// TODO: have redstone I/O node for component and shi
|
||||
override val node = object : Networking.Node() {
|
||||
override val deviceNode = object : DeviceNode() {
|
||||
|
||||
}
|
||||
|
||||
fun refetch(dir: Direction) {
|
||||
val src = blockPos.offset(dir.stepX, dir.stepY, dir.stepZ)
|
||||
val cur = level?.getSignal(src, dir) ?: 0
|
||||
val idx = dirToIdx(dir)
|
||||
val idx = dir.ordinal
|
||||
if(redstoneIn[idx] != cur) {
|
||||
onRedstoneSignalChanged(dir, redstoneIn[idx], cur)
|
||||
}
|
||||
@@ -42,12 +39,12 @@ class RedstoneIOEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnt
|
||||
}
|
||||
|
||||
fun onRedstoneSignalChanged(dir: Direction, oldValue: Int, newValue: Int) {
|
||||
Networking.emitMessage(node, Networking.ComputerUncheckedSignal(node, "redstone_changed", arrayOf(node.address.toString(), dirToIdx(dir), oldValue, newValue)))
|
||||
Networking.emitMessage(deviceNode, Networking.ComputerUncheckedSignal(deviceNode, "redstone_changed", arrayOf(deviceNode.address.toString(), dir.ordinal, oldValue, newValue)))
|
||||
NeoComputers.LOGGER.info("redstone in direction ${dir.name} changed from $oldValue to $newValue")
|
||||
}
|
||||
}
|
||||
|
||||
class RedstoneIOBlock(): NodeBlock(Properties.of().isRedstoneConductor { state, getter, pos -> true }) {
|
||||
class RedstoneIOBlock(): DeviceBlock(Properties.of().isRedstoneConductor { state, getter, pos -> true }) {
|
||||
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity = RedstoneIOEntity(blockPos, blockState)
|
||||
|
||||
fun getRedstoneIO(level: BlockGetter, blockPos: BlockPos): RedstoneIOEntity? {
|
||||
@@ -68,7 +65,7 @@ class RedstoneIOBlock(): NodeBlock(Properties.of().isRedstoneConductor { state,
|
||||
): Int {
|
||||
val redstoneIO = getRedstoneIO(blockGetter, blockPos)
|
||||
if(redstoneIO != null) {
|
||||
return redstoneIO.redstoneOut[dirToIdx(direction.opposite)]
|
||||
return redstoneIO.redstoneOut[direction.opposite.ordinal]
|
||||
}
|
||||
return super.getSignal(blockState, blockGetter, blockPos, direction)
|
||||
}
|
||||
@@ -126,7 +123,7 @@ class RedstoneIOBlock(): NodeBlock(Properties.of().isRedstoneConductor { state,
|
||||
val redio = getRedstoneIO(level, blockPos)
|
||||
val dir = blockHitResult.direction
|
||||
if (redio != null) {
|
||||
val idx = dirToIdx(dir)
|
||||
val idx = dir.ordinal
|
||||
redio.redstoneOut[idx]++
|
||||
redio.redstoneOut[idx] %= 16
|
||||
NeoComputers.LOGGER.info("outputting redstone level ${redio.redstoneOut[idx]} on ${dir.name}")
|
||||
|
||||
194
src/main/kotlin/org/neoflock/neocomputers/block/RelayBlock.kt
Normal file
194
src/main/kotlin/org/neoflock/neocomputers/block/RelayBlock.kt
Normal file
@@ -0,0 +1,194 @@
|
||||
package org.neoflock.neocomputers.block
|
||||
|
||||
import dev.architectury.registry.menu.MenuRegistry
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.HolderLookup
|
||||
import net.minecraft.core.NonNullList
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.ContainerHelper
|
||||
import net.minecraft.world.Containers
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.MenuProvider
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.SoundType
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import org.neoflock.neocomputers.entity.BlockEntities
|
||||
import org.neoflock.neocomputers.entity.ComponentUser
|
||||
import org.neoflock.neocomputers.gui.menu.RelayMenu
|
||||
import org.neoflock.neocomputers.item.RelayUpgrade
|
||||
import org.neoflock.neocomputers.network.ConventionalNetworkDevice
|
||||
import org.neoflock.neocomputers.network.DeviceNode
|
||||
import org.neoflock.neocomputers.network.NNComponent
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
import org.neoflock.neocomputers.network.NodeSynchronizer
|
||||
import org.neoflock.neocomputers.utils.GenericContainer
|
||||
|
||||
class RelayEntity(blockPos: BlockPos, blockState: BlockState): SingleDeviceBlockEntity(BlockEntities.RELAY_ENTITY.get(), blockPos, blockState),
|
||||
GenericContainer, ComponentUser, MenuProvider {
|
||||
|
||||
companion object RelaySlots {
|
||||
val CARD = 0
|
||||
val CPU = 1
|
||||
val MEM = 2
|
||||
val STORAGE = 3
|
||||
|
||||
val SLOT_COUNT = 4
|
||||
}
|
||||
|
||||
val slots = NonNullList.withSize(SLOT_COUNT, ItemStack.EMPTY)!!
|
||||
|
||||
override fun getItems(): NonNullList<ItemStack> = slots
|
||||
|
||||
override fun stillValid(player: Player): Boolean = true
|
||||
|
||||
fun getUpgrade(slot: Int) = slots[slot].item as? RelayUpgrade
|
||||
|
||||
fun computeRelayInterval(): Int = getUpgrade(CPU)?.getRelayInterval(slots[CPU]) ?: 5
|
||||
fun computeRelayBufferSize(): Int = getUpgrade(MEM)?.getRelayBufferSize(slots[MEM]) ?: 1
|
||||
fun computeRelayQueueSize(): Int = getUpgrade(STORAGE)?.getRelayQueueSize(slots[STORAGE]) ?: 20
|
||||
fun getRelaySender(): DeviceNode? = getUpgrade(CARD)?.getComponentNode(slots[CARD])
|
||||
|
||||
fun computeRelayCapacity(): Int = computeRelayBufferSize() + computeRelayQueueSize()
|
||||
|
||||
val queue = mutableListOf<Networking.ClassicPacket>()
|
||||
val justReceived = mutableListOf<Networking.ClassicPacket>()
|
||||
var activityTickLeft = 0
|
||||
var ticksUntilQueue = 0
|
||||
|
||||
override val deviceNode = object : DeviceNode() {
|
||||
override var reachability = Networking.Visibility.NONE
|
||||
override fun received(message: Networking.Message) {
|
||||
super.received(message)
|
||||
if(message.sender == this) return
|
||||
if(message is Networking.ClassicPacket && message.hopCount < 5 && (queue.size + justReceived.size) < computeRelayCapacity()) {
|
||||
justReceived.addLast(message)
|
||||
activityTickLeft = 20
|
||||
markChanged()
|
||||
}
|
||||
}
|
||||
|
||||
override fun encodeScreenData(player: ServerPlayer, buf: FriendlyByteBuf) {
|
||||
super.encodeScreenData(player, buf)
|
||||
buf.writeVarInt(computeRelayInterval())
|
||||
buf.writeVarInt(computeRelayBufferSize())
|
||||
buf.writeVarInt(computeRelayQueueSize())
|
||||
buf.writeVarInt(queue.size + justReceived.size)
|
||||
}
|
||||
|
||||
override fun writeFullStateCommit(buf: FriendlyByteBuf) {
|
||||
super.writeFullStateCommit(buf)
|
||||
buf.writeVarInt(activityTickLeft)
|
||||
}
|
||||
|
||||
override fun processCommit(buf: FriendlyByteBuf) {
|
||||
super.processCommit(buf)
|
||||
activityTickLeft = buf.readVarInt()
|
||||
}
|
||||
|
||||
override fun getComponent() = NNComponent("relay")
|
||||
}
|
||||
|
||||
fun sendQueuedPacket() {
|
||||
if(queue.isEmpty()) return
|
||||
val pack = queue.removeFirst()
|
||||
|
||||
for(connection in deviceNode.connections) {
|
||||
// skip unwanted loopback
|
||||
if(connection in pack.sender.getReachable()) continue
|
||||
val hopped = pack.hop(pack.sender)
|
||||
|
||||
if(connection is ConventionalNetworkDevice) {
|
||||
connection.sendClassicPacket(hopped)
|
||||
} else {
|
||||
Networking.emitMessage(connection, hopped, setOf(deviceNode))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun tickDevice(level: Level) {
|
||||
super.tickDevice(level)
|
||||
if(level !is ServerLevel) return
|
||||
if(activityTickLeft > 0) {
|
||||
activityTickLeft--
|
||||
deviceNode.markChanged()
|
||||
}
|
||||
queue.addAll(justReceived)
|
||||
justReceived.clear()
|
||||
val cap = computeRelayCapacity()
|
||||
while(queue.size > cap) queue.removeLast()
|
||||
ticksUntilQueue--
|
||||
if(ticksUntilQueue <= 0) {
|
||||
ticksUntilQueue = computeRelayInterval()
|
||||
val toSend = computeRelayBufferSize()
|
||||
for(i in 0..<toSend) {
|
||||
sendQueuedPacket()
|
||||
}
|
||||
}
|
||||
deviceNode.markChanged()
|
||||
}
|
||||
|
||||
override fun getMachineBlockPosition() = blockPos!!
|
||||
|
||||
override fun getMachineLevel() = level!!
|
||||
|
||||
override fun getMachineNode() = deviceNode
|
||||
|
||||
override fun getDisplayName() = Component.translatable("block.neocomputers.relay")!!
|
||||
|
||||
override fun createMenu(
|
||||
i: Int,
|
||||
inventory: Inventory,
|
||||
player: Player
|
||||
) = RelayMenu(i, inventory, this)
|
||||
|
||||
override fun loadAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
|
||||
super.loadAdditional(tag, registries)
|
||||
ContainerHelper.loadAllItems(tag, slots, registries)
|
||||
}
|
||||
|
||||
override fun saveAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
|
||||
super.saveAdditional(tag, registries)
|
||||
ContainerHelper.saveAllItems(tag, slots, registries)
|
||||
}
|
||||
}
|
||||
|
||||
class RelayBlock: DeviceBlock(Properties.of().sound(SoundType.METAL)) {
|
||||
override fun newBlockEntity(pos: BlockPos, state: BlockState) = RelayEntity(pos, state)
|
||||
|
||||
override fun useWithoutItem(
|
||||
state: BlockState,
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
player: Player,
|
||||
hitResult: BlockHitResult
|
||||
): InteractionResult {
|
||||
if(!level.isClientSide) {
|
||||
val ent = level.getBlockEntity(pos, BlockEntities.RELAY_ENTITY.get()).get()
|
||||
// Open menu
|
||||
MenuRegistry.openMenu(player as ServerPlayer, ent)
|
||||
NodeSynchronizer.registerPlayerScreen(player, ent.deviceNode)
|
||||
}
|
||||
return InteractionResult.SUCCESS
|
||||
}
|
||||
|
||||
override fun onRemove(
|
||||
blockState: BlockState,
|
||||
level: Level,
|
||||
blockPos: BlockPos,
|
||||
blockState2: BlockState,
|
||||
bl: Boolean
|
||||
) {
|
||||
Containers.dropContentsOnDestroy(blockState, blockState2, level, blockPos)
|
||||
super.onRemove(blockState, level, blockPos, blockState2, bl)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.neoflock.neocomputers.block
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.EntityBlock
|
||||
import net.minecraft.world.level.block.RenderShape
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.entity.RobotEntity
|
||||
|
||||
class RobotBlock : BaseBlock(Properties.of().noOcclusion()), EntityBlock { // todo: node stuff
|
||||
override fun newBlockEntity(pos: BlockPos, state: BlockState): BlockEntity {
|
||||
NeoComputers.LOGGER.info("block entity created..")
|
||||
return RobotEntity(pos, state)
|
||||
}
|
||||
|
||||
override fun getShape(state: BlockState, level: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape? {
|
||||
return Shapes.box(0.1, 0.1, 0.1, 0.9, 0.9, 0.9)
|
||||
}
|
||||
|
||||
override fun getRenderShape(state: BlockState): RenderShape {
|
||||
return RenderShape.INVISIBLE // this is so not good
|
||||
}
|
||||
// public RenderShape getRenderShape(BlockState state) {
|
||||
// return RenderShape.ENTITYBLOCK_ANIMATED;
|
||||
// }
|
||||
}
|
||||
@@ -7,49 +7,38 @@ import net.minecraft.core.Direction
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.MenuProvider
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.context.BlockPlaceContext
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.EntityBlock
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.StateDefinition
|
||||
import net.minecraft.world.level.block.state.properties.BooleanProperty
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty.*
|
||||
import net.minecraft.world.level.block.state.properties.IntegerProperty
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.entity.BlockEntities
|
||||
import org.neoflock.neocomputers.entity.ScreenEntity
|
||||
import org.neoflock.neocomputers.gui.menu.Menus
|
||||
import org.neoflock.neocomputers.gui.menu.ScreenMenu
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import org.neoflock.neocomputers.network.NodeSynchronizer
|
||||
|
||||
class ScreenBlock() : NodeBlock() {
|
||||
class ScreenBlock() : DeviceBlock() {
|
||||
companion object {
|
||||
val FACING: EnumProperty<Direction> = EnumProperty.create<Direction>("facing", Direction::class.java)
|
||||
val ENERGY: Long = 5
|
||||
val FACING_HORIZ: EnumProperty<Direction> = EnumProperty.create<Direction>("facing_horiz", Direction::class.java)
|
||||
val FACING_VERTI: IntegerProperty = IntegerProperty.create("facing_verti", 0, 2) // "Integer" property doesnt accept values below 0, also death to enums, long live magic numbers
|
||||
}
|
||||
|
||||
init {
|
||||
registerDefaultState(stateDefinition.any().setValue(FACING, Direction.NORTH))
|
||||
registerDefaultState(stateDefinition.any().setValue(FACING_HORIZ, Direction.NORTH).setValue(FACING_VERTI, 1))
|
||||
}
|
||||
|
||||
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity? {
|
||||
val scr = ScreenEntity(blockPos, blockState)
|
||||
scr.initNetworking()
|
||||
return scr
|
||||
}
|
||||
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState) = ScreenEntity(blockPos, blockState)
|
||||
|
||||
override fun useWithoutItem(
|
||||
blockState: BlockState,
|
||||
@@ -59,14 +48,9 @@ class ScreenBlock() : NodeBlock() {
|
||||
blockHitResult: BlockHitResult
|
||||
): InteractionResult {
|
||||
if(!level.isClientSide) {
|
||||
val screenState = level.getBlockEntity(blockPos, BlockEntities.SCREEN_ENTITY.get()).get()
|
||||
if(!screenState.node.consumeEnergy(ENERGY)) {
|
||||
player.sendSystemMessage(Component.literal("Not enough power."))
|
||||
return InteractionResult.SUCCESS
|
||||
};
|
||||
val sp = player as ServerPlayer
|
||||
val ent = level.getBlockEntity(blockPos, BlockEntities.SCREEN_ENTITY.get()).get()
|
||||
NodeSynchronizer.registerPlayerScreen(sp, ent)
|
||||
NodeSynchronizer.registerPlayerScreen(sp, ent.deviceNode)
|
||||
MenuRegistry.openExtendedMenu(sp, object : ExtendedMenuProvider {
|
||||
override fun getDisplayName(): Component = Component.literal("SCREEEEEN!")
|
||||
override fun createMenu(i: Int, inventory: Inventory, player: Player): AbstractContainerMenu {
|
||||
@@ -83,10 +67,26 @@ class ScreenBlock() : NodeBlock() {
|
||||
}
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block?, BlockState?>) {
|
||||
builder.add(FACING)
|
||||
builder.add(FACING_HORIZ)
|
||||
builder.add(FACING_VERTI)
|
||||
}
|
||||
|
||||
override fun getStateForPlacement(context: BlockPlaceContext): BlockState? {
|
||||
return super.getStateForPlacement(context)!!.setValue(FACING, context.nearestLookingDirection.opposite)
|
||||
val horiz = context.horizontalDirection
|
||||
val looking = context.player!!.lookAngle
|
||||
|
||||
val biggest = max(max(abs(looking.y), abs(looking.z)), abs(looking.x))
|
||||
|
||||
return super.getStateForPlacement(context)!!
|
||||
.setValue(FACING_HORIZ, horiz.opposite)
|
||||
.setValue(FACING_VERTI, if (biggest != abs(looking.y)) 1 else if (looking.y < 0) 2 else 0 )
|
||||
|
||||
// val dirs = context.nearestLookingDirections
|
||||
// context.
|
||||
// return when (face) {
|
||||
// Direction.UP -> super.getStateForPlacement(context)!!.setValue(FACING_HORIZ, looking.opposite).setValue(FACING_VERTI, 2)
|
||||
// Direction.DOWN -> super.getStateForPlacement(context)!!.setValue(FACING_HORIZ, looking.opposite).setValue(FACING_VERTI, 0)
|
||||
// else -> super.getStateForPlacement(context)!!.setValue(FACING_HORIZ, looking.opposite).setValue(FACING_VERTI, 1)
|
||||
// }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package org.neoflock.neocomputers.block.model
|
||||
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad
|
||||
import net.minecraft.client.renderer.block.model.ItemOverrides
|
||||
import net.minecraft.client.renderer.block.model.ItemTransforms
|
||||
import net.minecraft.client.renderer.texture.TextureAtlas
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite
|
||||
import net.minecraft.client.resources.model.BakedModel
|
||||
import net.minecraft.client.resources.model.Material
|
||||
import net.minecraft.client.resources.model.ModelBaker
|
||||
import net.minecraft.client.resources.model.ModelState
|
||||
import net.minecraft.client.resources.model.UnbakedModel
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import java.util.function.Function
|
||||
|
||||
abstract class AbstractModel : BakedModel {
|
||||
val atlas = Minecraft.getInstance().getTextureAtlas(TextureAtlas.LOCATION_BLOCKS)
|
||||
var baker: ModelBaker? = null;
|
||||
var mesh: Map<Direction, List<BakedQuad>> = mapOf(
|
||||
Direction.UP to listOf(),
|
||||
Direction.DOWN to listOf(),
|
||||
Direction.EAST to listOf(),
|
||||
Direction.WEST to listOf(),
|
||||
Direction.SOUTH to listOf(),
|
||||
Direction.NORTH to listOf(),
|
||||
);
|
||||
|
||||
override fun getQuads(state: BlockState?, direction: Direction?, random: RandomSource): List<BakedQuad?>? { // perf? what's that?
|
||||
if (direction != null) {
|
||||
return mesh[direction]
|
||||
} else {
|
||||
var allquads: MutableList<BakedQuad> = mutableListOf()
|
||||
mesh.forEach { (_, quads) ->
|
||||
allquads.addAll(quads)
|
||||
}
|
||||
return allquads
|
||||
}
|
||||
}
|
||||
|
||||
fun _bake(spriteGetter: Function<Material, TextureAtlasSprite>): BakedModel {
|
||||
bake { r: Material -> spriteGetter.apply(r) }
|
||||
return this
|
||||
}
|
||||
|
||||
override fun getParticleIcon(): TextureAtlasSprite? {
|
||||
return atlas.apply(particle())
|
||||
}
|
||||
|
||||
abstract fun bake(atlas: (Material) -> TextureAtlasSprite)
|
||||
|
||||
abstract fun particle(): ResourceLocation
|
||||
|
||||
}
|
||||
|
||||
class SchizoConsumer {
|
||||
var mesh: Map<Direction, MutableList<BakedQuad>> = mapOf(
|
||||
Direction.UP to mutableListOf(),
|
||||
Direction.DOWN to mutableListOf(),
|
||||
Direction.EAST to mutableListOf(),
|
||||
Direction.WEST to mutableListOf(),
|
||||
Direction.SOUTH to mutableListOf(),
|
||||
Direction.NORTH to mutableListOf(),
|
||||
);
|
||||
|
||||
var vertices: MutableList<Int> = mutableListOf();
|
||||
var sprite: TextureAtlasSprite? = null;
|
||||
var normal: Direction? = null;
|
||||
var tint_index = -1
|
||||
var shade = false
|
||||
|
||||
fun startQuad(normal: Direction, sprite: TextureAtlasSprite, tint_index: Int = -1, shade: Boolean = false): SchizoConsumer {
|
||||
this.sprite = sprite
|
||||
this.normal = normal
|
||||
this.tint_index = tint_index
|
||||
this.shade = shade
|
||||
return this
|
||||
}
|
||||
|
||||
fun vertex(x: Float, y: Float, z:Float, colorABGR: Int, u: Float, v: Float) { // uv are normalized
|
||||
if (sprite == null || normal == null) {
|
||||
throw Error("quad not started")
|
||||
}
|
||||
|
||||
// NeoComputers.LOGGER.info("{} {} -> {} {} ", u, v, sprite!!.getU(u), sprite!!.getV(v))
|
||||
vertices.add(x.toBits())
|
||||
vertices.add(y.toBits())
|
||||
vertices.add(z.toBits())
|
||||
vertices.add(colorABGR)
|
||||
vertices.add(sprite!!.getU(u).toBits())
|
||||
vertices.add(sprite!!.getV(v).toBits())
|
||||
vertices.add(0)
|
||||
vertices.add(0)
|
||||
|
||||
if (vertices.size == 4 * 8) {
|
||||
var quad = BakedQuad(vertices.toIntArray(), tint_index, normal!!, sprite!!, shade)
|
||||
mesh.get(normal)!!.add(quad)
|
||||
normal = null
|
||||
sprite = null
|
||||
vertices.clear()
|
||||
}
|
||||
} // TODO: add stuff like squares
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package org.neoflock.neocomputers.block.model
|
||||
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad
|
||||
import net.minecraft.client.renderer.block.model.ItemOverrides
|
||||
import net.minecraft.client.renderer.block.model.ItemTransforms
|
||||
import net.minecraft.client.renderer.texture.TextureAtlas
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite
|
||||
import net.minecraft.client.resources.model.BakedModel
|
||||
import net.minecraft.client.resources.model.Material
|
||||
import net.minecraft.client.resources.model.ModelBaker
|
||||
import net.minecraft.client.resources.model.ModelState
|
||||
import net.minecraft.client.resources.model.UnbakedModel
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.util.ResourceLocationPattern
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import java.util.function.Function
|
||||
|
||||
class RobotModel() : AbstractModel() {
|
||||
val size = 0.4f
|
||||
val l = 0.5f-size;
|
||||
val h = 0.5f+size;
|
||||
|
||||
// TODO: fix dimensions (i eyeballed it)
|
||||
override fun bake(atlas: (Material) -> TextureAtlasSprite) {
|
||||
// override fun bake(atlas: Function<Material?, TextureAtlasSprite?>, state: ModelState): BakedModel {
|
||||
val sprite = atlas(Material(TextureAtlas.LOCATION_BLOCKS, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "block/robot")))
|
||||
// val sprite = atlas.apply(Material(TextureAtlas.LOCATION_BLOCKS, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "robot")))!!
|
||||
var verts: SchizoConsumer = SchizoConsumer()
|
||||
|
||||
// top pyramid, enjoy reading this schizo mess
|
||||
bakeTri(verts, Direction.WEST, sprite, l,l, l, h, 9f/16f,1f, 0f, 0f, 0f, 16f/32f)
|
||||
bakeTri(verts, Direction.EAST, sprite, h, h, h, l, 9f/16f, 1f, 16/32f, 16/32f, 16/32f, 0f)
|
||||
bakeTri(verts, Direction.SOUTH, sprite, l, h, h, h, 9f/16f, 1f, 0f, 16f/32f, 16f/32f, 16f/32f)
|
||||
bakeTri(verts, Direction.NORTH, sprite, h, l, l,l, 9f/16f, 1f, 16/32f, 0f, 0f, 0f)
|
||||
|
||||
verts.startQuad(Direction.DOWN, sprite, 0)
|
||||
verts.vertex(l, 9f/16F, h, 0xFFFFFFFF.toInt(), 16f/32f, 16/32F)
|
||||
verts.vertex(l, 9f/16f, l, 0xFFFFFFFF.toInt(), 0F, 16/32F)
|
||||
verts.vertex(h, 9f/16f, l, 0xFFFFFFFF.toInt(), 0F, 1F)
|
||||
verts.vertex(h, 9f/16f, h, 0xFFFFFFFF.toInt(), 16/32F, 1F)
|
||||
|
||||
// bottom
|
||||
bakeTri(verts, Direction.WEST, sprite, l, h, l, l, 8f/16f, 1/16f, 0f, 0f, 0f, 16f/32f)
|
||||
bakeTri(verts, Direction.EAST, sprite, h, l, h, h, 8f/16f, 1/16f, 0f, 0f, 0f, 16f/32f)
|
||||
bakeTri(verts, Direction.SOUTH, sprite, h, h, l, h, 8f/16f, 1/16f, 0f, 0f, 0f, 16f/32f)
|
||||
bakeTri(verts, Direction.NORTH, sprite, l, l, h,l, 8f/16f, 1/16f, 0f, 0f, 0f, 16f/32f)
|
||||
|
||||
verts.startQuad(Direction.UP, sprite, 0)
|
||||
verts.vertex(h, 8f/16F, l, 0xFFFFFFFF.toInt(), 16/32F, 16/32F)
|
||||
verts.vertex(l, 8f/16f, l, 0xFFFFFFFF.toInt(), 0F, 16/32F)
|
||||
verts.vertex(l, 8f/16f, h, 0xFFFFFFFF.toInt(), 0F, 1F)
|
||||
verts.vertex(h, 8f/16f, h, 0xFFFFFFFF.toInt(), 16/32F, 1F)
|
||||
|
||||
|
||||
this.mesh = verts.mesh
|
||||
}
|
||||
|
||||
fun bakeTri(verts: SchizoConsumer, normal: Direction, sprite: TextureAtlasSprite, lx: Float, lz: Float, rx: Float, rz: Float, dy: Float, uy: Float, lu: Float, lv: Float, ru: Float, rv: Float) {
|
||||
verts.startQuad(normal, sprite, 0)
|
||||
verts.vertex(0.5F, uy, 0.5F, 0xFFFFFFFF.toInt(), 8F/32F, 8F/32F)
|
||||
verts.vertex(0.5F, uy, 0.5F, 0xFFFFFFFF.toInt(), 8F/32F, 8F/32F)
|
||||
verts.vertex(lx, dy, lz, 0xFFFFFFFF.toInt(), lu, lv)
|
||||
verts.vertex(rx, dy, rz, 0xFFFFFFFF.toInt(), ru, rv)
|
||||
}
|
||||
|
||||
override fun particle(): ResourceLocation = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "block/teto")
|
||||
|
||||
override fun useAmbientOcclusion(): Boolean = true
|
||||
|
||||
override fun isGui3d(): Boolean = true
|
||||
|
||||
override fun usesBlockLight(): Boolean = true
|
||||
|
||||
override fun isCustomRenderer(): Boolean = false
|
||||
|
||||
override fun getTransforms(): ItemTransforms? = ItemTransforms.NO_TRANSFORMS
|
||||
|
||||
override fun getOverrides(): ItemOverrides? = ItemOverrides.EMPTY // TODO: item
|
||||
}
|
||||
@@ -4,15 +4,19 @@ import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput
|
||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricModelProvider
|
||||
import net.minecraft.data.models.BlockModelGenerators
|
||||
import net.minecraft.data.models.ItemModelGenerators
|
||||
import net.minecraft.data.models.model.ModelTemplate
|
||||
import net.minecraft.data.models.model.ModelTemplates
|
||||
import org.neoflock.neocomputers.block.Blocks
|
||||
import org.neoflock.neocomputers.item.Items
|
||||
|
||||
class ModelGenerator(output: FabricDataOutput) : FabricModelProvider(output) {
|
||||
override fun generateBlockStateModels(blockStateModelGenerator: BlockModelGenerators) {
|
||||
blockStateModelGenerator.createGenericCube(Blocks.CASE_BLOCK.get())
|
||||
// blockStateModelGenerator.createGenericCube(Blocks.CASE_BLOCK.get())
|
||||
|
||||
}
|
||||
|
||||
override fun generateItemModels(itemModelGenerator: ItemModelGenerators) {
|
||||
// itemModelGenerator.generateFlatItem(Items.SERVER0.get(), ModelTemplates.FLAT_ITEM)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.neoflock.neocomputers.entity
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
|
||||
class AssemblerEntity(pos: BlockPos, state: BlockState) : BlockEntity(BlockEntities.ASSEMBLER_ENTITY.get(), pos, state) {
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import org.neoflock.neocomputers.block.CapacitorEntity
|
||||
import org.neoflock.neocomputers.block.CapacitorEntityTier1
|
||||
import org.neoflock.neocomputers.block.CapacitorEntityTier2
|
||||
import org.neoflock.neocomputers.block.CapacitorEntityTier3
|
||||
import org.neoflock.neocomputers.block.RelayEntity
|
||||
import org.neoflock.neocomputers.network.PowerManager
|
||||
|
||||
// complete fucking bullshit btw
|
||||
@@ -42,51 +43,81 @@ object BlockEntities {
|
||||
|
||||
val SCREEN_ENTITY: RegistrySupplier<BlockEntityType<ScreenEntity>> = BLOCKENTITIES.register("screen") {
|
||||
BlockEntityType(
|
||||
::ScreenEntity, mutableSetOf(Blocks.SCREEN_BLOCK.get()), BullshitFix()
|
||||
::ScreenEntity, setOf(Blocks.SCREEN_BLOCK.get()), BullshitFix()
|
||||
)
|
||||
}
|
||||
val CAPACITOR_ENTITY: RegistrySupplier<BlockEntityType<CapacitorEntityTier1>> = BLOCKENTITIES.register("capacitor") {
|
||||
BlockEntityType(
|
||||
::CapacitorEntityTier1, mutableSetOf(Blocks.CAPACITOR_BLOCK.get()), BullshitFix()
|
||||
::CapacitorEntityTier1, setOf(Blocks.CAPACITOR_BLOCK.get()), BullshitFix()
|
||||
)
|
||||
}
|
||||
val CAPACITOR2_ENTITY: RegistrySupplier<BlockEntityType<CapacitorEntityTier2>> = BLOCKENTITIES.register("capacitor2") {
|
||||
BlockEntityType(
|
||||
::CapacitorEntityTier2, mutableSetOf(Blocks.CAPACITOR_BLOCK2.get()), BullshitFix()
|
||||
::CapacitorEntityTier2, setOf(Blocks.CAPACITOR_BLOCK2.get()), BullshitFix()
|
||||
)
|
||||
}
|
||||
val CAPACITOR3_ENTITY: RegistrySupplier<BlockEntityType<CapacitorEntityTier3>> = BLOCKENTITIES.register("capacitor3") {
|
||||
BlockEntityType(
|
||||
::CapacitorEntityTier3, mutableSetOf(Blocks.CAPACITOR_BLOCK3.get()), BullshitFix()
|
||||
::CapacitorEntityTier3, setOf(Blocks.CAPACITOR_BLOCK3.get()), BullshitFix()
|
||||
)
|
||||
}
|
||||
val SOLARGEN_ENTITY: RegistrySupplier<BlockEntityType<SolarGeneratorBlockEntity>> = BLOCKENTITIES.register("solargen") {
|
||||
BlockEntityType(
|
||||
::SolarGeneratorBlockEntity, mutableSetOf(Blocks.SOLARGEN_BLOCK.get()), BullshitFix()
|
||||
::SolarGeneratorBlockEntity, setOf(Blocks.SOLARGEN_BLOCK.get()), BullshitFix()
|
||||
)
|
||||
}
|
||||
val COMBUSTGEN_ENTITY: RegistrySupplier<BlockEntityType<CombustionGeneratorBlockEntity>> = BLOCKENTITIES.register("combustgen") {
|
||||
BlockEntityType(
|
||||
::CombustionGeneratorBlockEntity, mutableSetOf(Blocks.COMBUSTGEN_BLOCK.get()), BullshitFix()
|
||||
::CombustionGeneratorBlockEntity, setOf(Blocks.COMBUSTGEN_BLOCK.get()), BullshitFix()
|
||||
)
|
||||
}
|
||||
val REDSTONEIO_ENTITY: RegistrySupplier<BlockEntityType<CombustionGeneratorBlockEntity>> = BLOCKENTITIES.register("redio") {
|
||||
BlockEntityType(
|
||||
::CombustionGeneratorBlockEntity, mutableSetOf(Blocks.REDSTONEIO_BLOCK.get()), BullshitFix()
|
||||
::CombustionGeneratorBlockEntity, setOf(Blocks.REDSTONEIO_BLOCK.get()), BullshitFix()
|
||||
)
|
||||
}
|
||||
val CASE_ENTITY: RegistrySupplier<BlockEntityType<CaseBlockEntity>> = BLOCKENTITIES.register("case") {
|
||||
BlockEntityType(
|
||||
::CaseBlockEntity, mutableSetOf(Blocks.CASE_BLOCK.get()), BullshitFix()
|
||||
::CaseBlockEntity, setOf(Blocks.CASE_BLOCK.get()), BullshitFix()
|
||||
)
|
||||
}
|
||||
|
||||
val CABLE_ENTITY: RegistrySupplier<BlockEntityType<CableEntity>> = BLOCKENTITIES.register("cable") {
|
||||
BlockEntityType(
|
||||
::CableEntity, setOf(Blocks.CABLE_BLOCK.get()), BullshitFix()
|
||||
)
|
||||
}
|
||||
|
||||
val RELAY_ENTITY: RegistrySupplier<BlockEntityType<RelayEntity>> = BLOCKENTITIES.register("relay") {
|
||||
BlockEntityType(
|
||||
::RelayEntity, setOf(Blocks.RELAY_BLOCK.get()), BullshitFix()
|
||||
)
|
||||
}
|
||||
|
||||
val ROBOT_ENTITY: RegistrySupplier<BlockEntityType<RobotEntity>> = BLOCKENTITIES.register("robot") {
|
||||
BlockEntityType(
|
||||
::RobotEntity, setOf(Blocks.ROBOT_BLOCK.get()), BullshitFix()
|
||||
)
|
||||
}
|
||||
|
||||
val RACK_ENTITY: RegistrySupplier<BlockEntityType<RackEntity>> = BLOCKENTITIES.register("rack") {
|
||||
BlockEntityType(
|
||||
::RackEntity, setOf(Blocks.RACK_BLOCK.get()), BullshitFix()
|
||||
)
|
||||
}
|
||||
|
||||
val ASSEMBLER_ENTITY: RegistrySupplier<BlockEntityType<AssemblerEntity>> = BLOCKENTITIES.register("assembler") {
|
||||
BlockEntityType(
|
||||
::AssemblerEntity, setOf(Blocks.ASSEMBLER_BLOCK.get()), BullshitFix()
|
||||
)
|
||||
}
|
||||
|
||||
fun registerPowerBlocks() {
|
||||
PowerManager.registerPowerBlockEntity(CAPACITOR_ENTITY.get())
|
||||
PowerManager.registerPowerBlockEntity(CAPACITOR2_ENTITY.get())
|
||||
PowerManager.registerPowerBlockEntity(CAPACITOR3_ENTITY.get())
|
||||
PowerManager.registerPowerBlockEntity(SOLARGEN_ENTITY.get())
|
||||
PowerManager.registerPowerBlockEntity(COMBUSTGEN_ENTITY.get())
|
||||
PowerManager.registerPowerBlockEntity(CASE_ENTITY.get())
|
||||
PowerManager.registerPowerDevice(CAPACITOR_ENTITY.get())
|
||||
PowerManager.registerPowerDevice(CAPACITOR2_ENTITY.get())
|
||||
PowerManager.registerPowerDevice(CAPACITOR3_ENTITY.get())
|
||||
PowerManager.registerPowerDevice(SOLARGEN_ENTITY.get())
|
||||
PowerManager.registerPowerDevice(COMBUSTGEN_ENTITY.get())
|
||||
PowerManager.registerPowerDevice(CASE_ENTITY.get())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.neoflock.neocomputers.entity
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.world.item.DyeColor
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import org.neoflock.neocomputers.block.CableBlock
|
||||
import org.neoflock.neocomputers.block.CableBlock.Companion.COLOR
|
||||
import org.neoflock.neocomputers.block.CableBlock.Companion.getPropByDirection
|
||||
import org.neoflock.neocomputers.block.DeviceBlockEntity
|
||||
import org.neoflock.neocomputers.block.SingleDeviceBlockEntity
|
||||
import org.neoflock.neocomputers.network.DeviceNode
|
||||
|
||||
class CableEntity(pos: BlockPos, state: BlockState) : SingleDeviceBlockEntity(BlockEntities.CABLE_ENTITY.get(), pos, state) {
|
||||
override val deviceNode = object : DeviceNode(){}
|
||||
|
||||
override fun sendCommitsToClient(level: Level) {
|
||||
// we have nothing to commit lol
|
||||
return
|
||||
}
|
||||
|
||||
override fun requestServerState() {
|
||||
// no state, we don't bother
|
||||
return
|
||||
}
|
||||
|
||||
override fun getNodeFromSide(directionToRequester: Direction): DeviceNode? {
|
||||
if(CableBlock.shouldConnect(blockPos, blockPos.relative(directionToRequester), level!!)) {
|
||||
return deviceNode
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun setChanged() {
|
||||
super.setChanged()
|
||||
for (dir in Direction.entries) {
|
||||
val ent = level!!.getBlockEntity(blockPos.relative(dir))
|
||||
level!!.setBlockAndUpdate(blockPos, blockState.setValue(getPropByDirection(dir), CableBlock.shouldConnect(blockPos, blockPos.relative(dir), level!!)))
|
||||
if(ent is DeviceBlockEntity) {
|
||||
ent.connectionsAreDirty = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.sounds.SoundSource
|
||||
import net.minecraft.world.Container
|
||||
import net.minecraft.world.ContainerHelper
|
||||
import net.minecraft.world.MenuProvider
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
@@ -20,68 +21,101 @@ import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.block.CaseBlock
|
||||
import org.neoflock.neocomputers.block.NodeBlockEntity
|
||||
import org.neoflock.neocomputers.block.NodeSynchronizer
|
||||
import org.neoflock.neocomputers.block.dirToIdx
|
||||
import org.neoflock.neocomputers.block.SingleDeviceBlockEntity
|
||||
import org.neoflock.neocomputers.gui.menu.CaseMenu
|
||||
import org.neoflock.neocomputers.item.ComponentItem
|
||||
import org.neoflock.neocomputers.network.DeviceNode
|
||||
import org.neoflock.neocomputers.network.NNComponent
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
import org.neoflock.neocomputers.network.PowerRole
|
||||
import org.neoflock.neocomputers.sounds.ComputerRunningSoundInstance
|
||||
import org.neoflock.neocomputers.sounds.Sounds
|
||||
import org.neoflock.neocomputers.utils.GenericContainer
|
||||
import java.time.Duration
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import org.neoflock.neocomputers.network.NodeSynchronizer
|
||||
import kotlin.text.ifEmpty
|
||||
|
||||
class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEntity(BlockEntities.CASE_ENTITY.get(), blockPos, blockState), MachineEntity, GenericContainer, MenuProvider {
|
||||
class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): SingleDeviceBlockEntity(BlockEntities.CASE_ENTITY.get(), blockPos, blockState), MachineEntity, GenericContainer, MenuProvider {
|
||||
val stacks: NonNullList<ItemStack> = NonNullList<ItemStack>.withSize(7, ItemStack.EMPTY)
|
||||
|
||||
var isOn = false
|
||||
var isDisking = false // TOOD: writing writers and reading readers
|
||||
var diskActivityTime = 0 // TOOD: writing writers and reading readers
|
||||
var networkActivityTime = 0
|
||||
var err: String? = null
|
||||
var arch = "Lua 5.3"
|
||||
var soundInstance: SoundInstance? = null
|
||||
|
||||
override val node = object : Networking.Node() {
|
||||
override val deviceNode = object : DeviceNode() {
|
||||
override var powerRole = PowerRole.CONSUMER
|
||||
override var energyCapacity: Long = 500
|
||||
}
|
||||
|
||||
override fun encodeDownstreamData(packet: FriendlyByteBuf) {
|
||||
super.encodeDownstreamData(packet)
|
||||
packet.writeBoolean(isOn)
|
||||
packet.writeBoolean(isDisking)
|
||||
packet.writeUtf(err ?: "")
|
||||
}
|
||||
|
||||
override fun syncWithUpstream(packet: FriendlyByteBuf) {
|
||||
super.syncWithUpstream(packet)
|
||||
setRunning(packet.readBoolean())
|
||||
isDisking = packet.readBoolean()
|
||||
err = packet.readUtf().ifEmpty { null }
|
||||
}
|
||||
|
||||
override fun processScreenInteraction(player: ServerPlayer, packet: FriendlyByteBuf) {
|
||||
val c = packet.readByte().toInt()
|
||||
if(c == 0x01) {
|
||||
start()
|
||||
override fun writeFullStateCommit(buf: FriendlyByteBuf) {
|
||||
super.writeFullStateCommit(buf)
|
||||
buf.writeUUID(address)
|
||||
buf.writeBoolean(isOn)
|
||||
buf.writeVarInt(diskActivityTime)
|
||||
buf.writeVarInt(networkActivityTime)
|
||||
buf.writeUtf(err ?: "")
|
||||
}
|
||||
if(c == 0x02) {
|
||||
stop()
|
||||
}
|
||||
}
|
||||
|
||||
override fun encodeScreenData(player: ServerPlayer, packet: FriendlyByteBuf) {
|
||||
super.encodeScreenData(player, packet)
|
||||
packet.writeBoolean(isOn)
|
||||
packet.writeByteArray((err ?: "").encodeToByteArray())
|
||||
packet.writeLong(node.energy)
|
||||
packet.writeLong(node.energyCapacity)
|
||||
packet.writeLong(getMachineMemoryUsed())
|
||||
packet.writeLong(getMachineMemoryTotal())
|
||||
packet.writeLong(getMachineComponentsUsed())
|
||||
packet.writeLong(getMachineComponentsTotal())
|
||||
packet.writeUtf(arch)
|
||||
override fun processCommit(buf: FriendlyByteBuf) {
|
||||
super.processCommit(buf)
|
||||
Networking.changeNodeAddress(this, buf.readUUID())
|
||||
setRunning(buf.readBoolean())
|
||||
diskActivityTime = buf.readVarInt()
|
||||
networkActivityTime = buf.readVarInt()
|
||||
err = buf.readUtf().ifEmpty { null }
|
||||
}
|
||||
|
||||
override fun processScreenInteraction(player: ServerPlayer, buf: FriendlyByteBuf) {
|
||||
super.processScreenInteraction(player, buf)
|
||||
val c = buf.readByte().toInt()
|
||||
if(c == 0x01) {
|
||||
start()
|
||||
}
|
||||
if(c == 0x02) {
|
||||
stop()
|
||||
}
|
||||
}
|
||||
|
||||
override fun encodeScreenData(player: ServerPlayer, buf: FriendlyByteBuf) {
|
||||
super.encodeScreenData(player, buf)
|
||||
buf.writeBoolean(isOn)
|
||||
buf.writeByteArray((err ?: "").encodeToByteArray())
|
||||
buf.writeLong(energy)
|
||||
buf.writeLong(energyCapacity)
|
||||
buf.writeLong(getMachineMemoryUsed())
|
||||
buf.writeLong(getMachineMemoryTotal())
|
||||
buf.writeLong(getMachineComponentsUsed())
|
||||
buf.writeLong(getMachineComponentsTotal())
|
||||
buf.writeUtf(arch)
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
super.tick()
|
||||
if (isRunning()) {
|
||||
if(diskActivityTime > 0) diskActivityTime--
|
||||
if(networkActivityTime > 0) networkActivityTime--
|
||||
if(getMachineArchitectures().isEmpty()) {
|
||||
crash("@neocomputers.errors.ENOCPU")
|
||||
} else if(getMachineComponentsUsed() > getMachineComponentsTotal()) {
|
||||
crash("@neocomputers.errors.E2BIG")
|
||||
} else if (!consumeEnergy(1)) {
|
||||
crash("@neocomputers.errors.ENOENJ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun received(message: Networking.Message) {
|
||||
super.received(message)
|
||||
if(message is Networking.ClassicPacket) {
|
||||
NeoComputers.LOGGER.info("machine $address got $message from ${message.sender.address}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getComponent() = NNComponent("computer")
|
||||
}
|
||||
|
||||
val redstoneIn = Array(Direction.entries.size) {0}
|
||||
@@ -90,7 +124,7 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
|
||||
fun refetchRedstone(dir: Direction) {
|
||||
val src = blockPos.offset(dir.stepX, dir.stepY, dir.stepZ)
|
||||
val cur = level?.getSignal(src, dir) ?: 0
|
||||
val idx = dirToIdx(dir)
|
||||
val idx = dir.ordinal
|
||||
if(redstoneIn[idx] != cur) {
|
||||
onRedstoneSignalChanged(dir, redstoneIn[idx], cur)
|
||||
}
|
||||
@@ -108,11 +142,12 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
|
||||
item.onMachineEvent(it, this, event)
|
||||
}
|
||||
}
|
||||
Networking.emitMessage(deviceNode, Networking.ComputerEvent(deviceNode, event))
|
||||
}
|
||||
|
||||
fun onRedstoneSignalChanged(dir: Direction, oldValue: Int, newValue: Int) {
|
||||
sendMachineEvent(MachineRedstoneEvent(this, dir, oldValue, newValue))
|
||||
Networking.emitMessage(node, Networking.ComputerUncheckedSignal(node, "redstone_changed", arrayOf(node.address.toString(), dirToIdx(dir), oldValue, newValue)))
|
||||
Networking.emitMessage(deviceNode, Networking.ComputerUncheckedSignal(deviceNode, "redstone_changed", arrayOf(deviceNode.address.toString(), dir.ordinal, oldValue, newValue)))
|
||||
NeoComputers.LOGGER.info("redstone in direction ${dir.name} changed from $oldValue to $newValue")
|
||||
if(oldValue == 0) {
|
||||
// Rising edge
|
||||
@@ -128,7 +163,8 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
|
||||
|
||||
fun setRunning(value: Boolean) {
|
||||
if(isOn == value) return
|
||||
NeoComputers.LOGGER.info("[${node.address}] Going from $isOn to $value")
|
||||
deviceNode.markChanged()
|
||||
NeoComputers.LOGGER.info("[${deviceNode.address}] Going from $isOn to $value")
|
||||
isOn = value
|
||||
val world = level ?: return
|
||||
blockState?.setValue(CaseBlock.COMPUTER_RUNNING, isOn)
|
||||
@@ -143,39 +179,40 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
|
||||
return
|
||||
}
|
||||
// Server-side stuff!!
|
||||
world.onBlockStateChange(blockPos, blockState, blockState)
|
||||
sendMachineEvent(MachinePowerEvent(this, isOn))
|
||||
Networking.emitMessage(deviceNode, Networking.ClassicPacket(deviceNode, deviceNode.address.toString(), null, 1, listOf(), 0))
|
||||
}
|
||||
|
||||
override fun start(): Boolean {
|
||||
if(isOn) return true
|
||||
err = null
|
||||
val archs = getMachineArchitectures()
|
||||
val architectures = getMachineArchitectures()
|
||||
// Beep patterns taken from https://github.com/MightyPirates/OpenComputers/blob/571482db88080d56329e8f8cf0db2a90825bf1d7/src/main/scala/li/cil/oc/server/machine/Machine.scala
|
||||
if(archs.isEmpty()) {
|
||||
crash("no cpu")
|
||||
if(architectures.isEmpty()) {
|
||||
crash("@neocomputers.errors.ENOCPU")
|
||||
beepAsync("-..")
|
||||
return false
|
||||
}
|
||||
if(getMachineComponentsUsed() > getMachineComponentsTotal()) {
|
||||
crash("too many components")
|
||||
crash("@neocomputers.errors.E2BIG")
|
||||
beepAsync("-..")
|
||||
return false
|
||||
}
|
||||
if(node.energy < 100) {
|
||||
crash("not enough energy")
|
||||
// less than 20% energy is bad
|
||||
if(deviceNode.energy < deviceNode.energyCapacity/5) {
|
||||
crash("@neocomputers.errors.ENOENJ")
|
||||
// we add a beep for the special case where we do have a little bit of energy :P
|
||||
if(node.energy > 0) beepAsync("..")
|
||||
if(deviceNode.energy > 0) beepAsync("..")
|
||||
return false
|
||||
}
|
||||
if(getMachineMemoryTotal() == 0L) {
|
||||
crash("no memory provided")
|
||||
crash("@neocomputers.errors.ENOMEM")
|
||||
beepAsync("-.")
|
||||
return false
|
||||
}
|
||||
if(arch !in archs) {
|
||||
// Just pick one!
|
||||
arch = archs.first()
|
||||
if(arch !in architectures) {
|
||||
// Just pick one! TODO: consult EEPROM first
|
||||
arch = architectures.first()
|
||||
}
|
||||
beepAsync(".")
|
||||
setRunning(true)
|
||||
@@ -189,9 +226,8 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
|
||||
}
|
||||
|
||||
override fun crash(error: String): Boolean {
|
||||
if(isOn) {
|
||||
beepAsync("--")
|
||||
}
|
||||
beepAsync("--")
|
||||
sendMachineEvent(MachineCrashEvent(this, error))
|
||||
setRunning(false)
|
||||
err = error
|
||||
return true
|
||||
@@ -199,14 +235,14 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
|
||||
|
||||
override fun getLastError(): String? = err
|
||||
|
||||
override fun getMachineNode(): Networking.Node = node
|
||||
override fun getMachineNode() = deviceNode
|
||||
|
||||
override fun getRedstoneInput(direction: Direction): Int = redstoneIn[dirToIdx(direction)]
|
||||
override fun getRedstoneInput(direction: Direction): Int = redstoneIn[direction.ordinal]
|
||||
|
||||
override fun getRedstoneOutput(direction: Direction): Int = redstoneOut[dirToIdx(direction)]
|
||||
override fun getRedstoneOutput(direction: Direction): Int = redstoneOut[direction.ordinal]
|
||||
|
||||
override fun setRedstoneOutput(direction: Direction, newValue: Int): Int {
|
||||
val idx = dirToIdx(direction)
|
||||
val idx = direction.ordinal
|
||||
val old = redstoneOut[idx]
|
||||
redstoneOut[idx] = newValue
|
||||
return old
|
||||
@@ -217,9 +253,17 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
|
||||
return true
|
||||
}
|
||||
|
||||
override fun signalDiskActivity(delay: Int) {
|
||||
diskActivityTime = max(delay, diskActivityTime)
|
||||
}
|
||||
|
||||
override fun signalNetworkActivity(delay: Int) {
|
||||
networkActivityTime = max(delay, networkActivityTime)
|
||||
}
|
||||
|
||||
override fun getMachineMemoryTotal(): Long = stacks.mapNotNull { (it.item as? ComponentItem)?.getMemoryCapacity(it) }.sum().toLong()
|
||||
override fun getMachineMemoryUsed(): Long = 0
|
||||
override fun getMachineComponentsUsed(): Long = node.getReachable().size.toLong()
|
||||
override fun getMachineComponentsUsed(): Long = deviceNode.getReachable().count { it.getComponent() != null }.toLong()
|
||||
override fun getMachineComponentsTotal(): Long = stacks.mapNotNull { (it.item as? ComponentItem)?.getComponentCapacity(it) }.sum().toLong()
|
||||
override fun getMachineArchitecture() = arch
|
||||
override fun getMachineArchitectures() = stacks.mapNotNull { (it.item as? ComponentItem)?.getArchitecturesProvided(it) }.flatten().toSet()
|
||||
@@ -236,16 +280,16 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
|
||||
|
||||
override fun stillValid(player: Player): Boolean = !this.isRemoved
|
||||
|
||||
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
|
||||
super.loadAdditional(compoundTag, provider)
|
||||
node.energy = min(node.energyCapacity, compoundTag.getLong("energy"))
|
||||
override fun loadAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
|
||||
super.loadAdditional(tag, registries)
|
||||
deviceNode.energy = min(deviceNode.energyCapacity, tag.getLong("energy"))
|
||||
//isOn = compoundTag.getBoolean("powerOn")
|
||||
ContainerHelper.loadAllItems(compoundTag, getItems(), provider)
|
||||
ContainerHelper.loadAllItems(tag, getItems(), registries)
|
||||
}
|
||||
|
||||
override fun saveAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
|
||||
super.saveAdditional(compoundTag, provider)
|
||||
compoundTag.putLong("energy", node.energy)
|
||||
compoundTag.putLong("energy", deviceNode.energy)
|
||||
//compoundTag.putBoolean("powerOn", isOn)
|
||||
ContainerHelper.saveAllItems(compoundTag, getItems(), provider)
|
||||
}
|
||||
@@ -258,17 +302,6 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
|
||||
super.setRemoved()
|
||||
}
|
||||
|
||||
override fun tickNode(level: Level) {
|
||||
super.tickNode(level)
|
||||
if(!level.isClientSide) {
|
||||
if (isRunning()) {
|
||||
if(getMachineComponentsUsed() > getMachineComponentsTotal()) {
|
||||
crash("too many components")
|
||||
}
|
||||
if (!node.consumeEnergy(1)) {
|
||||
crash("out of energy")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun canPlaceItem(slot: Int, stack: ItemStack): Boolean = false
|
||||
override fun canTakeItem(target: Container, slot: Int, stack: ItemStack): Boolean = false
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.neoflock.neocomputers.entity
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.HolderLookup
|
||||
import net.minecraft.core.NonNullList
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
@@ -15,22 +16,27 @@ import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import org.neoflock.neocomputers.block.CombustionGeneratorBlock
|
||||
import org.neoflock.neocomputers.block.NodeBlockEntity
|
||||
import org.neoflock.neocomputers.block.SingleDeviceBlockEntity
|
||||
import org.neoflock.neocomputers.gui.menu.CombustionGeneratorMenu
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
import org.neoflock.neocomputers.network.DeviceNode
|
||||
import org.neoflock.neocomputers.network.PowerRole
|
||||
import org.neoflock.neocomputers.utils.GenericContainer
|
||||
import org.neoflock.neocomputers.utils.ContainerUtils
|
||||
import kotlin.math.min
|
||||
|
||||
class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) : NodeBlockEntity(BlockEntities.COMBUSTGEN_ENTITY.get(), blockPos, blockState), GenericContainer, MenuProvider {
|
||||
class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) : SingleDeviceBlockEntity(BlockEntities.COMBUSTGEN_ENTITY.get(), blockPos, blockState), GenericContainer, MenuProvider {
|
||||
val energyPerTick: Long = 50
|
||||
|
||||
var burningTimeRemaining: Int = 0
|
||||
|
||||
override val node = object : Networking.Node() {
|
||||
override val deviceNode = object : DeviceNode() {
|
||||
override var powerRole = PowerRole.GENERATOR
|
||||
override var energyCapacity: Long = 100000
|
||||
|
||||
override fun encodeScreenData(player: ServerPlayer, buf: FriendlyByteBuf) {
|
||||
buf.writeLong(energy)
|
||||
buf.writeLong(energyCapacity)
|
||||
}
|
||||
}
|
||||
|
||||
val stacks: NonNullList<ItemStack> = NonNullList<ItemStack>.withSize(1, ItemStack.EMPTY)
|
||||
@@ -45,20 +51,20 @@ class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
||||
return !this.isRemoved
|
||||
}
|
||||
|
||||
override fun tickNode(level: Level) {
|
||||
super.tickNode(level)
|
||||
override fun tickDevice(level: Level) {
|
||||
super.tickDevice(level)
|
||||
// TODO: give us a block state tag for active
|
||||
|
||||
// keep combusting and shi
|
||||
if(burningTimeRemaining > 0) {
|
||||
burningTimeRemaining--
|
||||
node.giveEnergy(energyPerTick)
|
||||
deviceNode.giveEnergy(energyPerTick)
|
||||
setChanged()
|
||||
return
|
||||
}
|
||||
|
||||
// no point
|
||||
if(node.energy >= node.energyCapacity) return;
|
||||
if(deviceNode.energy >= deviceNode.energyCapacity) return;
|
||||
|
||||
// :fire:
|
||||
val fuel = stacks[0]
|
||||
@@ -78,21 +84,16 @@ class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
||||
level?.setBlockAndUpdate(blockPos, blockState.setValue(CombustionGeneratorBlock.COMBUSTGEN_ACTIVE, burningTimeRemaining > 0))
|
||||
}
|
||||
|
||||
override fun encodeScreenData(player: ServerPlayer, packet: FriendlyByteBuf) {
|
||||
packet.writeLong(node.energy)
|
||||
packet.writeLong(node.energyCapacity)
|
||||
}
|
||||
|
||||
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
|
||||
super.loadAdditional(compoundTag, provider)
|
||||
node.energy = min(node.energyCapacity, compoundTag.getLong("energy"))
|
||||
deviceNode.energy = min(deviceNode.energyCapacity, compoundTag.getLong("energy"))
|
||||
burningTimeRemaining = compoundTag.getInt("burningTimeRemaining")
|
||||
ContainerHelper.loadAllItems(compoundTag, getItems(), provider)
|
||||
}
|
||||
|
||||
override fun saveAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
|
||||
super.saveAdditional(compoundTag, provider)
|
||||
compoundTag.putLong("energy", node.energy)
|
||||
compoundTag.putLong("energy", deviceNode.energy)
|
||||
compoundTag.putInt("burningTimeRemaining", burningTimeRemaining)
|
||||
ContainerHelper.saveAllItems(compoundTag, getItems(), provider)
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ package org.neoflock.neocomputers.entity
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.world.level.Level
|
||||
import org.neoflock.neocomputers.item.ComponentItem
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.neoflock.neocomputers.network.DeviceNode
|
||||
import java.time.Duration
|
||||
|
||||
abstract class MachineEvent {
|
||||
@@ -13,18 +13,28 @@ abstract class MachineEvent {
|
||||
|
||||
data class MachineRedstoneEvent(override val machine: MachineEntity, val side: Direction, val oldValue: Int, val newValue: Int): MachineEvent()
|
||||
data class MachinePowerEvent(override val machine: MachineEntity, val nowRunning: Boolean): MachineEvent()
|
||||
data class MachineCrashEvent(override val machine: MachineEntity, val error: String): MachineEvent()
|
||||
|
||||
interface MachineEntity {
|
||||
interface ComponentUser {
|
||||
// Block position of machine, for wireless tech
|
||||
fun getMachineBlockPosition(): BlockPos
|
||||
fun getMachinePrecisePosition(): Vec3 = getMachineBlockPosition().center
|
||||
fun getMachineLevel(): Level
|
||||
|
||||
fun getMachineNode(): DeviceNode
|
||||
}
|
||||
|
||||
interface MachineEntity: ComponentUser {
|
||||
// Pattern can have dots (.), dashes (-) and spaces ( ).
|
||||
// Each character is duration long, and has a 50ms break.
|
||||
// For non-short ones, which are typically reserved only for hardware interactions,
|
||||
// the duration is doubled.
|
||||
// Architectures should only use short ones.
|
||||
fun beepAsync(pattern: String, frequency: Int = 1000, duration: Duration = Duration.ofMillis(200), volume: Double = 1.0): Boolean
|
||||
// Signals that disk activity is happening for at least that delay
|
||||
fun signalDiskActivity(delay: Int)
|
||||
// signal network activity to a machine
|
||||
fun signalNetworkActivity(delay: Int)
|
||||
|
||||
fun isRunning(): Boolean
|
||||
fun start(): Boolean
|
||||
@@ -32,8 +42,6 @@ interface MachineEntity {
|
||||
fun crash(error: String): Boolean
|
||||
fun getLastError(): String?
|
||||
|
||||
fun getMachineNode(): Networking.Node
|
||||
|
||||
// Some metadata
|
||||
fun getMachineMemoryTotal(): Long
|
||||
fun getMachineMemoryUsed(): Long
|
||||
|
||||
134
src/main/kotlin/org/neoflock/neocomputers/entity/RackEntity.kt
Normal file
134
src/main/kotlin/org/neoflock/neocomputers/entity/RackEntity.kt
Normal file
@@ -0,0 +1,134 @@
|
||||
package org.neoflock.neocomputers.entity
|
||||
|
||||
import dev.architectury.registry.menu.ExtendedMenuProvider
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.HolderLookup
|
||||
import net.minecraft.core.NonNullList
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.protocol.Packet
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.ContainerHelper
|
||||
import net.minecraft.world.MenuProvider
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.entity.ChestBlockEntity
|
||||
import net.minecraft.world.level.block.entity.FurnaceBlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.block.DeviceBlockEntity
|
||||
import org.neoflock.neocomputers.gui.menu.RackMenu
|
||||
import org.neoflock.neocomputers.network.DeviceNode
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
import org.neoflock.neocomputers.utils.ContainerUtils
|
||||
import org.neoflock.neocomputers.utils.GenericContainer
|
||||
|
||||
class RackEntity(pos: BlockPos, state: BlockState) : DeviceBlockEntity(BlockEntities.RACK_ENTITY.get(), pos, state), ExtendedMenuProvider, GenericContainer {
|
||||
val stacks: NonNullList<ItemStack> = NonNullList<ItemStack>.withSize(4, ItemStack.EMPTY)
|
||||
|
||||
var conns = mutableListOf(
|
||||
-1, -1, -1, -1,
|
||||
-1, -1, -1, -1,
|
||||
-1, -1, -1, -1,
|
||||
-1, -1, -1, -1
|
||||
)
|
||||
|
||||
var relayMode = false
|
||||
|
||||
val node: DeviceNode = object : DeviceNode() {
|
||||
override var reachability: Networking.Visibility = Networking.Visibility.NONE
|
||||
|
||||
override fun writeFullStateCommit(buf: FriendlyByteBuf) {
|
||||
super.writeFullStateCommit(buf)
|
||||
buf.writeBoolean(relayMode)
|
||||
|
||||
val tag = CompoundTag() // better way to do this, a better way i do not care to find atm
|
||||
ContainerHelper.saveAllItems(tag, stacks, level!!.registryAccess())
|
||||
buf.writeNbt(tag)
|
||||
|
||||
|
||||
for (conn in conns) {
|
||||
buf.writeInt(conn)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processCommit(buf: FriendlyByteBuf) {
|
||||
super.processCommit(buf)
|
||||
relayMode = buf.readBoolean()
|
||||
val tag = buf.readNbt()
|
||||
ContainerHelper.loadAllItems(tag!!, stacks, level!!.registryAccess())
|
||||
|
||||
for (i in 0..15) {
|
||||
conns[i] = buf.readInt()
|
||||
}
|
||||
markChanged()
|
||||
setChanged()
|
||||
}
|
||||
|
||||
override fun processScreenInteraction(player: ServerPlayer, buf: FriendlyByteBuf) {
|
||||
super.processScreenInteraction(player, buf)
|
||||
relayMode = buf.readBoolean()
|
||||
|
||||
val slot = buf.readInt()
|
||||
conns[slot*4+0] = buf.readInt()
|
||||
conns[slot*4+1] = buf.readInt()
|
||||
conns[slot*4+2] = buf.readInt()
|
||||
conns[slot*4+3] = buf.readInt()
|
||||
|
||||
markChanged()
|
||||
setChanged()
|
||||
}
|
||||
override fun encodeScreenData(player: ServerPlayer, buf: FriendlyByteBuf) { // TODO: set this up so other players can mess with racks
|
||||
super.encodeScreenData(player, buf)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setChanged() {
|
||||
super.setChanged()
|
||||
node.markChanged()
|
||||
}
|
||||
|
||||
override fun getDisplayName(): Component? = Component.literal("Rack")
|
||||
|
||||
override fun createMenu(i: Int, inventory: Inventory, player: Player): AbstractContainerMenu {
|
||||
return RackMenu(i, inventory, this)
|
||||
}
|
||||
|
||||
override fun getDeviceNodes(): List<DeviceNode> = listOf(node)
|
||||
|
||||
override fun getNodeFromSide(directionToRequester: Direction): DeviceNode? = node
|
||||
|
||||
|
||||
override fun loadAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
|
||||
super.loadAdditional(tag, registries)
|
||||
ContainerHelper.loadAllItems(tag, getItems(), registries)
|
||||
relayMode = tag.getBoolean("relay")
|
||||
|
||||
val connarray = tag.getIntArray("conns")
|
||||
if (connarray.size == 16) conns = connarray.toMutableList()
|
||||
setChanged()
|
||||
}
|
||||
|
||||
override fun saveAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
|
||||
super.saveAdditional(tag, registries)
|
||||
ContainerHelper.saveAllItems(tag, getItems(), registries)
|
||||
tag.putBoolean("relay", relayMode)
|
||||
tag.putIntArray("conns", conns.toIntArray())
|
||||
}
|
||||
|
||||
// override fun getItems(): NonNullList<ItemStack> = items
|
||||
override fun getItems(): NonNullList<ItemStack> = stacks
|
||||
|
||||
override fun stillValid(player: Player): Boolean = true
|
||||
override fun saveExtraData(buf: FriendlyByteBuf?) {
|
||||
buf!!.writeBlockPos(blockPos)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.neoflock.neocomputers.entity
|
||||
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.Nameable
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
|
||||
class RobotEntity(pos: BlockPos, state: BlockState) : BlockEntity(BlockEntities.ROBOT_ENTITY.get(), pos, state,), Nameable {
|
||||
val body: ModelPart? = null
|
||||
val name = "Diddyx" //TODO: names
|
||||
override fun getName(): Component? = Component.literal(name)
|
||||
|
||||
init {
|
||||
NeoComputers.LOGGER.info("yooo")
|
||||
}
|
||||
}
|
||||
@@ -1,63 +1,117 @@
|
||||
package org.neoflock.neocomputers.entity;
|
||||
package org.neoflock.neocomputers.entity
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.locale.Language
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.block.NodeBlockEntity
|
||||
import org.neoflock.neocomputers.block.SingleDeviceBlockEntity
|
||||
import org.neoflock.neocomputers.gui.buffer.BufferRenderer
|
||||
import org.neoflock.neocomputers.network.DeviceNode
|
||||
import org.neoflock.neocomputers.network.NNComponent
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
import org.neoflock.neocomputers.network.PowerRole
|
||||
import org.neoflock.neocomputers.utils.GPUChar
|
||||
import org.neoflock.neocomputers.utils.TextBuffer
|
||||
import kotlin.text.ifEmpty
|
||||
|
||||
class ScreenEntity(blockPos: BlockPos, blockState: BlockState) :
|
||||
NodeBlockEntity(BlockEntities.SCREEN_ENTITY.get(), blockPos, blockState) {
|
||||
SingleDeviceBlockEntity(BlockEntities.SCREEN_ENTITY.get(), blockPos, blockState) {
|
||||
|
||||
override val node = Networking.Node()
|
||||
var bound = "screen/unbound"
|
||||
var render_on_block = false
|
||||
var lastError: String? = null
|
||||
var isOn: Boolean = false
|
||||
|
||||
val scrwidth: Short = 160
|
||||
val scrheight: Short = 50
|
||||
|
||||
private var cleanrenderer: () -> Unit = { }; // TODO: THIS SUCKS, FIND A BETTER WAY
|
||||
|
||||
override fun encodeScreenData(player: ServerPlayer, packet: FriendlyByteBuf) {
|
||||
super.encodeScreenData(player, packet)
|
||||
packet.writeShort(scrwidth.toInt())
|
||||
packet.writeShort(scrheight.toInt())
|
||||
}
|
||||
|
||||
override fun tickNode(level: Level) {
|
||||
super.tickNode(level)
|
||||
if (bound == "screen/unbound" && level.isClientSide) { // am i epstein or am i just retarded?
|
||||
createscreenstuffs()
|
||||
override val deviceNode = object : DeviceNode() {
|
||||
override fun received(message: Networking.Message) {
|
||||
super.received(message)
|
||||
if(message is Networking.ComputerEvent) {
|
||||
val mEnv = message.machineEvent
|
||||
NeoComputers.LOGGER.info("Got message $mEnv!")
|
||||
if(mEnv is MachinePowerEvent) {
|
||||
if(mEnv.nowRunning) {
|
||||
lastError = null
|
||||
textBuf.fill(0, 0, textBuf.width, textBuf.height, GPUChar(' '))
|
||||
textBuf.set(0, 0, address.toString())
|
||||
}
|
||||
isOn = mEnv.nowRunning
|
||||
markChanged()
|
||||
}
|
||||
if(mEnv is MachineCrashEvent) {
|
||||
lastError = mEnv.error
|
||||
markChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun encodeScreenData(player: ServerPlayer, buf: FriendlyByteBuf) {
|
||||
super.encodeScreenData(player, buf)
|
||||
textBuf.encodeContents(buf)
|
||||
}
|
||||
|
||||
override fun writeFullStateCommit(buf: FriendlyByteBuf) {
|
||||
super.writeFullStateCommit(buf)
|
||||
buf.writeUUID(address)
|
||||
buf.writeBoolean(isOn)
|
||||
buf.writeUtf(lastError ?: "")
|
||||
textBuf.encodeContents(buf)
|
||||
}
|
||||
|
||||
override fun processCommit(buf: FriendlyByteBuf) {
|
||||
super.processCommit(buf)
|
||||
if(Networking.changeNodeAddress(this, buf.readUUID())) createScreenTexture()
|
||||
isOn = buf.readBoolean()
|
||||
lastError = buf.readUtf().ifEmpty { null }
|
||||
textBuf.decodeContents(buf)
|
||||
}
|
||||
|
||||
override fun getComponent() = NNComponent("screen")
|
||||
}
|
||||
var bound = "screen/unbound"
|
||||
|
||||
val textBuf = TextBuffer(50, 16)
|
||||
|
||||
private var cleanRenderer: () -> Unit = { } // TODO: THIS SUCKS, FIND A BETTER WAY
|
||||
|
||||
override fun tickDevice(level: Level) {
|
||||
super.tickDevice(level)
|
||||
cleanRenderer()
|
||||
createScreenTexture()
|
||||
}
|
||||
|
||||
override fun setRemoved() {
|
||||
super.setRemoved()
|
||||
bound = "screen/unbound" // ensure no missing texture is displayed
|
||||
cleanrenderer()
|
||||
cleanRenderer()
|
||||
}
|
||||
|
||||
private fun createscreenstuffs() {
|
||||
bound = "screen/"+node.address.toString().replace("-", "_")
|
||||
NeoComputers.LOGGER.info(bound)
|
||||
private fun createScreenTexture() {
|
||||
bound = "screen/"+deviceNode.address.toString().replace("-", "_")
|
||||
if (level!!.isClientSide) {
|
||||
var buffer: MutableList<BufferRenderer.GPUChar> = mutableListOf()
|
||||
for(char in node.address.toString()) {
|
||||
buffer.add(BufferRenderer.GPUChar(char))
|
||||
if(lastError == null) {
|
||||
if(!isOn) {
|
||||
textBuf.fill(0, 0, textBuf.width, textBuf.height)
|
||||
}
|
||||
val renderer = BufferRenderer(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, bound), textBuf)
|
||||
renderer.drawBuffer()
|
||||
cleanRenderer = { renderer.clean() }
|
||||
} else {
|
||||
var trueError = lastError!!
|
||||
if(trueError.startsWith("@")) {
|
||||
val trans = trueError.substring(1)
|
||||
val lang = Language.getInstance()
|
||||
trueError = lang.getOrDefault("neocomputers.computer.errorNoMsg", "Error: ") + lang.getOrDefault(trans)
|
||||
}
|
||||
val throwAwayBuf = TextBuffer(50, 16)
|
||||
val fg = 0xFFFFFF
|
||||
val bg = 0x2B68A6
|
||||
throwAwayBuf.fill(0, 0, throwAwayBuf.width, throwAwayBuf.height, GPUChar(' ', fg, bg))
|
||||
throwAwayBuf.set((throwAwayBuf.width - trueError.length) / 2, throwAwayBuf.height/2, trueError, fg, bg)
|
||||
val renderer = BufferRenderer(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, bound), throwAwayBuf)
|
||||
renderer.drawBuffer()
|
||||
cleanRenderer = { renderer.clean() }
|
||||
}
|
||||
for (i in 0..((scrwidth*scrheight)-36)) {
|
||||
buffer.add(BufferRenderer.GPUChar(' '))
|
||||
}
|
||||
|
||||
var renderer: BufferRenderer = BufferRenderer(scrwidth.toInt(), scrheight.toInt(), ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, bound), buffer)
|
||||
renderer.drawBuffer()
|
||||
cleanrenderer = { renderer.clean() }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +1,38 @@
|
||||
package org.neoflock.neocomputers.entity
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.HolderLookup
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import org.neoflock.neocomputers.block.NodeBlockEntity
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
import org.neoflock.neocomputers.block.SingleDeviceBlockEntity
|
||||
import org.neoflock.neocomputers.network.DeviceNode
|
||||
import org.neoflock.neocomputers.network.PowerRole
|
||||
|
||||
class SolarGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) : NodeBlockEntity(BlockEntities.SOLARGEN_ENTITY.get(), blockPos, blockState) {
|
||||
val energyPerTick: Long = 50
|
||||
class SolarGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) : SingleDeviceBlockEntity(BlockEntities.SOLARGEN_ENTITY.get(), blockPos, blockState) {
|
||||
val energyPerTick: Long = 10
|
||||
|
||||
override val node = object : Networking.Node() {
|
||||
override val deviceNode = object : DeviceNode() {
|
||||
override var powerRole: PowerRole = PowerRole.GENERATOR
|
||||
override var energyCapacity: Long = 50000
|
||||
}
|
||||
|
||||
override fun tickNode(level: Level) {
|
||||
super.tickNode(level)
|
||||
override fun tickDevice(level: Level) {
|
||||
super.tickDevice(level)
|
||||
val l = level
|
||||
if(l.isDay) {
|
||||
node.giveEnergy(energyPerTick)
|
||||
deviceNode.giveEnergy(energyPerTick)
|
||||
}
|
||||
}
|
||||
|
||||
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
|
||||
super.loadAdditional(compoundTag, provider)
|
||||
node.energy = compoundTag.getLong("energy")
|
||||
deviceNode.energy = compoundTag.getLong("energy")
|
||||
}
|
||||
|
||||
override fun saveAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
|
||||
super.saveAdditional(compoundTag, provider)
|
||||
compoundTag.putLong("energy", node.energy)
|
||||
compoundTag.putLong("energy", deviceNode.energy)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.neoflock.neocomputers.entity.render
|
||||
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import com.mojang.blaze3d.vertex.VertexFormat
|
||||
import com.mojang.math.Axis
|
||||
import net.minecraft.client.renderer.MultiBufferSource
|
||||
import net.minecraft.client.renderer.RenderStateShard
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.entity.AssemblerEntity
|
||||
|
||||
class AssemblerEntityRenderer(val context: BlockEntityRendererProvider.Context) : BlockEntityRenderer<AssemblerEntity> {
|
||||
val RENDER_TYPE = {l: ResourceLocation ->
|
||||
RenderType.create("nc_assembler", DefaultVertexFormat.POSITION_TEX, VertexFormat.Mode.QUADS, RenderType.TRANSIENT_BUFFER_SIZE, RenderType.CompositeState.builder()
|
||||
.setTextureState(RenderStateShard.TextureStateShard(l, false, false))
|
||||
.setShaderState(RenderStateShard.ShaderStateShard.POSITION_TEX_SHADER)
|
||||
.createCompositeState(false))
|
||||
}
|
||||
|
||||
override fun render(blockEntity: AssemblerEntity, partialTick: Float, poseStack: PoseStack, bufferSource: MultiBufferSource, packedLight: Int, packedOverlay: Int) {
|
||||
var buffer = bufferSource.getBuffer(RENDER_TYPE(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/block/assembler_top_on.png")))
|
||||
val pose = poseStack.last()
|
||||
buffer.addVertex(pose, 0f, 17/16f, 1f).setUv(1f, 0f)
|
||||
buffer.addVertex(pose, 1f, 17/16f, 1f).setUv(1f, 1f)
|
||||
buffer.addVertex(pose, 1f, 17/16f, 0f).setUv(0f, 1f)
|
||||
buffer.addVertex(pose, 0f, 17/16f, 0f).setUv(0f, 0f)
|
||||
|
||||
// TODO: do assembling texture
|
||||
buffer = bufferSource.getBuffer(RENDER_TYPE(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/block/assembler_side_on.png")))
|
||||
poseStack.pushPose()
|
||||
for (i in 0..3) {
|
||||
val pose = poseStack.last()
|
||||
buffer.addVertex(pose, 1.001f, 1f, 0f).setUv(0f, 0f)
|
||||
buffer.addVertex(pose, 1.001f, 1f, 1f).setUv(1f, 0f)
|
||||
buffer.addVertex(pose, 1.001f, 0f, 1f).setUv(1f, 1f)
|
||||
buffer.addVertex(pose, 1.001f, 0f, 0f).setUv(0f, 1f)
|
||||
poseStack.rotateAround(Axis.YP.rotationDegrees(90f), 0.5f, 0.5f, 0.5f)
|
||||
}
|
||||
poseStack.popPose()
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
package org.neoflock.neocomputers.gui.render
|
||||
package org.neoflock.neocomputers.entity.render
|
||||
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer
|
||||
import com.mojang.blaze3d.vertex.VertexFormat
|
||||
import com.mojang.math.Axis
|
||||
import net.minecraft.client.renderer.LightTexture
|
||||
import net.minecraft.client.renderer.MultiBufferSource
|
||||
import net.minecraft.client.renderer.RenderStateShard
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
@@ -15,7 +16,8 @@ import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.block.CaseBlock
|
||||
import org.neoflock.neocomputers.entity.CaseBlockEntity
|
||||
|
||||
class CaseEntityRenderer(private val context: BlockEntityRendererProvider.Context?) : BlockEntityRenderer<CaseBlockEntity>{
|
||||
class CaseEntityRenderer(private val context: BlockEntityRendererProvider.Context?) :
|
||||
BlockEntityRenderer<CaseBlockEntity> {
|
||||
|
||||
val OFF = 0xFF5F855E.toInt()
|
||||
val GREEN = 0xFF4EDC5E.toInt()
|
||||
@@ -23,9 +25,10 @@ class CaseEntityRenderer(private val context: BlockEntityRendererProvider.Contex
|
||||
|
||||
val BLINKTIME: Long = 10 // in ticks
|
||||
|
||||
val RENDER_TYPE = RenderType.create("nc_case", DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.QUADS,
|
||||
val RENDER_TYPE = RenderType.create("nc_case", DefaultVertexFormat.POSITION_COLOR_LIGHTMAP, VertexFormat.Mode.QUADS,
|
||||
RenderType.TRANSIENT_BUFFER_SIZE, RenderType.CompositeState.builder()
|
||||
.setShaderState(RenderStateShard.POSITION_COLOR_SHADER)
|
||||
.setShaderState(RenderStateShard.POSITION_COLOR_LIGHTMAP_SHADER)
|
||||
.setLightmapState(RenderStateShard.LightmapStateShard.LIGHTMAP)
|
||||
.createCompositeState(false))
|
||||
|
||||
override fun render(ent: CaseBlockEntity, partialTick: Float, mat: PoseStack, bufferSource: MultiBufferSource, packedLight: Int, packedOverlay: Int) {
|
||||
@@ -38,20 +41,20 @@ class CaseEntityRenderer(private val context: BlockEntityRendererProvider.Contex
|
||||
if (ent.isOn) drawLED(buffer, mat.last(), 3F)
|
||||
else if (ent.getLastError() != null) { // if else hell
|
||||
if ((ent.level!!.dayTime/BLINKTIME) % 2 == 1.toLong()) drawLED(buffer, mat.last(), 3F, RED)
|
||||
else drawLED(buffer, mat.last(), 3F, OFF)
|
||||
} else drawLED(buffer, mat.last(), 3F, OFF)
|
||||
else drawLED(buffer, mat.last(), 3F, OFF, packedLight)
|
||||
} else drawLED(buffer, mat.last(), 3F, OFF, packedLight)
|
||||
|
||||
mat.translate(6/16F, 0F, 0F)
|
||||
drawLED(buffer, mat.last(), 2F, if (ent.isDisking) GREEN else OFF)
|
||||
drawLED(buffer, mat.last(), 2F, if (ent.diskActivityTime > 0) GREEN else OFF, if (ent.diskActivityTime > 0) LightTexture.FULL_BRIGHT else packedLight)
|
||||
|
||||
mat.popPose()
|
||||
|
||||
}
|
||||
private fun drawLED(buffer: VertexConsumer, mat: PoseStack.Pose, width: Float, color: Int = GREEN) {
|
||||
buffer.addVertex(mat, width/16F, 0F, 0F).setColor(color)
|
||||
buffer.addVertex(mat, width/16F, 1/16F, 0F).setColor(color)
|
||||
buffer.addVertex(mat, 0F, 1/16F, 0F).setColor(color)
|
||||
buffer.addVertex(mat, 0F, 0F, 0F).setColor(color)
|
||||
private fun drawLED(buffer: VertexConsumer, mat: PoseStack.Pose, width: Float, color: Int = GREEN, light: Int = LightTexture.FULL_BRIGHT) {
|
||||
buffer.addVertex(mat, width/16F, 0F, 0F).setColor(color).setLight(light)
|
||||
buffer.addVertex(mat, width/16F, 1/16F, 0F).setColor(color).setLight(light)
|
||||
buffer.addVertex(mat, 0F, 1/16F, 0F).setColor(color).setLight(light)
|
||||
buffer.addVertex(mat, 0F, 0F, 0F).setColor(color).setLight(light)
|
||||
}
|
||||
|
||||
private fun handleDirection(facing: Direction, mat: PoseStack) {
|
||||
@@ -63,4 +66,4 @@ class CaseEntityRenderer(private val context: BlockEntityRendererProvider.Contex
|
||||
else -> return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.neoflock.neocomputers.entity.render
|
||||
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderers
|
||||
import org.neoflock.neocomputers.entity.BlockEntities
|
||||
|
||||
object EntityRenderers {
|
||||
fun registerBlockEntityRenderers() {
|
||||
BlockEntityRenderers.register(BlockEntities.SCREEN_ENTITY.get(), ::ScreenEntityRenderer); // TODO: put this in common
|
||||
BlockEntityRenderers.register(BlockEntities.CASE_ENTITY.get(), ::CaseEntityRenderer);
|
||||
BlockEntityRenderers.register(BlockEntities.RELAY_ENTITY.get(), ::RelayEntityRenderer);
|
||||
BlockEntityRenderers.register(BlockEntities.ROBOT_ENTITY.get(), ::RobotEntityRenderer);
|
||||
BlockEntityRenderers.register(BlockEntities.RACK_ENTITY.get(), ::RackEntityRenderer);
|
||||
BlockEntityRenderers.register(BlockEntities.ASSEMBLER_ENTITY.get(), ::AssemblerEntityRenderer)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.neoflock.neocomputers.entity.render
|
||||
|
||||
import com.mojang.authlib.minecraft.client.MinecraftClient
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.renderer.LevelRenderer
|
||||
import net.minecraft.client.renderer.LightTexture
|
||||
import net.minecraft.client.renderer.MultiBufferSource
|
||||
import net.minecraft.client.renderer.block.ModelBlockRenderer
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider
|
||||
import net.minecraft.world.level.LightLayer
|
||||
import net.minecraft.world.level.dimension.DimensionType
|
||||
import net.minecraft.world.level.lighting.BlockLightEngine
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.entity.RackEntity
|
||||
import org.neoflock.neocomputers.item.RackItem
|
||||
|
||||
class RackEntityRenderer(val context: BlockEntityRendererProvider.Context) : BlockEntityRenderer<RackEntity> {
|
||||
|
||||
override fun render(ent: RackEntity, partialTick: Float, poseStack: PoseStack, source: MultiBufferSource, packedLight: Int, packedOverlay: Int) {
|
||||
poseStack.pushPose()
|
||||
poseStack.translate(1/16f, 11/16f, 1/16f)
|
||||
|
||||
val items = ent.stacks
|
||||
for (i in 0..3) {
|
||||
if (items[i].item is RackItem) {
|
||||
val item = items[i].item as RackItem
|
||||
item.render(source, poseStack, packedLight, 2f+(3*i))
|
||||
}
|
||||
poseStack.translate(0f, -3/16f, 0f)
|
||||
}
|
||||
// val render_slot = (ent.level!!.dayTime/40)%4 // this is purely temporary type shit like true alpha shit, anyway it go to 0-3, change and test it if you want
|
||||
// poseStack.translate(0f, (render_slot)*-3/16f, 0f)
|
||||
// val server = object : RackItem { override fun render_lights(source: MultiBufferSource, stack: PoseStack, light: Int) { } }
|
||||
// server.render(source, poseStack, packedLight, 2f+(3*render_slot)) // who knows atp
|
||||
poseStack.popPose()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package org.neoflock.neocomputers.entity.render
|
||||
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import com.mojang.blaze3d.vertex.VertexFormat
|
||||
import com.mojang.math.Axis
|
||||
import net.minecraft.client.renderer.GameRenderer
|
||||
import net.minecraft.client.renderer.MultiBufferSource
|
||||
import net.minecraft.client.renderer.RenderStateShard
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.block.RelayEntity
|
||||
import java.util.Timer
|
||||
import kotlin.math.min
|
||||
|
||||
class RelayEntityRenderer(val context: BlockEntityRendererProvider.Context?): BlockEntityRenderer<RelayEntity> {
|
||||
val RELAY_ON_TEX = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/block/relay_side_on.png")
|
||||
|
||||
val RENDER_TYPE: RenderType =
|
||||
RenderType.create(
|
||||
"nc_screen",
|
||||
DefaultVertexFormat.POSITION_TEX_COLOR,
|
||||
VertexFormat.Mode.QUADS,
|
||||
RenderType.TRANSIENT_BUFFER_SIZE, RenderType.CompositeState.builder().
|
||||
setShaderState(RenderStateShard.ShaderStateShard(GameRenderer::getPositionTexColorShader)).
|
||||
setTextureState(RenderStateShard.TextureStateShard(RELAY_ON_TEX, false, false))
|
||||
.createCompositeState(false))
|
||||
|
||||
override fun render(
|
||||
blockEntity: RelayEntity,
|
||||
partialTick: Float,
|
||||
mat: PoseStack,
|
||||
bufferSource: MultiBufferSource,
|
||||
packedLight: Int,
|
||||
packedOverlay: Int
|
||||
) {
|
||||
if(blockEntity.activityTickLeft == 0) return
|
||||
|
||||
val alpha = min((blockEntity.activityTickLeft.toFloat() * 255 / 20).toInt(), 255)
|
||||
|
||||
for(i in 0..<4) {
|
||||
mat.pushPose()
|
||||
|
||||
val antiZFight = 0.001F
|
||||
|
||||
mat.rotateAround(Axis.YN.rotationDegrees(90F * i), 0.5F, 0.5F, 0.5F)
|
||||
mat.translate(0F, 0F, 1F + antiZFight)
|
||||
|
||||
val width = 1F
|
||||
val height = 1F
|
||||
val bx = 0F
|
||||
val by = 0F
|
||||
|
||||
val buffer = bufferSource.getBuffer(RENDER_TYPE)
|
||||
buffer.addVertex(mat.last(), bx + width, by, 0f).setUv(1f, 1f).setColor(alpha, alpha, alpha, alpha)
|
||||
buffer.addVertex(mat.last(), bx + width, by + height, 0f).setUv(1f, 0f).setColor(alpha, alpha, alpha, alpha)
|
||||
buffer.addVertex(mat.last(), bx, by + height, 0f).setUv(0f, 0f).setColor(alpha, alpha, alpha, alpha)
|
||||
buffer.addVertex(mat.last(), bx, by, 0f).setUv(0f, 1f).setColor(alpha, alpha, alpha, alpha)
|
||||
|
||||
mat.popPose()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package org.neoflock.neocomputers.entity.render
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer
|
||||
import com.mojang.blaze3d.vertex.VertexFormat
|
||||
import com.mojang.math.Axis
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.Font
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.client.renderer.GameRenderer
|
||||
import net.minecraft.client.renderer.ItemBlockRenderTypes
|
||||
import net.minecraft.client.renderer.MultiBufferSource
|
||||
import net.minecraft.client.renderer.RenderStateShard
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import net.minecraft.client.renderer.RenderType.CompositeState
|
||||
import net.minecraft.client.renderer.block.ModelBlockRenderer
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider
|
||||
import net.minecraft.client.renderer.blockentity.ChestRenderer
|
||||
import net.minecraft.client.renderer.entity.EntityRenderer
|
||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture
|
||||
import net.minecraft.client.renderer.texture.TextureAtlas
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite
|
||||
import net.minecraft.client.resources.model.BakedModel
|
||||
import net.minecraft.client.resources.model.Material
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation
|
||||
import net.minecraft.client.resources.model.ModelState
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.world.item.DyeColor
|
||||
import net.minecraft.world.level.block.entity.ChestBlockEntity
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.block.model.RobotModel
|
||||
import org.neoflock.neocomputers.entity.RobotEntity
|
||||
import kotlin.math.sin
|
||||
|
||||
class RobotEntityRenderer(val context: BlockEntityRendererProvider.Context) : BlockEntityRenderer<RobotEntity> {
|
||||
val atlas: (Material) -> TextureAtlasSprite = { m ->
|
||||
Minecraft.getInstance().getTextureAtlas(m.atlasLocation()).apply(m.texture())
|
||||
}
|
||||
val loc: ResourceLocation = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "robot")
|
||||
var model: BakedModel? = Minecraft.getInstance().modelManager.getModel(ModelResourceLocation.inventory(loc))
|
||||
val renderer: ModelBlockRenderer = ModelBlockRenderer(Minecraft.getInstance().blockColors) // so ass
|
||||
|
||||
val STREAK_RENDER_TYPE = RenderType.create("nc_robot_streak", DefaultVertexFormat.POSITION_TEX_COLOR, VertexFormat.Mode.QUADS, RenderType.TRANSIENT_BUFFER_SIZE,
|
||||
CompositeState.builder()
|
||||
.setShaderState(RenderStateShard.ShaderStateShard { GameRenderer.getPositionTexColorShader() })
|
||||
.setTransparencyState(RenderStateShard.ADDITIVE_TRANSPARENCY)
|
||||
.setCullState(RenderStateShard.CullStateShard.NO_CULL)
|
||||
.setTextureState(RenderStateShard.TextureStateShard(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/block/robot.png"), false, false))
|
||||
.createCompositeState(false))
|
||||
|
||||
override fun render(ent: RobotEntity, partialTick: Float, poseStack: PoseStack, bufferSource: MultiBufferSource, packedLight: Int, packedOverlay: Int) {
|
||||
poseStack.pushPose()
|
||||
// poseStack.translate(0f, sin(ent.level!!.dayTime.toFloat()/20F)*0.02F, 0f)
|
||||
val modelbuffer = bufferSource.getBuffer(RenderType.entitySolid(TextureAtlas.LOCATION_BLOCKS))
|
||||
val colorbuffer = bufferSource.getBuffer(STREAK_RENDER_TYPE)
|
||||
|
||||
val col = DyeColor.LIGHT_GRAY.fireworkColor
|
||||
val red = ((col and 0xFF0000) shr 8*2) / 255f
|
||||
val green = ((col and 0xFF00) shr 8) / 255f
|
||||
val blue = ((col and 0xFF)) / 255f
|
||||
|
||||
renderer.renderModel(poseStack.last(), modelbuffer, ent.blockState, model!!, red, green, blue, packedLight, packedOverlay)
|
||||
renderLight(poseStack, colorbuffer, (ent.level!!.dayTime%16).toInt())
|
||||
|
||||
|
||||
// TODO: crafting table and chest little models
|
||||
// EntityRenderer
|
||||
|
||||
renderTag(ent, Component.literal(ent.name), poseStack, bufferSource, packedLight, partialTick)
|
||||
poseStack.popPose()
|
||||
}
|
||||
|
||||
// offset is 0-15
|
||||
fun renderLight(poseStack: PoseStack, buffer: VertexConsumer, offset: Int) {
|
||||
poseStack.pushPose()
|
||||
|
||||
val u1 = 0.5f
|
||||
val v1 = 0.5f + offset*1/32f
|
||||
val u2 = 1F
|
||||
val v2 = 17/32f + offset*1/32f
|
||||
|
||||
for (i in 0..3) {
|
||||
poseStack.rotateAround(Axis.YP.rotationDegrees(90f), 0.5f, 0.5f, 0.5f)
|
||||
|
||||
buffer.addVertex(poseStack.last(),0.1f+2/16f, 7/16f, 0.9f-2/16f).setColor(1f, 0f, 0f, 1f).setUv(u2, v2)
|
||||
buffer.addVertex(poseStack.last(),0.1f+2/16f, 9/16f, 0.9f-2/16f).setColor(1f, 0f, 0f, 1f).setUv(u2, v1)
|
||||
buffer.addVertex(poseStack.last(),0.1f+2/16f, 9/16f, 0.1f+2/16f).setColor(1f, 0f, 0f, 1f).setUv(u1, v1)
|
||||
buffer.addVertex(poseStack.last(),0.1f+2/16f, 7/16f, 0.1f+2/16f).setColor(1f, 0f, 0f, 1f).setUv(u1, v2)
|
||||
}
|
||||
|
||||
poseStack.popPose()
|
||||
|
||||
|
||||
}
|
||||
|
||||
fun renderTag(ent: RobotEntity, name: Component, stack: PoseStack, source: MultiBufferSource, light: Int, ptick: Float) {
|
||||
val d = Minecraft.getInstance().cameraEntity!!.distanceToSqr(ent.blockPos.center)
|
||||
if (d > 4096.0) return
|
||||
|
||||
val vec = Vec3(0.5, 20 / 16.0, 0.5)
|
||||
|
||||
stack.pushPose()
|
||||
stack.translate(vec.x, vec.y, vec.z)
|
||||
stack.mulPose(context.entityRenderer.cameraOrientation())
|
||||
stack.scale(0.025F, -0.025F, 0.025F)
|
||||
val opacity = Minecraft.getInstance().options.getBackgroundOpacity(0.25F)
|
||||
val alpha: Int = (opacity * 255.0f).toInt() shl 24
|
||||
// val alpha = 255
|
||||
val halfwidth = (-context.font.width(name)) / 2;
|
||||
// RenderSystem.enableDepthTest()
|
||||
// RenderSystem.enableBlend()
|
||||
// RenderSystem.depthMask(true)
|
||||
|
||||
context.font.drawInBatch(name, halfwidth.toFloat(), 2f, 0xFFFFFF, false, stack.last().pose(), source, Font.DisplayMode.SEE_THROUGH, alpha, light)
|
||||
(source as MultiBufferSource.BufferSource).endBatch()
|
||||
stack.popPose()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,26 +1,20 @@
|
||||
package org.neoflock.neocomputers.gui.render
|
||||
package org.neoflock.neocomputers.entity.render
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer
|
||||
import com.mojang.blaze3d.vertex.VertexFormat
|
||||
import com.mojang.math.Axis
|
||||
import net.minecraft.client.renderer.GameRenderer
|
||||
import net.minecraft.client.renderer.MultiBufferSource
|
||||
import net.minecraft.client.renderer.RenderStateShard
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider
|
||||
import net.minecraft.client.renderer.blockentity.ChestRenderer
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.block.ScreenBlock
|
||||
import org.neoflock.neocomputers.entity.ScreenEntity
|
||||
|
||||
|
||||
class ScreenEntityRenderer(val context: BlockEntityRendererProvider.Context?) : BlockEntityRenderer<ScreenEntity> { // TODO: FORGE
|
||||
val RENDER_TYPE: (ResourceLocation) -> RenderType = { t: ResourceLocation ->
|
||||
RenderType.create(
|
||||
@@ -33,30 +27,45 @@ class ScreenEntityRenderer(val context: BlockEntityRendererProvider.Context?) :
|
||||
.createCompositeState(false))
|
||||
}
|
||||
override fun render(entity: ScreenEntity, partialTick: Float, mat: PoseStack, bufferSource: MultiBufferSource, packedLight: Int, packedOverlay: Int) {
|
||||
val facing = entity.blockState.getValue(ScreenBlock.FACING)
|
||||
if(!entity.isOn && entity.lastError == null) return
|
||||
val facing = entity.blockState.getValue(ScreenBlock.FACING_HORIZ)
|
||||
val vert = entity.blockState.getValue(ScreenBlock.FACING_VERTI)-1
|
||||
|
||||
mat.pushPose()
|
||||
handleDirection(facing, mat)
|
||||
handleDirection(facing, vert, mat)
|
||||
mat.translate(2 / 16f, 2 / 16f, 0.0001f) // am i epstein or am i just retarded
|
||||
|
||||
val width = 3/4F
|
||||
val height = 3/4F
|
||||
val bx = 0F
|
||||
val by = 0F
|
||||
|
||||
val rendertype = RENDER_TYPE(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, entity.bound))
|
||||
val buffer = bufferSource.getBuffer(rendertype)
|
||||
buffer.addVertex(mat.last(), 3 / 4f, 0f, 0f).setUv(1f, 1f)
|
||||
buffer.addVertex(mat.last(), 3 / 4f, 3 / 4f, 0f).setUv(1f, 0f)
|
||||
buffer.addVertex(mat.last(), 0f, 3 / 4f, 0f).setUv(0f, 0f)
|
||||
buffer.addVertex(mat.last(), 0f, 0f, 0f).setUv(0f, 1f)
|
||||
buffer.addVertex(mat.last(), bx+width, by, 0f).setUv(1f, 1f)
|
||||
buffer.addVertex(mat.last(), bx+width, by+height, 0f).setUv(1f, 0f)
|
||||
buffer.addVertex(mat.last(), bx, by+height, 0f).setUv(0f, 0f)
|
||||
buffer.addVertex(mat.last(), bx, by, 0f).setUv(0f, 1f)
|
||||
|
||||
mat.popPose()
|
||||
}
|
||||
|
||||
private fun handleDirection(facing: Direction, mat: PoseStack) { // TODO: separate up and down from cardinal directions
|
||||
private fun handleDirection(facing: Direction, vert: Int, mat: PoseStack) { // TODO: separate up and down from cardinal directions
|
||||
// mat.mulPose(Axis.XN.rotationDegrees(vert.toFloat()*90F))
|
||||
// if (vert==0) {
|
||||
// mat.mulPose(Axis.YP.rotationDegrees(90F))
|
||||
// return
|
||||
// }
|
||||
when (facing) {
|
||||
Direction.SOUTH -> { mat.translate(0F, 0F, 1F) }
|
||||
Direction.EAST -> { mat.mulPose(Axis.YP.rotationDegrees(90F)); mat.translate(-1F, 0F, 1F) }
|
||||
Direction.WEST -> { mat.mulPose(Axis.YN.rotationDegrees(90F)); }
|
||||
Direction.NORTH -> {mat.mulPose(Axis.YP.rotationDegrees(180F)); mat.translate(-1F, 0F, 0F) }
|
||||
Direction.UP -> { mat.mulPose(Axis.XN.rotationDegrees(90F)); mat.mulPose(Axis.ZP.rotationDegrees(180F)); mat.translate(-1F, 0F, 1F) } // idek
|
||||
Direction.DOWN -> { mat.mulPose(Axis.XP.rotationDegrees(90F)); mat.mulPose(Axis.ZN.rotationDegrees(180F)); mat.translate(-1F, -1F, 0F) }
|
||||
else -> {}
|
||||
// Direction.UP -> { mat.mulPose(Axis.XN.rotationDegrees(90F)); mat.mulPose(Axis.ZP.rotationDegrees(180F)); mat.translate(-1F, 0F, 1F) } // idek
|
||||
// Direction.DOWN -> { mat.mulPose(Axis.XP.rotationDegrees(90F)); mat.mulPose(Axis.ZN.rotationDegrees(180F)); mat.translate(-1F, -1F, 0F) }
|
||||
}
|
||||
mat.mulPose(Axis.XN.rotationDegrees(vert*90F))
|
||||
mat.translate(0F, if (vert==-1) -1F else 0F, if (vert==1) 1F else 0F)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.neoflock.neocomputers.gui.menu
|
||||
|
||||
import net.fabricmc.fabric.mixin.item.client.HeldItemRendererMixin
|
||||
import net.minecraft.client.gui.MapRenderer
|
||||
import net.minecraft.client.renderer.entity.ItemRenderer
|
||||
import net.minecraft.world.Container
|
||||
import net.minecraft.world.SimpleContainer
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import org.neoflock.neocomputers.block.Blocks
|
||||
import org.neoflock.neocomputers.gui.widget.DynamicSlot
|
||||
import org.neoflock.neocomputers.utils.GenericContainer
|
||||
import org.neoflock.neocomputers.utils.GenericContainerMenu
|
||||
|
||||
class CaseSlot(container: Container, index: Int, x: Int, y: Int) : DynamicSlot(container, index, x, y) {
|
||||
val caseItems = listOf(Blocks.CASE_BLOCK.get().asItem())
|
||||
|
||||
override fun mayPlace(stack: ItemStack): Boolean = stack.item in caseItems
|
||||
}
|
||||
|
||||
class AssemblerMenu : GenericContainerMenu {
|
||||
|
||||
constructor(id: Int, inv: Inventory) : this(id, inv, SimpleContainer(1))
|
||||
constructor(id: Int, inv: Inventory, container: Container) : super(Menus.ASSEMBLER_MENU.get(), id, container) {
|
||||
this.addSlot(CaseSlot(container, 0, 12, 12))
|
||||
|
||||
this.addInventoryHotbar(inv, 8, 84)
|
||||
}
|
||||
}
|
||||
@@ -10,21 +10,30 @@ import net.minecraft.world.flag.FeatureFlags
|
||||
import net.minecraft.world.inventory.MenuType
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.gui.menu.ScreenMenu
|
||||
import org.neoflock.neocomputers.gui.screen.AssemblerScreen
|
||||
import org.neoflock.neocomputers.gui.screen.CaseScreen
|
||||
import org.neoflock.neocomputers.gui.screen.CombustionGeneratorScreen
|
||||
import org.neoflock.neocomputers.gui.screen.RackScreen
|
||||
import org.neoflock.neocomputers.gui.screen.RelayScreen
|
||||
import org.neoflock.neocomputers.gui.screen.ScreenScreen
|
||||
|
||||
object Menus {
|
||||
val MENUS: DeferredRegister<MenuType<*>> = DeferredRegister.create(NeoComputers.MODID, Registries.MENU)
|
||||
|
||||
// val SCREEN_MENU: RegistrySupplier<MenuType<ScreenMenu>> = MENUS.register("screen_menu") { MenuType(::ScreenMenu, FeatureFlagSet.of()) }
|
||||
val SCREEN_MENU: RegistrySupplier<MenuType<ScreenMenu>> = MENUS.register("screen_menu") { MenuRegistry.ofExtended<ScreenMenu>(::ScreenMenu) }
|
||||
val COMBUSTGEN_MENU: RegistrySupplier<MenuType<CombustionGeneratorMenu>> = MENUS.register("combustgen_menu") { MenuType(::CombustionGeneratorMenu, FeatureFlagSet.of() ) }
|
||||
val CASE_MENU: RegistrySupplier<MenuType<CaseMenu>> = MENUS.register("case_menu") { MenuType(::CaseMenu, FeatureFlagSet.of() )}
|
||||
val RELAY_MENU: RegistrySupplier<MenuType<RelayMenu>> = MENUS.register("relay_menu") { MenuType(::RelayMenu, FeatureFlagSet.of() )}
|
||||
val RACK_MENU: RegistrySupplier<MenuType<RackMenu>> = MENUS.register("rack_menu") { MenuRegistry.ofExtended(::RackMenu) }
|
||||
val ASSEMBLER_MENU: RegistrySupplier<MenuType<AssemblerMenu>> = MENUS.register("assembler_menu") { MenuType(::AssemblerMenu, FeatureFlagSet.of() )}
|
||||
// val RACK_MENU: RegistrySupplier<MenuType<RackMenu>> = MENUS.register("rack_menu") { MenuType(::RackMenu, FeatureFlagSet.of() )}
|
||||
|
||||
fun registerScreens() {
|
||||
MenuScreens.register(Menus.COMBUSTGEN_MENU.get()) { m: CombustionGeneratorMenu, u, comp ->CombustionGeneratorScreen(m,u,comp)}
|
||||
MenuScreens.register(Menus.SCREEN_MENU.get(), ::ScreenScreen)
|
||||
MenuScreens.register(Menus.CASE_MENU.get(), ::CaseScreen)
|
||||
MenuScreens.register(Menus.RELAY_MENU.get(), ::RelayScreen)
|
||||
MenuScreens.register(Menus.RACK_MENU.get(), ::RackScreen)
|
||||
MenuScreens.register(Menus.ASSEMBLER_MENU.get(), ::AssemblerScreen)
|
||||
}
|
||||
}
|
||||
193
src/main/kotlin/org/neoflock/neocomputers/gui/menu/RackMenu.kt
Normal file
193
src/main/kotlin/org/neoflock/neocomputers/gui/menu/RackMenu.kt
Normal file
@@ -0,0 +1,193 @@
|
||||
package org.neoflock.neocomputers.gui.menu
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import com.mojang.blaze3d.vertex.BufferUploader
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat
|
||||
import com.mojang.blaze3d.vertex.Tesselator
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer
|
||||
import com.mojang.blaze3d.vertex.VertexFormat
|
||||
import io.netty.buffer.Unpooled
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener
|
||||
import net.minecraft.client.renderer.GameRenderer
|
||||
import net.minecraft.client.renderer.MultiBufferSource
|
||||
import net.minecraft.client.renderer.RenderStateShard
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import net.minecraft.world.Container
|
||||
import net.minecraft.world.SimpleContainer
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.entity.RackEntity
|
||||
import org.neoflock.neocomputers.gui.widget.ComponentRoles
|
||||
import org.neoflock.neocomputers.gui.widget.DynamicSlot
|
||||
import org.neoflock.neocomputers.item.ComponentItem
|
||||
import org.neoflock.neocomputers.utils.GenericContainerMenu
|
||||
|
||||
class RackSlot(container: Container, slot: Int, x: Int, y: Int) : DynamicSlot(container, slot, x, y), GuiEventListener {
|
||||
// i hate that i made this, my regret is immeasurable
|
||||
// i genuinely cant help myself
|
||||
val MAIN_COLOURS = listOf(0xff8382d8.toInt(), 0xff75bdc1.toInt(), 0xffc8ca5f.toInt(), 0xffdb7d75.toInt(), 0xff7ec95f.toInt())
|
||||
val DARK_COLOURS = listOf(0xff6a6ab0.toInt(), 0xff60999d.toInt(), 0xffa2a44e.toInt(), 0xffb36660.toInt(), 0xff67a34e.toInt())
|
||||
val LIGHT_COLOURS = listOf(0xffdcdcf0.toInt(), 0xffdcdcf0.toInt(), 0xffececd4.toInt(), 0xfff0dbd9.toInt(), 0xffdbecd4.toInt())
|
||||
|
||||
val secondaries = 2 // TODO: make this actually change depending on how many network cards
|
||||
|
||||
// todo: kotlin getters and setters
|
||||
fun getSelected(i: Int): Int = (container as RackEntity).conns[containerSlot*4+i]
|
||||
fun setSelected(i: Int, v: Int) { (container as RackEntity).conns[containerSlot*4+i] = v }
|
||||
|
||||
override fun draw(graphics: GuiGraphics, mouseX: Int, mouseY: Int) {
|
||||
super.draw(graphics, mouseX, mouseY)
|
||||
if (!hasItem()) { drawQuad(graphics, ComponentRoles.getTextureFor("rack"), x, y, 16, 16, 0f, 0f, 15f, 15f); return; }
|
||||
for (i in 0..secondaries) {
|
||||
if (getSelected(i) > -1) drawConnection(graphics, getSelected(i), i-1)
|
||||
}
|
||||
|
||||
drawEndpoints(graphics, mouseX, mouseY, secondaries)
|
||||
}
|
||||
|
||||
override fun mayPlace(stack: ItemStack): Boolean {
|
||||
if (stack.item !is ComponentItem) return false
|
||||
return (stack.item as ComponentItem).getComponentRoles(stack).contains(ComponentRoles.RACK_MOUNTABLE)
|
||||
}
|
||||
|
||||
override fun onTake(player: Player, stack: ItemStack) {
|
||||
super.onTake(player, stack)
|
||||
setSelected(0, -1)
|
||||
setSelected(1, -1)
|
||||
setSelected(2, -1)
|
||||
setSelected(3, -1)
|
||||
(container as RackEntity).setChanged()
|
||||
|
||||
}
|
||||
|
||||
fun drawConnection(guiGraphics: GuiGraphics, side: Int, sec: Int = -1) {
|
||||
val bufferSource = guiGraphics.bufferSource()
|
||||
val buffer = bufferSource.getBuffer(RenderType.gui())
|
||||
|
||||
if (sec == -1) {
|
||||
drawColor(guiGraphics, buffer, 18, 1, DARK_COLOURS[side], 6 + (11 * side))
|
||||
drawColor(guiGraphics, buffer, 18, 2, MAIN_COLOURS[side], 6 + (11 * side))
|
||||
drawColor(guiGraphics, buffer, 18, 3, LIGHT_COLOURS[side], 6 + (11 * side))
|
||||
} else {
|
||||
drawColor(guiGraphics, buffer, 18, 6+(4*sec), MAIN_COLOURS[side], 6+(11*side))
|
||||
drawColor(guiGraphics, buffer, 18, 7+(4*sec), 0xff8f8f90.toInt(), 6+(11*side))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun drawEndpoints(guiGraphics: GuiGraphics, mx: Int, my: Int, sec: Int =0) {
|
||||
val bufferSource = guiGraphics.bufferSource()
|
||||
val buffer = bufferSource.getBuffer(RenderType.gui())
|
||||
|
||||
// main slot endpoint
|
||||
drawColor(guiGraphics, buffer, 17, 1, 0xff888888.toInt())
|
||||
drawColor(guiGraphics, buffer, 17, 3, 0xffffffff.toInt())
|
||||
|
||||
// main cable endpoints
|
||||
for (i in 0..4) {
|
||||
drawColor(guiGraphics, buffer, 24+(11*i), 1, 0xff333333.toInt(), 1, 3)
|
||||
drawColor(guiGraphics, buffer, 25+(11*i), 1, MAIN_COLOURS[i], 3, 3)
|
||||
drawColor(guiGraphics, buffer, 28+(11*i), 1, 0xffffffff.toInt(), 1, 3)
|
||||
|
||||
// highlight
|
||||
if (mx >= x+25+(11*i) && mx <= x+27+(11*i) && my >= y+1 && my <= y+3) {
|
||||
drawColor(guiGraphics, buffer, 25+(11*i), 1, 0x80FFFFFF.toInt(), 3, 3)
|
||||
}
|
||||
}
|
||||
|
||||
// secondary endpoints
|
||||
for (i in 0..<sec) {
|
||||
// slot
|
||||
drawColor(guiGraphics, buffer, 17, 6+(4*i), 0xffffffff.toInt())
|
||||
drawColor(guiGraphics, buffer, 17, 7+(4*i), 0xff888888.toInt())
|
||||
|
||||
// cable
|
||||
for (j in 0..4) {
|
||||
drawColor(guiGraphics, buffer, 24+(11*j), 6+(4*i), 0xff333333.toInt(), 1, 2)
|
||||
drawColor(guiGraphics, buffer, 25+(11*j), 6+(4*i), MAIN_COLOURS[j], 3, 2)
|
||||
drawColor(guiGraphics, buffer, 28+(11*j), 6+(4*i), 0xffffffff.toInt(), 1, 2)
|
||||
|
||||
// highlight
|
||||
if (mx >= x+25+(11*j) && mx <= x+27+(11*j) && my >= y+6+(4*i) && my <= y+8+(4*i)) {
|
||||
drawColor(guiGraphics, buffer, 25+(11*j), 6+(4*i), 0x80FFFFFF.toInt(), 3, 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun encode(buf: FriendlyByteBuf) { // client -> server
|
||||
buf.writeInt(containerSlot)
|
||||
buf.writeInt(getSelected(0))
|
||||
buf.writeInt(getSelected(1))
|
||||
buf.writeInt(getSelected(2))
|
||||
buf.writeInt(getSelected(3))
|
||||
|
||||
}
|
||||
|
||||
// TODO: replace with graphics.fill (cant be assed atm)
|
||||
fun drawColor(guiGraphics: GuiGraphics, buffer: VertexConsumer, _x:Int, _y: Int, col: Int, width: Int=1, height: Int=1) {
|
||||
val pose = guiGraphics.pose().last()
|
||||
|
||||
// x+_x+1 is one im not proud of
|
||||
buffer.addVertex(pose, x+_x+width.toFloat(), y+_y+height.toFloat(), 2f).setColor(col)
|
||||
buffer.addVertex(pose, x+_x+width.toFloat(), y+_y.toFloat(), 2f).setColor(col)
|
||||
buffer.addVertex(pose, x+_x.toFloat(), y+_y.toFloat(), 2f).setColor(col)
|
||||
buffer.addVertex(pose, x+_x.toFloat(), y+_y+height.toFloat(), 2f).setColor(col)
|
||||
}
|
||||
|
||||
fun clickynoise() {
|
||||
val handler = Minecraft.getInstance().soundManager
|
||||
handler.play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F));
|
||||
}
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
for (i in 0..4) { // main line
|
||||
if (mouseX >= x+25+(11*i) && mouseX <= x+28+(11*i) && mouseY >= y+1 && mouseY <= y+4 && button == 0) {
|
||||
setSelected(0, if (getSelected(0) != i) i else -1)
|
||||
(container as RackEntity).setChanged()
|
||||
clickynoise()
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
for (i in 0..<secondaries) { // secondary lines
|
||||
for (j in 0..4) {
|
||||
if (mouseX >= x+25+(11*j) && mouseX <= x+28+(11*j) && mouseY >= y+6+(4*i) && mouseY <= y+8+(4*i) && button == 0) {
|
||||
setSelected(i+1, if (getSelected(i+1) != j) j else -1)
|
||||
(container as RackEntity).setChanged()
|
||||
clickynoise()
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.mouseClicked(mouseX, mouseY, button)
|
||||
}
|
||||
|
||||
override fun setFocused(focused: Boolean) {
|
||||
}
|
||||
|
||||
override fun isFocused(): Boolean {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
class RackMenu : GenericContainerMenu {
|
||||
|
||||
constructor(i: Int, inv: Inventory, buf: FriendlyByteBuf) : this(i, inv, (inv.player.level().getBlockEntity(buf.readBlockPos()) as RackEntity))
|
||||
|
||||
constructor(i: Int, inv: Inventory, container: Container) : super(Menus.RACK_MENU.get(), i, container) {
|
||||
for(i in 0..3) {
|
||||
val slot = RackSlot(container, i, 20, 23+i*20)
|
||||
this.addSlot(slot)
|
||||
}
|
||||
this.addInventorySlots(inv, 8, 128)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package org.neoflock.neocomputers.gui.menu
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.renderer.GameRenderer
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.Container
|
||||
import net.minecraft.world.SimpleContainer
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.block.RelayEntity
|
||||
import org.neoflock.neocomputers.gui.widget.ComponentRoles
|
||||
import org.neoflock.neocomputers.gui.widget.DynamicSlot
|
||||
import org.neoflock.neocomputers.item.ComponentItem
|
||||
import org.neoflock.neocomputers.item.RelayUpgrade
|
||||
import org.neoflock.neocomputers.utils.GenericContainerMenu
|
||||
|
||||
class RelaySlot(container: Container, slot: Int, x: Int, y: Int, val role: String, val relay: RelayEntity?) : DynamicSlot(container, slot, x, y) {
|
||||
override fun mayPlace(stack: ItemStack): Boolean {
|
||||
if(stack.isEmpty) return true
|
||||
val upgrade = stack.item as? RelayUpgrade ?: return false
|
||||
if(containerSlot == RelayEntity.CARD) {
|
||||
return upgrade.isRelayCompatibleCard(stack)
|
||||
}
|
||||
if(containerSlot == RelayEntity.CPU) {
|
||||
return upgrade.getRelayInterval(stack) != null
|
||||
}
|
||||
if(containerSlot == RelayEntity.MEM) {
|
||||
return upgrade.getRelayBufferSize(stack) != null
|
||||
}
|
||||
if(containerSlot == RelayEntity.STORAGE) {
|
||||
return upgrade.getRelayQueueSize(stack) != null
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun set(stack: ItemStack) {
|
||||
super.set(stack)
|
||||
val item = stack.item
|
||||
if(item is ComponentItem) {
|
||||
item.whenComponentPlaced(stack, relay, role)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTake(player: Player, stack: ItemStack) {
|
||||
super.onTake(player, stack)
|
||||
val item = stack.item
|
||||
if(item is ComponentItem) {
|
||||
item.whenComponentTaken(stack, relay, role)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMaxStackSize() = 1
|
||||
override fun getMaxStackSize(stack: ItemStack) = 1
|
||||
|
||||
override fun draw(graphics: GuiGraphics, mouseX: Int, mouseY: Int) {
|
||||
super.draw(graphics, mouseX, mouseY)
|
||||
if(!hasItem()) {
|
||||
drawQuad(graphics, ComponentRoles.getTextureFor(role), x-1, y-1, 18, 18, 0f, 0f, 15f, 15f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RelayMenu : GenericContainerMenu {
|
||||
constructor(i: Int, inv: Inventory) : this(i, inv, SimpleContainer(RelayEntity.SLOT_COUNT))
|
||||
|
||||
constructor(i: Int, inv: Inventory, container: Container) : super(Menus.RELAY_MENU.get(), i, container) {
|
||||
val relay = container as? RelayEntity
|
||||
|
||||
val relayMenuWidth = 176
|
||||
val itemX = 152
|
||||
val itemRowDist = 16
|
||||
val itemSpacing = 20
|
||||
|
||||
this.addSlot(RelaySlot(container, RelayEntity.CARD, relayMenuWidth+4, itemRowDist, ComponentRoles.NETWORK, relay))
|
||||
|
||||
this.addSlot(RelaySlot(container, RelayEntity.CPU, itemX, itemRowDist, ComponentRoles.COMPUTE, relay))
|
||||
this.addSlot(RelaySlot(container, RelayEntity.MEM, itemX, itemRowDist+itemSpacing, ComponentRoles.MEMORY, relay))
|
||||
this.addSlot(RelaySlot(container, RelayEntity.STORAGE, itemX, itemRowDist+itemSpacing*2, ComponentRoles.STORAGE, relay))
|
||||
|
||||
this.addInventorySlots(inv, 8, 84)
|
||||
}
|
||||
}
|
||||
@@ -7,16 +7,18 @@ import net.minecraft.client.renderer.texture.TextureManager
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.utils.FontProvider
|
||||
import org.neoflock.neocomputers.utils.GPUChar
|
||||
import org.neoflock.neocomputers.utils.TextBuffer
|
||||
import java.io.File
|
||||
import kotlin.experimental.and
|
||||
import kotlin.experimental.xor
|
||||
|
||||
class BufferRenderer(private var width: Int, private var height: Int, private var id: ResourceLocation, private var buffer: MutableList<GPUChar>) { // TODO: NN buffer
|
||||
class BufferRenderer(private var id: ResourceLocation, var buffer: TextBuffer) { // TODO: NN buffer
|
||||
val CHARW = 8
|
||||
val CHARH = 16
|
||||
|
||||
private var texwidth: Int = width*CHARW;
|
||||
private var texheight: Int = height*CHARH;
|
||||
private var texwidth: Int = buffer.width*CHARW;
|
||||
private var texheight: Int = buffer.height*CHARH;
|
||||
private var image: NativeImage = NativeImage(texwidth, texheight, true); // idk what the boolean is
|
||||
private var tex: DynamicTexture = DynamicTexture(image)
|
||||
|
||||
@@ -24,15 +26,11 @@ class BufferRenderer(private var width: Int, private var height: Int, private va
|
||||
Minecraft.getInstance().textureManager.register(this.id, tex)
|
||||
}
|
||||
|
||||
fun dump(path: String) {
|
||||
image.writeToFile(File(path))
|
||||
NeoComputers.LOGGER.info("DUMPED!!!")
|
||||
fun toRGBA(color: Int): Int {
|
||||
// Minecaft lies, its AGBR
|
||||
return java.lang.Integer.reverseBytes((color.toLong() * 256 + 0xFF).toInt())
|
||||
}
|
||||
|
||||
// fun toRGBA(color: Int): Int {
|
||||
// return color.shl(8).or(0xFF)
|
||||
// }
|
||||
|
||||
fun drawGlyph(x: Int, y: Int, c: Char, fg: Int) {
|
||||
var glyph: ArrayList<Byte> = FontProvider.map[c]!!
|
||||
|
||||
@@ -40,34 +38,27 @@ class BufferRenderer(private var width: Int, private var height: Int, private va
|
||||
for (i in 0..<CHARW) {
|
||||
// var pixel = ((glyph[j] and ((1 shl (CHARW - i - 1)).toByte())).toInt()) ushr (CHARW - i - 1) // retardation
|
||||
var pixel = (glyph[j] and (0b10000000 ushr i).toByte()).toInt()
|
||||
if (pixel > 0) image.setPixelRGBA(x+i, y+j, 0xFF000000.toInt()+fg)
|
||||
if (pixel > 0) image.setPixelRGBA(x+i, y+j, toRGBA(fg))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun drawBuffer() {
|
||||
for (i in 0..<width) {
|
||||
for (j in 0..<height) {
|
||||
var char: GPUChar = get(i, j)
|
||||
for (i in 0..<buffer.width) {
|
||||
for (j in 0..<buffer.height) {
|
||||
var char: GPUChar = buffer.get(i, j)
|
||||
var x = i*CHARW
|
||||
var y = j*CHARH
|
||||
image.fillRect(x, y, CHARW, CHARH, (0xFF000000+char.bg).toInt())
|
||||
image.fillRect(x, y, CHARW, CHARH, toRGBA(char.bg))
|
||||
if (char.c != ' ' && char.c != '\u0000') drawGlyph(x, y, char.c, char.fg)
|
||||
}
|
||||
}
|
||||
tex.upload()
|
||||
}
|
||||
|
||||
fun get(x: Int, y: Int) = buffer[y*width+x]
|
||||
fun set(x: Int, y: Int, c: GPUChar) {
|
||||
buffer[y*width+x] = c
|
||||
}
|
||||
|
||||
fun clean() {
|
||||
Minecraft.getInstance().textureManager.release(this.id)
|
||||
image.close()
|
||||
tex.close()
|
||||
}
|
||||
|
||||
data class GPUChar(val c: Char, val fg: Int =0xFFFFFF, val bg: Int = 0) // all is bgr
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.neoflock.neocomputers.gui.screen
|
||||
|
||||
import io.netty.buffer.Unpooled
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.gui.menu.AssemblerMenu
|
||||
import org.neoflock.neocomputers.gui.menu.CaseMenu
|
||||
import org.neoflock.neocomputers.gui.widget.ButtonSprites
|
||||
import org.neoflock.neocomputers.gui.widget.ImagerButton
|
||||
import org.neoflock.neocomputers.network.NodeSynchronizer
|
||||
import org.neoflock.neocomputers.utils.GenericContainerScreen
|
||||
|
||||
class AssemblerScreen : GenericContainerScreen<AssemblerMenu> {
|
||||
private var btn: ImagerButton? = null
|
||||
private val PCB: ResourceLocation = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/gui/computer.png")
|
||||
private val BTN: ResourceLocation = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/gui/button_power.png")
|
||||
|
||||
constructor(abstractContainerMenu: AssemblerMenu, inventory: Inventory, component: Component) : super(abstractContainerMenu, inventory, component) {
|
||||
btn = ImagerButton(
|
||||
8, 104,
|
||||
18, 18,
|
||||
ButtonSprites(BTN, 18, 18, 36, 36)
|
||||
) {
|
||||
// val buf = FriendlyByteBuf(Unpooled.buffer())
|
||||
// buf.writeByte(if(isOn) 0x02 else 0x01)
|
||||
// NodeSynchronizer.sendScreenInteraction(buf)
|
||||
}
|
||||
|
||||
addWidget(btn!!)
|
||||
}
|
||||
|
||||
override fun renderbg(guiGraphics: GuiGraphics, f: Float, i: Int, j: Int) {
|
||||
guiGraphics.blit(PCB, 0, 0, 0, 0, this.imageWidth, this.imageHeight) // WE'RE FREE
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.inventory.tooltip.TooltipComponent
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.block.NodeSynchronizer
|
||||
import org.neoflock.neocomputers.network.NodeSynchronizer
|
||||
import org.neoflock.neocomputers.gui.menu.CaseMenu
|
||||
import org.neoflock.neocomputers.gui.widget.ButtonSprites
|
||||
import org.neoflock.neocomputers.gui.widget.ImagerButton
|
||||
@@ -26,6 +26,7 @@ class CaseScreen : GenericContainerScreen<CaseMenu> {
|
||||
|
||||
private var btn: ImagerButton? = null
|
||||
override fun shouldCenterTitle(): Boolean = false
|
||||
// override fun findMenuTexture(): ResourceLocation = BG
|
||||
|
||||
var isOn = false
|
||||
var lastError: String? = null
|
||||
@@ -57,25 +58,27 @@ class CaseScreen : GenericContainerScreen<CaseMenu> {
|
||||
arch = buf.readUtf()
|
||||
}
|
||||
|
||||
fun getErrorComponent(err: String): Component = if(err.startsWith("@")) Component.translatable(err.substring(1)) else Component.literal(err)
|
||||
|
||||
fun computeButtonTooltip(): List<Component> {
|
||||
val msgs = mutableListOf(Component.literal("Computer " + if(isOn) "ON" else "OFF").withStyle(if(isOn) ChatFormatting.GREEN else ChatFormatting.RED))
|
||||
val msgs = mutableListOf(Component.translatable(if(isOn) "neocomputers.computer.on" else "neocomputers.computer.off").withStyle(if(isOn) ChatFormatting.GREEN else ChatFormatting.RED))
|
||||
if(lastError != null) {
|
||||
msgs.addLast(Component.literal("Error: ").withStyle(ChatFormatting.RED).append(Component.literal(lastError!!)))
|
||||
msgs.addLast(Component.translatable("neocomputers.computer.errorNoMsg").withStyle(ChatFormatting.RED).append(getErrorComponent(lastError!!)))
|
||||
}
|
||||
if(arch.isNotEmpty()) {
|
||||
msgs.addLast(Component.literal("Architecture: $arch"))
|
||||
msgs.addLast(Component.translatable("neocomputers.arch", arch))
|
||||
}
|
||||
if(hasShiftDown()) {
|
||||
msgs.addLast(Component.literal("Energy: $energy / $maxEnergy J").withStyle(if(energy < 100) ChatFormatting.RED else ChatFormatting.WHITE))
|
||||
msgs.addLast(Component.literal("Memory: ${Formatting.formatMemory(memory)} / ${Formatting.formatMemory(maxMemory)}"))
|
||||
msgs.addLast(Component.literal("Components: $components / $maxComponents").withStyle(if(components <= maxComponents) ChatFormatting.WHITE else ChatFormatting.RED))
|
||||
msgs.addLast(Component.translatable("neocomputers.computer.energy", energy, maxEnergy).withStyle(if(energy < maxEnergy/5) ChatFormatting.RED else ChatFormatting.WHITE))
|
||||
msgs.addLast(Component.translatable("neocomputers.computer.memory", Formatting.formatMemory(memory), Formatting.formatMemory(maxMemory)))
|
||||
msgs.addLast(Component.translatable("neocomputers.computer.components", components, maxComponents).withStyle(if(components <= maxComponents) ChatFormatting.WHITE else ChatFormatting.RED))
|
||||
}
|
||||
return msgs
|
||||
}
|
||||
|
||||
constructor(abstractContainerMenu: CaseMenu, inventory: Inventory, component: Component) : super(abstractContainerMenu, inventory, component) {
|
||||
btn = ImagerButton(
|
||||
15, 15,
|
||||
71, 33,
|
||||
18, 18,
|
||||
ButtonSprites(BTN, 18, 18, 36, 36)
|
||||
) {
|
||||
@@ -83,17 +86,11 @@ class CaseScreen : GenericContainerScreen<CaseMenu> {
|
||||
buf.writeByte(if(isOn) 0x02 else 0x01)
|
||||
NodeSynchronizer.sendScreenInteraction(buf)
|
||||
}
|
||||
// addRenderableWidget(btn!!)
|
||||
}
|
||||
override fun renderBg(guiGraphics: GuiGraphics, f: Float, i: Int, j: Int) {
|
||||
super.renderBg(guiGraphics, f, i ,j)
|
||||
val relX = (this.width - this.imageWidth) / 2
|
||||
val relY = (this.height - this.imageHeight) / 2
|
||||
|
||||
btn!!.x = relX+70
|
||||
btn!!.y = relY+33
|
||||
btn!!.render(guiGraphics, i, j, f) // minecraft SUCKSSS
|
||||
guiGraphics.blit(PCB, relX, relY, 0, 0, this.imageWidth, this.imageHeight)
|
||||
addWidget(btn!!)
|
||||
}
|
||||
override fun renderbg(guiGraphics: GuiGraphics, f: Float, i: Int, j: Int) {
|
||||
guiGraphics.blit(PCB, 0, 0, 0, 0, this.imageWidth, this.imageHeight) // WE'RE FREE
|
||||
}
|
||||
|
||||
override fun renderCustomOverlay(graphics: GuiGraphics, mouseX: Int, mouseY: Int, blend: Float) {
|
||||
@@ -103,13 +100,4 @@ class CaseScreen : GenericContainerScreen<CaseMenu> {
|
||||
}
|
||||
}
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean { // todo: make a better widget system than mojang, practically not even using the fact it's a widget atp
|
||||
if (button == 0 && btn!!.isHovered) {
|
||||
btn!!.playDownSound(Minecraft.getInstance().soundManager)
|
||||
btn!!.onClick(mouseX, mouseY)
|
||||
return true
|
||||
}
|
||||
return super.mouseClicked(mouseX, mouseY, button)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package org.neoflock.neocomputers.gui.screen
|
||||
|
||||
import io.netty.buffer.Unpooled
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.components.Button
|
||||
import net.minecraft.client.gui.components.SpriteIconButton
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener
|
||||
import net.minecraft.client.gui.narration.NarrationElementOutput
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.entity.RackEntity
|
||||
import org.neoflock.neocomputers.gui.menu.RackMenu
|
||||
import org.neoflock.neocomputers.gui.menu.RackSlot
|
||||
import org.neoflock.neocomputers.gui.widget.IconTextButton
|
||||
import org.neoflock.neocomputers.network.NodeSynchronizer
|
||||
import org.neoflock.neocomputers.utils.GenericContainerScreen
|
||||
import java.util.function.Supplier
|
||||
|
||||
class RackScreen(menu: RackMenu, inventory: Inventory, component: Component) : GenericContainerScreen<RackMenu>(menu, inventory, component) {
|
||||
override fun findMenuTexture(): ResourceLocation = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/gui/rack.png")
|
||||
val RELAY = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/gui/relay.png")
|
||||
|
||||
var relay_mode = if (menu.container is RackEntity) (menu.container as RackEntity).relayMode else false
|
||||
|
||||
val relaybtn = IconTextButton(100, 96, if(relay_mode) "Enabled" else "Disabled", RELAY, width = 64) {
|
||||
if (relay_mode){
|
||||
it.message = Component.literal("Disabled")
|
||||
relay_mode = false
|
||||
} else {
|
||||
it.message = Component.literal("Enabled")
|
||||
relay_mode = true
|
||||
}
|
||||
|
||||
val buffer = FriendlyByteBuf(Unpooled.buffer())
|
||||
buffer.writeBoolean(relay_mode)
|
||||
(menu.slots[0] as RackSlot).encode(buffer)
|
||||
NodeSynchronizer.sendScreenInteraction(buffer)
|
||||
}
|
||||
init {
|
||||
this.imageWidth = 175
|
||||
this.imageHeight = 209
|
||||
this.inventoryLabelY = imageHeight - 93
|
||||
addWidget(relaybtn)
|
||||
}
|
||||
|
||||
override fun renderbg(guiGraphics: GuiGraphics, partialTick: Float, mouseX: Int, mouseY: Int) {
|
||||
renderSideLabels(guiGraphics)
|
||||
if(relay_mode) renderRelayConnections(guiGraphics)
|
||||
}
|
||||
|
||||
fun renderRelayConnections(graphics: GuiGraphics) {
|
||||
for(i in 0..3) {
|
||||
val x = 50+(i*11)
|
||||
graphics.fill(x, 104, x+4, 105, 0xffffffff.toInt())
|
||||
graphics.fill(x, 105, x+4, 106, 0xff888888.toInt())
|
||||
}
|
||||
}
|
||||
|
||||
fun renderSideLabels(graphics: GuiGraphics) {
|
||||
val x = 115+7
|
||||
val y = 20
|
||||
|
||||
graphics.drawString(font, "Bottom", x, y, 0x404040, false)
|
||||
graphics.drawString(font, "Top", x, y+11, 0x404040, false)
|
||||
graphics.drawString(font, "Back", x, y+22, 0x404040, false)
|
||||
graphics.drawString(font, "Right", x, y+33, 0x404040, false)
|
||||
graphics.drawString(font, "Left", x, y+44, 0x404040, false)
|
||||
}
|
||||
|
||||
// override fun processScreenStatePacket(buf: FriendlyByteBuf) {
|
||||
// super.processScreenStatePacket(buf)
|
||||
//// NeoComputers.LOGGER.info("porcessing screen state packet...")
|
||||
//// relay_mode = buf.readBoolean()
|
||||
//// if (relay_mode) relaybtn.message = Component.literal("Enabled")
|
||||
//// else relaybtn.message = Component.literal("Disabled")
|
||||
////
|
||||
//// for (slot in menu.slots) {
|
||||
//// if (slot is RackSlot) {
|
||||
//// slot.processStateScreenPacket(buf)
|
||||
//// }
|
||||
//// }
|
||||
//
|
||||
// }
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
if (super.mouseClicked(mouseX, mouseY, button)) return true
|
||||
for (slot in menu.slots) {
|
||||
if (slot is RackSlot) {
|
||||
if(slot.mouseClicked(mouseX-imageX, mouseY-imageY, button)) {
|
||||
val buf = FriendlyByteBuf(Unpooled.buffer())
|
||||
buf.writeBoolean(relay_mode)
|
||||
slot.encode(buf)
|
||||
|
||||
NodeSynchronizer.sendScreenInteraction(buf)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.neoflock.neocomputers.gui.screen
|
||||
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.Style
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.item.DyeColor
|
||||
import org.neoflock.neocomputers.gui.menu.RelayMenu
|
||||
import org.neoflock.neocomputers.utils.GenericContainerScreen
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class RelayScreen(abstractContainerMenu: RelayMenu, inventory: Inventory, component: Component): GenericContainerScreen<RelayMenu>(abstractContainerMenu, inventory, component) {
|
||||
var interval: Int = 5
|
||||
var bufferSize: Int = 1
|
||||
var queueSize: Int = 20
|
||||
var inQueue: Int = 0
|
||||
|
||||
override fun shouldCenterTitle(): Boolean = false
|
||||
|
||||
override fun processScreenStatePacket(buf: FriendlyByteBuf) {
|
||||
super.processScreenStatePacket(buf)
|
||||
interval = buf.readVarInt()
|
||||
bufferSize = buf.readVarInt()
|
||||
queueSize = buf.readVarInt()
|
||||
inQueue = buf.readVarInt()
|
||||
}
|
||||
|
||||
override fun render(graphics: GuiGraphics, mouseX: Int, mouseY: Int, something: Float) {
|
||||
super.render(graphics, mouseX, mouseY, something)
|
||||
val textX = imageX + 12
|
||||
val dataX = imageX + 100
|
||||
val textSpacing = 20
|
||||
val textY = imageY + 20
|
||||
val clr = ChatFormatting.DARK_GRAY.color!!
|
||||
|
||||
graphics.drawString(this.font, "Cycle rate", textX, textY, clr, false)
|
||||
graphics.drawString(this.font, "Packets / cycle", textX, textY + textSpacing, clr, false)
|
||||
graphics.drawString(this.font, "Queue Size", textX, textY + textSpacing*2, clr, false)
|
||||
|
||||
val hz = if(interval == 0) 20 else 20 / interval
|
||||
val buffered = min(inQueue, bufferSize)
|
||||
val queued = max(inQueue - bufferSize, 0)
|
||||
|
||||
graphics.drawString(this.font, "$hz Hz", dataX, textY, clr, false)
|
||||
graphics.drawString(this.font, "$buffered / $bufferSize", dataX, textY + textSpacing, clr, false)
|
||||
graphics.drawString(this.font, "$queued / $queueSize", dataX, textY + textSpacing * 2, clr, false)
|
||||
}
|
||||
}
|
||||
@@ -16,18 +16,19 @@ import org.neoflock.neocomputers.gui.buffer.BufferRenderer
|
||||
import org.neoflock.neocomputers.gui.menu.ScreenMenu
|
||||
import org.neoflock.neocomputers.gui.render.ScreenRenderer
|
||||
import org.neoflock.neocomputers.utils.GenericContainerScreen
|
||||
import org.neoflock.neocomputers.utils.TextBuffer
|
||||
import kotlin.math.min
|
||||
|
||||
class ScreenScreen : GenericContainerScreen<ScreenMenu>{
|
||||
private var renderer: ScreenRenderer = ScreenRenderer();
|
||||
|
||||
var scrWidth: Short = 0
|
||||
var scrHeight: Short = 0
|
||||
var textBuf = TextBuffer(0, 0)
|
||||
|
||||
override fun shouldCenterTitle(): Boolean = false
|
||||
|
||||
override fun processScreenStatePacket(buf: FriendlyByteBuf) {
|
||||
super.processScreenStatePacket(buf)
|
||||
scrWidth = buf.readShort()
|
||||
scrHeight = buf.readShort()
|
||||
textBuf.decodeContents(buf)
|
||||
}
|
||||
|
||||
constructor(abstractContainerMenu: ScreenMenu, inventory: Inventory, component: Component) : super(abstractContainerMenu, inventory, component) {
|
||||
@@ -38,13 +39,15 @@ class ScreenScreen : GenericContainerScreen<ScreenMenu>{
|
||||
this.inventoryLabelX = Int.MAX_VALUE
|
||||
}
|
||||
override fun renderBg(guiGraphics: GuiGraphics, f: Float, i: Int, j: Int) {
|
||||
if(scrWidth > 0) {
|
||||
imageWidth = scrWidth * 4
|
||||
imageHeight = scrHeight * 8
|
||||
if(textBuf.width > 0) {
|
||||
imageWidth = textBuf.width * 4
|
||||
imageHeight = textBuf.height * 8
|
||||
renderer.render(guiGraphics, imageX, imageY, imageWidth, imageHeight)
|
||||
}
|
||||
}
|
||||
|
||||
override fun renderLabels(guiGraphics: GuiGraphics, mouseX: Int, mouseY: Int) { }
|
||||
|
||||
// override fun onClose() {
|
||||
// super.onClose()
|
||||
// renderer.
|
||||
|
||||
@@ -6,11 +6,9 @@ import net.minecraft.client.renderer.GameRenderer
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.Container
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.ItemLike
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.entity.MachineEntity
|
||||
import org.neoflock.neocomputers.entity.ComponentUser
|
||||
import org.neoflock.neocomputers.item.ComponentItem
|
||||
|
||||
// Sort of a mis-nomer, does not need to be associated with components specifically
|
||||
@@ -85,14 +83,11 @@ data class ComponentSlotRequirement(val tier: Int, val role: String) {
|
||||
|
||||
// Tier 0 allows ALL tiers, making it completely untiered.
|
||||
// Role determines what the role is.
|
||||
class ComponentSlot(container: Container, slot: Int, x: Int, y: Int, val machine: MachineEntity?, val requirement: ComponentSlotRequirement): DynamicSlot(container, slot, x, y) {
|
||||
override fun draw(graphics: GuiGraphics, relX: Int, relY: Int, mouseX: Int, mouseY: Int) {
|
||||
super.draw(graphics, relX, relY, mouseX, mouseY)
|
||||
class ComponentSlot(container: Container, slot: Int, x: Int, y: Int, val machine: ComponentUser?, var requirement: ComponentSlotRequirement): DynamicSlot(container, slot, x, y) {
|
||||
override fun draw(graphics: GuiGraphics, mouseX: Int, mouseY: Int) {
|
||||
super.draw(graphics, mouseX, mouseY)
|
||||
if(!hasItem()) {
|
||||
RenderSystem.enableBlend()
|
||||
RenderSystem.setShaderTexture(0, ComponentRoles.getTextureFor(requirement.role))
|
||||
RenderSystem.setShader { GameRenderer.getPositionTexShader() }
|
||||
drawQuad(relX + x - 1, relY + y - 1, 18, 18, 0F, 0F, 15F, 15F)
|
||||
drawQuad(graphics, ComponentRoles.getTextureFor(requirement.role), x - 1, y - 1, 18, 18, 0F, 0F, 15F, 15F)
|
||||
if (requirement.tier > 0) {
|
||||
RenderSystem.setShaderTexture(
|
||||
0,
|
||||
@@ -101,10 +96,11 @@ class ComponentSlot(container: Container, slot: Int, x: Int, y: Int, val machine
|
||||
"textures/gui/slots/tier${requirement.tier - 1}.png"
|
||||
)
|
||||
)
|
||||
RenderSystem.setShader { GameRenderer.getPositionTexShader() }
|
||||
drawQuad(relX + x - 1, relY + y - 1, 18, 18, 0F, 0F, 15F, 15F)
|
||||
val tex = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/gui/slots/tier${requirement.tier - 1}.png")
|
||||
// RenderSystem.setShader { GameRenderer.getPositionTexShader() }
|
||||
drawQuad(graphics, tex, x - 1, y - 1, 18, 18, 0F, 0F, 15F, 15F)
|
||||
}
|
||||
RenderSystem.disableBlend()
|
||||
// RenderSystem.disableBlend()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,41 +5,43 @@ import com.mojang.blaze3d.vertex.BufferBuilder
|
||||
import com.mojang.blaze3d.vertex.BufferUploader
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat
|
||||
import com.mojang.blaze3d.vertex.Tesselator
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer
|
||||
import com.mojang.blaze3d.vertex.VertexFormat
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.renderer.GameRenderer
|
||||
import net.minecraft.client.renderer.RenderStateShard
|
||||
import net.minecraft.client.renderer.RenderStateShard.ShaderStateShard
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.Container
|
||||
import net.minecraft.world.inventory.Slot
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
|
||||
open class DynamicSlot(container: Container, slot: Int, x: Int, y: Int) : Slot(container, slot, x, y) {
|
||||
open class DynamicSlot(container: Container, slot: Int, x: Int, y: Int, var active: Boolean = true) : Slot(container, slot, x, y) {
|
||||
|
||||
val BACKGROUND: ResourceLocation = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/gui/slots/slot.png")
|
||||
|
||||
open fun draw(graphics: GuiGraphics, relX: Int, relY: Int, mouseX: Int, mouseY: Int) {
|
||||
RenderSystem.enableBlend() // background
|
||||
RenderSystem.setShaderTexture(0, BACKGROUND)
|
||||
RenderSystem.setShader { GameRenderer.getPositionTexShader() }
|
||||
drawQuad(relX+x-1, relY+y-1, 18, 18, 0F, 0F, 15F, 15F)
|
||||
RenderSystem.disableBlend()
|
||||
val RENDER_TYPE = { r: ResourceLocation ->
|
||||
RenderType.create("nc_gui_slot", DefaultVertexFormat.POSITION_TEX, VertexFormat.Mode.QUADS, RenderType.TRANSIENT_BUFFER_SIZE, RenderType.CompositeState.builder()
|
||||
.setShaderState(ShaderStateShard.POSITION_TEX_SHADER)
|
||||
.setTextureState(RenderStateShard.TextureStateShard(r, false, false))
|
||||
.setTransparencyState(RenderStateShard.TransparencyStateShard.TRANSLUCENT_TRANSPARENCY)
|
||||
.createCompositeState(false))
|
||||
}
|
||||
|
||||
fun drawQuad(x: Int, y: Int, width: Int, height: Int, u1: Float, v1: Float, u2: Float, v2: Float) {
|
||||
var t: Tesselator = Tesselator.getInstance()
|
||||
var builder: BufferBuilder = t.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX)
|
||||
|
||||
builder.addVertex(x.toFloat(), (y+height).toFloat(), 1f).setUv(u1/15F, v2/15F)
|
||||
builder.addVertex((x+width).toFloat(), (y+height).toFloat(), 1f).setUv(u2/15F, v2/15F)
|
||||
builder.addVertex((x+width).toFloat(), y.toFloat(), 1f).setUv(u2/15F, v1/15F)
|
||||
builder.addVertex(x.toFloat(), y.toFloat(), 1f).setUv(u1/15F,v1/15F)
|
||||
|
||||
BufferUploader.drawWithShader(builder.build()!!)
|
||||
open fun draw(graphics: GuiGraphics, mouseX: Int, mouseY: Int) {
|
||||
drawQuad(graphics, BACKGROUND, x-1, y-1, 18, 18, 0F, 0F, 15F, 15F)
|
||||
}
|
||||
|
||||
// private fun renderSlotHighlight(guiGraphics: GuiGraphics, x: Int, y: Int, k: Int) { // im not sure but i tihnk i copied this from mc source code
|
||||
// guiGraphics.fillGradient(RenderType.guiOverlay(), x, y, x + 16, y + 16, -2130706433, -2130706433, k);
|
||||
// }
|
||||
fun drawQuad(guiGraphics: GuiGraphics, tex: ResourceLocation, x: Int, y: Int, width: Int, height: Int, u1: Float, v1: Float, u2: Float, v2: Float) {
|
||||
val pose = guiGraphics.pose().last()
|
||||
val builder = guiGraphics.bufferSource().getBuffer(RENDER_TYPE(tex))
|
||||
|
||||
builder.addVertex(pose, x.toFloat(), (y+height).toFloat(), 1f).setUv(u1/15F, v2/15F)
|
||||
builder.addVertex(pose, (x+width).toFloat(), (y+height).toFloat(), 1f).setUv(u2/15F, v2/15F)
|
||||
builder.addVertex(pose, (x+width).toFloat(), y.toFloat(), 1f).setUv(u2/15F, v1/15F)
|
||||
builder.addVertex(pose, x.toFloat(), y.toFloat(), 1f).setUv(u1/15F,v1/15F)
|
||||
}
|
||||
|
||||
override fun isActive() = active
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package org.neoflock.neocomputers.gui.widget
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.Font
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.components.Button
|
||||
import net.minecraft.client.renderer.texture.TextureAtlas
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.ResourceLocationPattern
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import java.util.function.Supplier
|
||||
|
||||
class press(val lambda: (IconTextButton) -> Unit) : Button.OnPress {
|
||||
override fun onPress(button: Button) {
|
||||
lambda(button as IconTextButton)
|
||||
}
|
||||
}
|
||||
|
||||
class narr : Button.CreateNarration {
|
||||
override fun createNarrationMessage(supplier: Supplier<MutableComponent?>): MutableComponent? {
|
||||
return supplier.get() // no narration for u
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class IconTextButton(x: Int, y: Int, text: String, val icon: ResourceLocation, val iconw: Int =16, val iconh: Int = 16, width: Int=150, height: Int=20, lambda: (IconTextButton) -> Unit) :
|
||||
Button(x, y, width, height, Component.literal(text),press(lambda), narr()) {
|
||||
|
||||
|
||||
var xOffset = 2
|
||||
override fun renderWidget(guiGraphics: GuiGraphics, mouseX: Int, mouseY: Int, partialTick: Float) {
|
||||
super.renderWidget(guiGraphics, mouseX, mouseY, partialTick)
|
||||
|
||||
RenderSystem.disableBlend() // i hate this
|
||||
val imx = x + xOffset
|
||||
val imy = y + (height/2) - (iconh/2)
|
||||
guiGraphics.blit(icon, imx, imy, 0f, 0f, iconw, iconh, iconw, iconh)
|
||||
RenderSystem.enableBlend()
|
||||
}
|
||||
|
||||
override fun renderString(guiGraphics: GuiGraphics, font: Font, color: Int) {
|
||||
val startx = x + iconw/2 // idk why /2, might be coincidence thing
|
||||
renderScrollingString(guiGraphics, font, message, startx, y, startx+width, y+height, color)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,18 +2,17 @@ package org.neoflock.neocomputers.item
|
||||
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import org.neoflock.neocomputers.entity.MachineEntity
|
||||
import org.neoflock.neocomputers.entity.ComponentUser
|
||||
import org.neoflock.neocomputers.gui.widget.ComponentRoles
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
|
||||
open class CBUSItem(val tier: Int, val maxComponents: Int): Item(Item.Properties()), ComponentItem {
|
||||
override fun getComponentRoles(itemStack: ItemStack): Set<String> = setOf(ComponentRoles.BUS)
|
||||
override fun getComponentRoles(itemStack: ItemStack) = setOf(ComponentRoles.BUS)
|
||||
|
||||
override fun getComponentTier(itemStack: ItemStack): Int = tier
|
||||
override fun getComponentTier(itemStack: ItemStack) = tier
|
||||
|
||||
override fun getComponentCapacity(itemStack: ItemStack): Int = maxComponents
|
||||
override fun getComponentCapacity(itemStack: ItemStack) = maxComponents
|
||||
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity): Networking.Node? = null
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
|
||||
}
|
||||
class CBUS0: CBUSItem(1, 8)
|
||||
class CBUS1: CBUSItem(2, 12)
|
||||
|
||||
@@ -2,11 +2,10 @@ package org.neoflock.neocomputers.item
|
||||
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import org.neoflock.neocomputers.entity.MachineEntity
|
||||
import org.neoflock.neocomputers.entity.ComponentUser
|
||||
import org.neoflock.neocomputers.gui.widget.ComponentRoles
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
|
||||
open class CPUItem(val tier: Int, val maxComponents: Int): Item(Item.Properties()), ComponentItem {
|
||||
open class CPUItem(val tier: Int, val maxComponents: Int): Item(Item.Properties()), RelayUpgrade {
|
||||
override fun getComponentRoles(itemStack: ItemStack): Set<String> = setOf(ComponentRoles.COMPUTE)
|
||||
|
||||
override fun getComponentTier(itemStack: ItemStack): Int = tier
|
||||
@@ -15,7 +14,9 @@ open class CPUItem(val tier: Int, val maxComponents: Int): Item(Item.Properties(
|
||||
|
||||
override fun getArchitecturesProvided(itemStack: ItemStack): Set<String> = setOf("Lua 5.3")
|
||||
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity): Networking.Node? = null
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
|
||||
|
||||
override fun getRelayInterval(itemStack: ItemStack) = 4 / tier
|
||||
}
|
||||
|
||||
class CPU0: CPUItem(1, 8)
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package org.neoflock.neocomputers.item
|
||||
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import org.neoflock.neocomputers.entity.ComponentUser
|
||||
import org.neoflock.neocomputers.entity.MachineEntity
|
||||
import org.neoflock.neocomputers.entity.MachineEvent
|
||||
import org.neoflock.neocomputers.network.DeviceNode
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
import java.util.UUID
|
||||
|
||||
@@ -17,26 +19,26 @@ interface ComponentItem {
|
||||
fun getArchitecturesProvided(itemStack: ItemStack): Set<String> = setOf()
|
||||
|
||||
// Component placed, node must now exist
|
||||
fun whenComponentPlaced(itemStack: ItemStack, machine: MachineEntity, newRole: String) {
|
||||
fun whenComponentPlaced(itemStack: ItemStack, machine: ComponentUser?, newRole: String) {
|
||||
val oldNode = getComponentNode(itemStack)
|
||||
if(oldNode != null) Networking.removeNode(oldNode) // did a mod forget to call whenComponentTaken?
|
||||
val node = toComponentNode(itemStack, machine) ?: return
|
||||
Networking.addNode(node)
|
||||
machine.getMachineNode().connectTo(node)
|
||||
machine?.getMachineNode()?.connectTo(node)
|
||||
}
|
||||
|
||||
// Component taken, and thus removed
|
||||
fun whenComponentTaken(itemStack: ItemStack, machine: MachineEntity, previousRole: String) {
|
||||
fun whenComponentTaken(itemStack: ItemStack, machine: ComponentUser?, previousRole: String) {
|
||||
val node = getComponentNode(itemStack) ?: return
|
||||
node.disconnectFrom(machine.getMachineNode())
|
||||
// removing disconnects
|
||||
Networking.removeNode(node)
|
||||
}
|
||||
|
||||
// To node, if applicable. Meant to create the node, but not add it, as it will use the itemStack's address to find it again
|
||||
fun toComponentNode(itemStack: ItemStack, machine: MachineEntity): Networking.Node?
|
||||
fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?): DeviceNode?
|
||||
|
||||
// Gets the node associated to an item, if it exists
|
||||
fun getComponentNode(itemStack: ItemStack): Networking.Node? {
|
||||
fun getComponentNode(itemStack: ItemStack): DeviceNode? {
|
||||
val address = itemStack.get(DataComponents.ADDRESS) ?: return null
|
||||
val uuid = UUID.fromString(address) ?: return null
|
||||
return Networking.getNode(uuid)
|
||||
@@ -50,4 +52,12 @@ interface ComponentItem {
|
||||
}
|
||||
|
||||
fun onMachineEvent(itemStack: ItemStack, machine: MachineEntity, event: MachineEvent) {}
|
||||
}
|
||||
|
||||
// A special ComponentItem which specifies upgrades specific to the relay
|
||||
interface RelayUpgrade: ComponentItem {
|
||||
fun getRelayInterval(itemStack: ItemStack): Int? = null
|
||||
fun getRelayBufferSize(itemStack: ItemStack): Int? = null
|
||||
fun getRelayQueueSize(itemStack: ItemStack): Int? = null
|
||||
fun isRelayCompatibleCard(itemStack: ItemStack): Boolean = false
|
||||
}
|
||||
@@ -4,9 +4,8 @@ import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.TooltipFlag
|
||||
import org.neoflock.neocomputers.entity.MachineEntity
|
||||
import org.neoflock.neocomputers.entity.ComponentUser
|
||||
import org.neoflock.neocomputers.gui.widget.ComponentRoles
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
import org.neoflock.neocomputers.utils.Formatting
|
||||
|
||||
// Note: We'll prob want to replace them with NN component configs later on
|
||||
@@ -16,13 +15,13 @@ open class DataCard(val tier: Int, val limit: Long): Item(Properties()), Compone
|
||||
|
||||
override fun getComponentTier(itemStack: ItemStack): Int = tier
|
||||
|
||||
override fun whenComponentPlaced(itemStack: ItemStack, machine: MachineEntity, newRole: String) {
|
||||
ensureHasAddress(itemStack)
|
||||
override fun whenComponentPlaced(itemStack: ItemStack, machine: ComponentUser?, newRole: String) {
|
||||
if(machine != null) ensureHasAddress(itemStack)
|
||||
super.whenComponentPlaced(itemStack, machine, newRole)
|
||||
}
|
||||
|
||||
// TODO: Modem Component
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity): Networking.Node? = null
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
|
||||
|
||||
override fun appendHoverText(
|
||||
itemStack: ItemStack,
|
||||
|
||||
@@ -15,6 +15,9 @@ object DataComponents {
|
||||
DataComponentType.builder<String>().persistent(Codec.STRING).build())
|
||||
val READONLY = Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "readonly"),
|
||||
DataComponentType.builder<Boolean>().persistent(Codec.BOOL).build())
|
||||
val ARCH = Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "architecture"),
|
||||
DataComponentType.builder<String>().persistent(Codec.STRING).build())
|
||||
|
||||
val EEPROM_CODE = Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "eeprom_code"),
|
||||
DataComponentType.builder<ByteBuffer>().persistent(Codec.BYTE_BUFFER).build())
|
||||
val EEPROM_DATA = Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "eeprom_data"),
|
||||
|
||||
@@ -4,9 +4,8 @@ import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.TooltipFlag
|
||||
import org.neoflock.neocomputers.entity.MachineEntity
|
||||
import org.neoflock.neocomputers.entity.ComponentUser
|
||||
import org.neoflock.neocomputers.gui.widget.ComponentRoles
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
import org.neoflock.neocomputers.utils.Formatting
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
@@ -27,12 +26,12 @@ open class EEPROMItem(val tier: Int, val codeCapacity: Int, val dataCapacity: In
|
||||
|
||||
override fun getComponentCapacity(itemStack: ItemStack): Int = 0
|
||||
|
||||
override fun whenComponentPlaced(itemStack: ItemStack, machine: MachineEntity, newRole: String) {
|
||||
ensureHasAddress(itemStack)
|
||||
override fun whenComponentPlaced(itemStack: ItemStack, machine: ComponentUser?, newRole: String) {
|
||||
if(machine != null) ensureHasAddress(itemStack)
|
||||
super.whenComponentPlaced(itemStack, machine, newRole)
|
||||
}
|
||||
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity): Networking.Node? = null
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
|
||||
|
||||
override fun appendHoverText(
|
||||
itemStack: ItemStack,
|
||||
@@ -43,10 +42,14 @@ open class EEPROMItem(val tier: Int, val codeCapacity: Int, val dataCapacity: In
|
||||
if(tooltipFlag.isAdvanced) {
|
||||
val codeSize = itemStack.get(DataComponents.EEPROM_CODESIZE) ?: 0
|
||||
val dataSize = itemStack.get(DataComponents.EEPROM_DATASIZE) ?: 0
|
||||
val arch = itemStack.get(DataComponents.ARCH)
|
||||
val addr = itemStack.get(DataComponents.ADDRESS)
|
||||
val readonly = itemStack.get(DataComponents.READONLY) ?: false
|
||||
val addrComp = if(addr == null) Component.translatable("neocomputers.noaddr") else Component.literal(addr)
|
||||
list.addLast(addrComp)
|
||||
if(arch != null) {
|
||||
list.addLast(Component.translatable("neocomputers.arch", arch))
|
||||
}
|
||||
list.addLast(Component.translatable("neocomputers.eeprom.codeused", Formatting.formatMemory(codeSize.toLong()),
|
||||
Formatting.formatMemory(codeCapacity.toLong())))
|
||||
list.addLast(Component.translatable("neocomputers.eeprom.dataused", Formatting.formatMemory(dataSize.toLong()),
|
||||
|
||||
@@ -4,9 +4,8 @@ import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.TooltipFlag
|
||||
import org.neoflock.neocomputers.entity.MachineEntity
|
||||
import org.neoflock.neocomputers.entity.ComponentUser
|
||||
import org.neoflock.neocomputers.gui.widget.ComponentRoles
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
|
||||
// Note: We'll prob want to replace them with NN component configs later on
|
||||
|
||||
@@ -15,13 +14,13 @@ open class GPUCard(val tier: Int, val vram: Long): Item(Properties()), Component
|
||||
|
||||
override fun getComponentTier(itemStack: ItemStack): Int = tier
|
||||
|
||||
override fun whenComponentPlaced(itemStack: ItemStack, machine: MachineEntity, newRole: String) {
|
||||
ensureHasAddress(itemStack)
|
||||
override fun whenComponentPlaced(itemStack: ItemStack, machine: ComponentUser?, newRole: String) {
|
||||
if(machine != null) ensureHasAddress(itemStack)
|
||||
super.whenComponentPlaced(itemStack, machine, newRole)
|
||||
}
|
||||
|
||||
// TODO: GPU Component
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity): Networking.Node? = null
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
|
||||
|
||||
override fun appendHoverText(
|
||||
itemStack: ItemStack,
|
||||
|
||||
@@ -4,17 +4,15 @@ import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.TooltipFlag
|
||||
import org.neoflock.neocomputers.entity.MachineEntity
|
||||
import org.neoflock.neocomputers.entity.ComponentUser
|
||||
import org.neoflock.neocomputers.gui.widget.ComponentRoles
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
import org.neoflock.neocomputers.utils.Formatting
|
||||
import java.util.UUID
|
||||
|
||||
fun getDiskProperties(): Item.Properties = Item.Properties()
|
||||
.component(DataComponents.LABEL, "")
|
||||
.component(DataComponents.READONLY, false)
|
||||
|
||||
open class HardDiskItem(val tier: Int, val capacity: Long): Item(getDiskProperties()), ComponentItem {
|
||||
open class HardDiskItem(val tier: Int, val capacity: Long, val relayQueueSize: Int): Item(getDiskProperties()), RelayUpgrade {
|
||||
override fun getComponentRoles(itemStack: ItemStack): Set<String> = setOf(ComponentRoles.STORAGE)
|
||||
|
||||
override fun getComponentTier(itemStack: ItemStack): Int = tier
|
||||
@@ -23,12 +21,12 @@ open class HardDiskItem(val tier: Int, val capacity: Long): Item(getDiskProperti
|
||||
|
||||
override fun getComponentCapacity(itemStack: ItemStack): Int = 0
|
||||
|
||||
override fun whenComponentPlaced(itemStack: ItemStack, machine: MachineEntity, newRole: String) {
|
||||
ensureHasAddress(itemStack)
|
||||
override fun whenComponentPlaced(itemStack: ItemStack, machine: ComponentUser?, newRole: String) {
|
||||
if(machine != null) ensureHasAddress(itemStack)
|
||||
super.whenComponentPlaced(itemStack, machine, newRole)
|
||||
}
|
||||
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity): Networking.Node? = null
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
|
||||
|
||||
override fun appendHoverText(
|
||||
itemStack: ItemStack,
|
||||
@@ -56,8 +54,10 @@ open class HardDiskItem(val tier: Int, val capacity: Long): Item(getDiskProperti
|
||||
}
|
||||
return super.getName(itemStack)
|
||||
}
|
||||
|
||||
override fun getRelayQueueSize(itemStack: ItemStack) = relayQueueSize
|
||||
}
|
||||
|
||||
class HardDisk0: HardDiskItem(1, 1 shl 20)
|
||||
class HardDisk1: HardDiskItem(2, 2 shl 20)
|
||||
class HardDisk2: HardDiskItem(3, 4 shl 20)
|
||||
class HardDisk0: HardDiskItem(1, 1 shl 20, 30)
|
||||
class HardDisk1: HardDiskItem(2, 2 shl 20, 40)
|
||||
class HardDisk2: HardDiskItem(3, 4 shl 20, 50)
|
||||
@@ -4,23 +4,21 @@ import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.TooltipFlag
|
||||
import org.neoflock.neocomputers.entity.MachineEntity
|
||||
import org.neoflock.neocomputers.entity.ComponentUser
|
||||
import org.neoflock.neocomputers.gui.widget.ComponentRoles
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
import org.neoflock.neocomputers.utils.Formatting
|
||||
|
||||
class InternetCard: Item(Item.Properties()), ComponentItem {
|
||||
override fun getComponentRoles(itemStack: ItemStack): Set<String> = setOf(ComponentRoles.CARD, ComponentRoles.INET)
|
||||
|
||||
override fun getComponentTier(itemStack: ItemStack): Int = 1
|
||||
override fun getComponentTier(itemStack: ItemStack): Int = 2
|
||||
|
||||
override fun whenComponentPlaced(itemStack: ItemStack, machine: MachineEntity, newRole: String) {
|
||||
ensureHasAddress(itemStack)
|
||||
override fun whenComponentPlaced(itemStack: ItemStack, machine: ComponentUser?, newRole: String) {
|
||||
if(machine != null) ensureHasAddress(itemStack)
|
||||
super.whenComponentPlaced(itemStack, machine, newRole)
|
||||
}
|
||||
|
||||
// TODO: Internet Component
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity): Networking.Node? = null
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
|
||||
|
||||
override fun appendHoverText(
|
||||
itemStack: ItemStack,
|
||||
|
||||
@@ -46,4 +46,6 @@ object Items {
|
||||
|
||||
val REDIO0 = ITEMS.register("redio0") { RedstoneCard0() }
|
||||
val REDIO1 = ITEMS.register("redio1") { RedstoneCard1() }
|
||||
|
||||
val SERVER0 = ITEMS.register("server0") { ServerItem() }
|
||||
}
|
||||
@@ -4,12 +4,11 @@ import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.TooltipFlag
|
||||
import org.neoflock.neocomputers.entity.MachineEntity
|
||||
import org.neoflock.neocomputers.entity.ComponentUser
|
||||
import org.neoflock.neocomputers.gui.widget.ComponentRoles
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
import org.neoflock.neocomputers.utils.Formatting
|
||||
|
||||
open class MemoryItem(val tier: Int, val capacity: Int): Item(Item.Properties().`arch$tab`(Tabs.TAB)), ComponentItem {
|
||||
open class MemoryItem(val tier: Int, val capacity: Int, val relayBuf: Int): Item(Item.Properties().`arch$tab`(Tabs.TAB)), RelayUpgrade {
|
||||
override fun getComponentRoles(itemStack: ItemStack) = setOf(ComponentRoles.MEMORY)
|
||||
|
||||
override fun getComponentTier(itemStack: ItemStack): Int = tier
|
||||
@@ -19,7 +18,7 @@ open class MemoryItem(val tier: Int, val capacity: Int): Item(Item.Properties().
|
||||
override fun getComponentCapacity(itemStack: ItemStack): Int = 0
|
||||
|
||||
// no node for memory
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity): Networking.Node? = null
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
|
||||
|
||||
override fun appendHoverText(
|
||||
itemStack: ItemStack,
|
||||
@@ -32,11 +31,13 @@ open class MemoryItem(val tier: Int, val capacity: Int): Item(Item.Properties().
|
||||
}
|
||||
super.appendHoverText(itemStack, tooltipContext, list, tooltipFlag)
|
||||
}
|
||||
|
||||
override fun getRelayBufferSize(itemStack: ItemStack) = relayBuf
|
||||
}
|
||||
|
||||
class MemoryTier1(): MemoryItem(1, 192 shl 10)
|
||||
class MemoryTier1_5(): MemoryItem(1, 256 shl 10)
|
||||
class MemoryTier2(): MemoryItem(2, 384 shl 10)
|
||||
class MemoryTier2_5(): MemoryItem(2, 512 shl 10)
|
||||
class MemoryTier3(): MemoryItem(3, 768 shl 10)
|
||||
class MemoryTier3_5(): MemoryItem(3, 1 shl 20)
|
||||
class MemoryTier1(): MemoryItem(1, 192 shl 10, 2)
|
||||
class MemoryTier1_5(): MemoryItem(1, 256 shl 10, 3)
|
||||
class MemoryTier2(): MemoryItem(2, 384 shl 10, 4)
|
||||
class MemoryTier2_5(): MemoryItem(2, 512 shl 10, 5)
|
||||
class MemoryTier3(): MemoryItem(3, 768 shl 10, 6)
|
||||
class MemoryTier3_5(): MemoryItem(3, 1 shl 20, 7)
|
||||
@@ -4,22 +4,21 @@ import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.TooltipFlag
|
||||
import org.neoflock.neocomputers.entity.MachineEntity
|
||||
import org.neoflock.neocomputers.entity.ComponentUser
|
||||
import org.neoflock.neocomputers.gui.widget.ComponentRoles
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
|
||||
open class NetworkCard(val tier: Int, val maxRange: Int, val isWired: Boolean): Item(Properties()), ComponentItem {
|
||||
override fun getComponentRoles(itemStack: ItemStack): Set<String> = setOf(ComponentRoles.CARD, ComponentRoles.NETWORK)
|
||||
|
||||
override fun getComponentTier(itemStack: ItemStack): Int = tier
|
||||
|
||||
override fun whenComponentPlaced(itemStack: ItemStack, machine: MachineEntity, newRole: String) {
|
||||
ensureHasAddress(itemStack)
|
||||
override fun whenComponentPlaced(itemStack: ItemStack, machine: ComponentUser?, newRole: String) {
|
||||
if(machine != null) ensureHasAddress(itemStack)
|
||||
super.whenComponentPlaced(itemStack, machine, newRole)
|
||||
}
|
||||
|
||||
// TODO: Modem Component
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity): Networking.Node? = null
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
|
||||
|
||||
override fun appendHoverText(
|
||||
itemStack: ItemStack,
|
||||
|
||||
62
src/main/kotlin/org/neoflock/neocomputers/item/RackItem.kt
Normal file
62
src/main/kotlin/org/neoflock/neocomputers/item/RackItem.kt
Normal file
@@ -0,0 +1,62 @@
|
||||
package org.neoflock.neocomputers.item
|
||||
|
||||
import com.mojang.blaze3d.shaders.Shader
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer
|
||||
import com.mojang.blaze3d.vertex.VertexFormat
|
||||
import net.minecraft.client.renderer.MultiBufferSource
|
||||
import net.minecraft.client.renderer.RenderStateShard
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
|
||||
interface RackItem {
|
||||
// companion object {
|
||||
// val RENDER_TYPE = {l: ResourceLocation ->
|
||||
// RenderType.create("nc_server", DefaultVertexFormat.POSITION_COLOR_TEX_LIGHTMAP, VertexFormat.Mode.QUADS, RenderType.SMALL_BUFFER_SIZE, RenderType.CompositeState.builder()
|
||||
// .setShaderState(RenderStateShard.ShaderStateShard.POSITION_COLOR_TEX_LIGHTMAP_SHADER)
|
||||
// .setLightmapState(RenderStateShard.LIGHTMAP)
|
||||
// .setTextureState(RenderStateShard.TextureStateShard(l, false, false))
|
||||
// .createCompositeState(false))
|
||||
// }
|
||||
// }
|
||||
val TOP_TEX: ResourceLocation
|
||||
get() = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/block/generic_top.png")
|
||||
|
||||
val FRONT_TEX: ResourceLocation
|
||||
get() = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/block/rack_server.png")
|
||||
|
||||
fun render_lights(source: MultiBufferSource, stack: PoseStack, light: Int)
|
||||
|
||||
fun render(source: MultiBufferSource, stack: PoseStack, light: Int, v_offset: Float = 2f) {
|
||||
val pose = stack.last()
|
||||
|
||||
|
||||
// var buffer = source.getBuffer(RenderType.gui()) // TODO: correct rendertype
|
||||
var buffer = source.getBuffer(RenderType.entitySolid(TOP_TEX))
|
||||
// val u1 = 1/16f
|
||||
buffer.addVertex(pose, 0f, 0f, 0f).setUv(1/16f, 15/16f).setColor(1f, 1f, 1f, 1f).setLight(light).setNormal(pose, 0f, -1f, 0f).setOverlay(OverlayTexture.NO_OVERLAY)
|
||||
buffer.addVertex(pose, 14/16f, 0f, 0f).setUv(1/16f, 1/16f).setColor(1f, 1f, 1f, 1f).setLight(light).setNormal(pose, 0f, -1f, 0f).setOverlay(OverlayTexture.NO_OVERLAY)
|
||||
buffer.addVertex(pose, 14/16f, 0f, 14/16f).setUv(15/16f, 1/16f).setColor(1f, 1f, 1f, 1f).setLight(light).setNormal(pose, 0f, -1f, 0f).setOverlay(OverlayTexture.NO_OVERLAY)
|
||||
buffer.addVertex(pose, 0f, 0f, 14/16f).setUv(15/16f, 1/16f).setColor(1f, 1f, 1f, 1f).setLight(light).setNormal(pose, 0f, -1f, 0f).setOverlay(OverlayTexture.NO_OVERLAY)
|
||||
|
||||
buffer.addVertex(pose, 0f, 3/16f, 14/16f).setUv(15/16f, 1/16f).setColor(1f, 1f, 1f, 1f).setLight(light).setNormal(pose, 0f, 1f, 0f).setOverlay(OverlayTexture.NO_OVERLAY)
|
||||
buffer.addVertex(pose, 14/16f, 3/16f, 14/16f).setUv(15/16f, 15/16f).setColor(1f, 1f, 1f, 1f).setLight(light).setNormal(pose, 0f, 1f, 0f).setOverlay(OverlayTexture.NO_OVERLAY)
|
||||
buffer.addVertex(pose, 14/16f, 3/16f, 0f).setUv(1/16f, 15/16f).setColor(1f, 1f, 1f, 1f).setLight(light).setNormal(pose, 0f, 1f, 0f).setOverlay(OverlayTexture.NO_OVERLAY)
|
||||
buffer.addVertex(pose, 0f, 3/16f, 0f).setUv(1/16f, 1/16f).setColor(1f, 1f, 1f, 1f).setLight(light).setNormal(pose, 0f, 1f, 0f).setOverlay(OverlayTexture.NO_OVERLAY)
|
||||
|
||||
buffer = source.getBuffer(RenderType.entitySolid(FRONT_TEX))
|
||||
buffer.addVertex(pose, 14/16f, 3/16f, 14/16f).setUv(1/16f, v_offset/16f).setColor(1f, 1f, 1f, 1f).setLight(light).setNormal(pose, 1f, 0f, 0f).setOverlay(OverlayTexture.NO_OVERLAY)
|
||||
buffer.addVertex(pose, 14/16f, 0f, 14/16f).setUv(1/16f, (v_offset+3)/16f).setColor(1f, 1f, 1f, 1f).setLight(light).setNormal(pose, 1f, 0f, 0f).setOverlay(OverlayTexture.NO_OVERLAY)
|
||||
buffer.addVertex(pose, 14/16f, 0/16f, 0/16f).setUv(15/16f, (v_offset+3)/16f).setColor(1f, 1f, 1f, 1f).setLight(light).setNormal(pose, 1f, 0f, 0f).setOverlay(OverlayTexture.NO_OVERLAY)
|
||||
buffer.addVertex(pose, 14/16f, 3/16f, 0/16f).setUv(15/16f, v_offset/16f).setColor(1f, 1f, 1f, 1f).setLight(light).setNormal(pose, 1f, 0f, 0f).setOverlay(OverlayTexture.NO_OVERLAY)
|
||||
|
||||
stack.pushPose()
|
||||
stack.translate((14/16f)+0.001F, 0f, 0f)
|
||||
render_lights(source, stack, light)
|
||||
stack.popPose()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,9 +4,8 @@ import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.TooltipFlag
|
||||
import org.neoflock.neocomputers.entity.MachineEntity
|
||||
import org.neoflock.neocomputers.entity.ComponentUser
|
||||
import org.neoflock.neocomputers.gui.widget.ComponentRoles
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
|
||||
// Note: We'll prob want to replace them with NN component configs later on
|
||||
|
||||
@@ -15,13 +14,13 @@ open class RedstoneCard(val tier: Int): Item(Properties()), ComponentItem {
|
||||
|
||||
override fun getComponentTier(itemStack: ItemStack): Int = tier
|
||||
|
||||
override fun whenComponentPlaced(itemStack: ItemStack, machine: MachineEntity, newRole: String) {
|
||||
ensureHasAddress(itemStack)
|
||||
override fun whenComponentPlaced(itemStack: ItemStack, machine: ComponentUser?, newRole: String) {
|
||||
if(machine != null) ensureHasAddress(itemStack)
|
||||
super.whenComponentPlaced(itemStack, machine, newRole)
|
||||
}
|
||||
|
||||
// TODO: Redstone Component
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity): Networking.Node? = null
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
|
||||
|
||||
override fun appendHoverText(
|
||||
itemStack: ItemStack,
|
||||
|
||||
27
src/main/kotlin/org/neoflock/neocomputers/item/ServerItem.kt
Normal file
27
src/main/kotlin/org/neoflock/neocomputers/item/ServerItem.kt
Normal file
@@ -0,0 +1,27 @@
|
||||
package org.neoflock.neocomputers.item
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import net.minecraft.client.renderer.MultiBufferSource
|
||||
import net.minecraft.client.renderer.entity.ItemRenderer
|
||||
import net.minecraft.client.renderer.item.ItemProperties
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import org.neoflock.neocomputers.entity.ComponentUser
|
||||
import org.neoflock.neocomputers.gui.widget.ComponentRoles
|
||||
import org.neoflock.neocomputers.network.DeviceNode
|
||||
|
||||
class ServerItem() : Item(Properties()), ComponentItem, RackItem {
|
||||
override fun getComponentRoles(itemStack: ItemStack): Set<String> = setOf(ComponentRoles.RACK_MOUNTABLE)
|
||||
|
||||
override fun getComponentTier(itemStack: ItemStack): Int = 0
|
||||
|
||||
override fun toComponentNode(
|
||||
itemStack: ItemStack,
|
||||
machine: ComponentUser?
|
||||
): DeviceNode? {
|
||||
return null // TODO: atom machine item plz
|
||||
}
|
||||
|
||||
override fun render_lights(source: MultiBufferSource, stack: PoseStack, light: Int) {
|
||||
}
|
||||
}
|
||||
@@ -23,38 +23,9 @@ object Tabs {
|
||||
ItemStack(Items.MEM0.get())
|
||||
}
|
||||
builder.displayItems { parameters, output ->
|
||||
// TODO: get rid of arch$tab and this shi and replace with loop over items registry
|
||||
output.accept(ItemStack(Items.CPU0.get()))
|
||||
output.accept(ItemStack(Items.CPU1.get()))
|
||||
output.accept(ItemStack(Items.CPU2.get()))
|
||||
|
||||
output.accept(ItemStack(Items.CBUS0.get()))
|
||||
output.accept(ItemStack(Items.CBUS1.get()))
|
||||
output.accept(ItemStack(Items.CBUS2.get()))
|
||||
output.accept(ItemStack(Items.CBUS_CREATIVE.get()))
|
||||
|
||||
output.accept(ItemStack(Items.DATA0.get()))
|
||||
output.accept(ItemStack(Items.DATA1.get()))
|
||||
output.accept(ItemStack(Items.DATA2.get()))
|
||||
|
||||
output.accept(ItemStack(Items.GPU0.get()))
|
||||
output.accept(ItemStack(Items.GPU1.get()))
|
||||
output.accept(ItemStack(Items.GPU2.get()))
|
||||
|
||||
output.accept(ItemStack(Items.HDD0.get()))
|
||||
output.accept(ItemStack(Items.HDD1.get()))
|
||||
output.accept(ItemStack(Items.HDD2.get()))
|
||||
|
||||
output.accept(ItemStack(Items.INET.get()))
|
||||
output.accept(ItemStack(Items.TUNNEL.get()))
|
||||
output.accept(ItemStack(Items.LAN.get()))
|
||||
output.accept(ItemStack(Items.WLAN0.get()))
|
||||
output.accept(ItemStack(Items.WLAN1.get()))
|
||||
|
||||
output.accept(ItemStack(Items.REDIO0.get()))
|
||||
output.accept(ItemStack(Items.REDIO1.get()))
|
||||
|
||||
output.accept(ItemStack(Items.EE0.get()))
|
||||
Items.ITEMS.forEach {
|
||||
output.accept(ItemStack(it.get()))
|
||||
}
|
||||
|
||||
// Criminal black magic to put LuaBIOS EEPROM in the tabs
|
||||
do {
|
||||
@@ -71,6 +42,7 @@ object Tabs {
|
||||
val codeBuf = ByteBuffer.allocate(code.size)
|
||||
codeBuf.put(code)
|
||||
luaBios.set(DataComponents.LABEL, "Lua BIOS")
|
||||
luaBios.set(DataComponents.ARCH, "Lua 5.2")
|
||||
luaBios.set(DataComponents.EEPROM_CODE, codeBuf)
|
||||
luaBios.set(DataComponents.EEPROM_CODESIZE, code.size)
|
||||
output.accept(luaBios)
|
||||
|
||||
@@ -4,9 +4,8 @@ import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.TooltipFlag
|
||||
import org.neoflock.neocomputers.entity.MachineEntity
|
||||
import org.neoflock.neocomputers.entity.ComponentUser
|
||||
import org.neoflock.neocomputers.gui.widget.ComponentRoles
|
||||
import org.neoflock.neocomputers.network.Networking
|
||||
|
||||
class TunnelCard: Item(Properties().component(DataComponents.TUNNEL_CHANNEL, "creative")), ComponentItem {
|
||||
// yes, we're counting TUNNEL as a conventional networking card
|
||||
@@ -14,13 +13,13 @@ class TunnelCard: Item(Properties().component(DataComponents.TUNNEL_CHANNEL, "cr
|
||||
|
||||
override fun getComponentTier(itemStack: ItemStack): Int = 3
|
||||
|
||||
override fun whenComponentPlaced(itemStack: ItemStack, machine: MachineEntity, newRole: String) {
|
||||
ensureHasAddress(itemStack)
|
||||
override fun whenComponentPlaced(itemStack: ItemStack, machine: ComponentUser?, newRole: String) {
|
||||
if(machine != null) ensureHasAddress(itemStack)
|
||||
super.whenComponentPlaced(itemStack, machine, newRole)
|
||||
}
|
||||
|
||||
// TODO: Tunnel Component
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity): Networking.Node? = null
|
||||
override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
|
||||
|
||||
override fun appendHoverText(
|
||||
itemStack: ItemStack,
|
||||
|
||||
256
src/main/kotlin/org/neoflock/neocomputers/network/DeviceNode.kt
Normal file
256
src/main/kotlin/org/neoflock/neocomputers/network/DeviceNode.kt
Normal file
@@ -0,0 +1,256 @@
|
||||
package org.neoflock.neocomputers.network
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import org.neoflock.neocomputers.network.Networking.Message
|
||||
import org.neoflock.neocomputers.network.Networking.Visibility
|
||||
import org.neoflock.neocomputers.network.Networking.maxHopCount
|
||||
import java.util.UUID
|
||||
import kotlin.math.min
|
||||
|
||||
// tmp class until JNI bindings work
|
||||
data class NNComponent(val type: String)
|
||||
|
||||
open class DeviceNode(_address: UUID? = null) {
|
||||
val connections = HashSet<DeviceNode>()
|
||||
private var reachableCache: Set<DeviceNode>? = null
|
||||
var address = _address ?: UUID.randomUUID()
|
||||
|
||||
open var reachability = Visibility.NETWORK
|
||||
open var powerRole = PowerRole.CONSUMER
|
||||
open var energy: Long = 0
|
||||
open var energyCapacity: Long = 0
|
||||
// give energy, returns how much was actually given
|
||||
// cannot exceed amount specified
|
||||
open fun giveEnergy(amount: Long): Long {
|
||||
val maximum = min(amount, energyCapacity - energy)
|
||||
energy += maximum
|
||||
markChanged()
|
||||
return maximum
|
||||
}
|
||||
// take energy out, returns how much was actually taken
|
||||
// cannot exceed amount specified
|
||||
open fun withdrawEnergy(amount: Long): Long {
|
||||
val maximum = min(amount, energy)
|
||||
energy -= maximum
|
||||
markChanged()
|
||||
return maximum
|
||||
}
|
||||
|
||||
fun getChargerNodes(): Set<DeviceNode> = getReachable().filter { it.powerRole != PowerRole.CONSUMER }.toSet()
|
||||
fun totalEnergyInConnections(): Long = getChargerNodes().fold(0) { acc, node -> acc + node.energy }
|
||||
fun maxEnergyInConnections(): Long = getChargerNodes().fold(0) { acc, node -> acc + node.energyCapacity }
|
||||
|
||||
// attempts to consume
|
||||
fun consumeEnergy(energy: Long): Boolean {
|
||||
// consumes energy, returns false if not enough
|
||||
val total = totalEnergyInConnections() + this.energy
|
||||
if(energy > total) return false
|
||||
|
||||
var remaining = energy
|
||||
remaining -= withdrawEnergy(remaining)
|
||||
if(remaining <= 0) return true
|
||||
|
||||
for (charger in getChargerNodes()) {
|
||||
if(remaining <= 0) break
|
||||
remaining -= charger.withdrawEnergy(remaining)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// PLEASE only call if consumer, in the name of all that is holy
|
||||
fun tryToChargeFully() {
|
||||
var remaining = energyCapacity - energy
|
||||
if(remaining <= 0) return
|
||||
for (charger in getChargerNodes()) {
|
||||
if(remaining <= 0) break
|
||||
val amount = charger.withdrawEnergy(remaining)
|
||||
val given = giveEnergy(amount)
|
||||
remaining -= given
|
||||
if(given < amount) {
|
||||
val delta = amount - given // amount lost while given back
|
||||
if(charger.giveEnergy(delta) < delta) {
|
||||
NeoComputers.LOGGER.warn("LOSING ENERGY! Tried giving $delta back to $charger and we're losing our marbles!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// only call if storage
|
||||
fun balanceStorage() {
|
||||
for(battery in getReachable()) {
|
||||
if(battery.powerRole != PowerRole.STORAGE) continue
|
||||
// its so if for example we have a battery with 2x the capacity
|
||||
// we don't try to even the energy between them since that's just bad
|
||||
// and might pointless delete energy over time
|
||||
val capacityRatio = energyCapacity.toDouble() / battery.energyCapacity
|
||||
|
||||
val meaningfulSurplus = (battery.energy * capacityRatio - energy).toLong()
|
||||
|
||||
if(meaningfulSurplus <= 0) {
|
||||
// WE'RE greedy (or negligible surplus)? Do nothing
|
||||
continue
|
||||
}
|
||||
|
||||
// steal from this greedy mf
|
||||
val toSteal = meaningfulSurplus / 2
|
||||
if(toSteal == 0L) continue // broke storahh
|
||||
|
||||
val stolen = battery.withdrawEnergy(toSteal)
|
||||
if(giveEnergy(stolen) < stolen) {
|
||||
NeoComputers.LOGGER.warn("LOSING ENERGY IN NODE $address!!!! THIS IS REALLY BAD!!!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rob the generators
|
||||
fun stealGeneratorPower() {
|
||||
var remaining = energyCapacity - energy
|
||||
|
||||
for(generator in getReachable()) {
|
||||
if(generator.powerRole != PowerRole.GENERATOR) continue
|
||||
// rob this mf
|
||||
val robbed = generator.withdrawEnergy(remaining)
|
||||
val taken = giveEnergy(robbed)
|
||||
if(taken < robbed) {
|
||||
NeoComputers.LOGGER.warn("energy caught being DELETED in the big 26")
|
||||
}
|
||||
remaining -= taken
|
||||
}
|
||||
}
|
||||
|
||||
open fun tick() {
|
||||
if(powerRole == PowerRole.CONSUMER) tryToChargeFully()
|
||||
if(powerRole == PowerRole.STORAGE) {
|
||||
stealGeneratorPower()
|
||||
balanceStorage()
|
||||
}
|
||||
}
|
||||
// processes a received message
|
||||
open fun received(message: Message) {}
|
||||
|
||||
// called when a new direct connection is made
|
||||
open fun onConnect(deviceNode: DeviceNode) {}
|
||||
// called when a direct connection is lost
|
||||
open fun onDisconnect(deviceNode: DeviceNode) {}
|
||||
|
||||
// called when a new node is added globally
|
||||
open fun onNodeAdded(deviceNode: DeviceNode) {
|
||||
invalidateReachableCache()
|
||||
}
|
||||
|
||||
// called when a node is removed globally
|
||||
open fun onNodeRemoved(deviceNode: DeviceNode) {
|
||||
invalidateReachableCache()
|
||||
}
|
||||
|
||||
fun getReachable(): Set<DeviceNode> {
|
||||
if(reachableCache == null) {
|
||||
reachableCache = computeReachable()
|
||||
}
|
||||
return reachableCache!!
|
||||
}
|
||||
|
||||
open fun invalidateReachableCache() {
|
||||
reachableCache = null
|
||||
}
|
||||
|
||||
// Returns a subset of connections, for a subset of direct
|
||||
// meant for things like drives which dont want to accidentally fuse networks
|
||||
open fun getPreferredFew() = setOf<DeviceNode>()
|
||||
|
||||
fun computeReachable(): Set<DeviceNode> {
|
||||
if(reachability == Visibility.NONE) {
|
||||
return setOf()
|
||||
}
|
||||
if(reachability == Visibility.SOME) {
|
||||
return getPreferredFew()
|
||||
}
|
||||
if(reachability == Visibility.NETWORK) {
|
||||
// absolute cinema
|
||||
val working = HashSet<DeviceNode>()
|
||||
val pending = mutableListOf(this)
|
||||
var iterCount = 0
|
||||
while(iterCount < maxHopCount && pending.isNotEmpty()) {
|
||||
iterCount++
|
||||
val subnode = pending.removeFirst()
|
||||
if(subnode in working) continue
|
||||
working.add(subnode)
|
||||
if(subnode.reachability == Visibility.NETWORK) {
|
||||
pending.addAll(subnode.connections)
|
||||
} else if(subnode.reachability == Visibility.SOME) {
|
||||
pending.addAll(subnode.getPreferredFew())
|
||||
}
|
||||
}
|
||||
// cannot send to itself!
|
||||
working.remove(this)
|
||||
return working
|
||||
}
|
||||
throw NotImplementedError("visibility not implemented")
|
||||
}
|
||||
|
||||
fun connectTo(other: DeviceNode) {
|
||||
this.directConnectTo(other)
|
||||
other.directConnectTo(this)
|
||||
}
|
||||
|
||||
fun disconnectFrom(other: DeviceNode) {
|
||||
this.directDisconnectFrom(other)
|
||||
other.directDisconnectFrom(this)
|
||||
}
|
||||
|
||||
fun directConnectTo(other: DeviceNode) {
|
||||
if(other == this) return
|
||||
if(other in connections) return
|
||||
connections.add(other)
|
||||
this.onConnect(other)
|
||||
invalidateReachableCache()
|
||||
}
|
||||
|
||||
fun directDisconnectFrom(other: DeviceNode) {
|
||||
if(other !in connections) return
|
||||
connections.remove(other)
|
||||
this.onDisconnect(other)
|
||||
invalidateReachableCache()
|
||||
}
|
||||
|
||||
// Network synchronization with the NodeSynchronizer
|
||||
// TODO: process shi
|
||||
|
||||
var outOfSync = false
|
||||
fun markChanged() {
|
||||
outOfSync = true
|
||||
}
|
||||
|
||||
open fun encodeScreenData(player: ServerPlayer, buf: FriendlyByteBuf) {}
|
||||
open fun processScreenInteraction(player: ServerPlayer, buf: FriendlyByteBuf) {}
|
||||
|
||||
// Meant to write the entire state as a single commit
|
||||
// for clients which say they have no fucking idea what the server is storing
|
||||
open fun writeFullStateCommit(buf: FriendlyByteBuf) {}
|
||||
|
||||
// client-side, meant to bring state forward
|
||||
open fun processCommit(buf: FriendlyByteBuf) {}
|
||||
|
||||
open fun getComponent(): NNComponent? = null
|
||||
}
|
||||
|
||||
// Used by the relay
|
||||
// If the ComponentItem in the card slot
|
||||
interface ConventionalNetworkDevice {
|
||||
fun sendClassicPacket(packet: Networking.ClassicPacket)
|
||||
}
|
||||
|
||||
abstract class WirelessEndpoint(address: UUID?) : DeviceNode(address) {
|
||||
|
||||
abstract fun getEndpointRange(): Double
|
||||
abstract fun getEndpointDimension(): Int
|
||||
abstract fun getEndpointLevel(): Level
|
||||
abstract fun getEndpointPosition(): Vec3
|
||||
// separate from process for simplicity
|
||||
abstract fun receiveWireless(message: Message, emitter: WirelessEndpoint)
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
package org.neoflock.neocomputers.network
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import net.minecraft.world.level.Level
|
||||
import org.neoflock.neocomputers.entity.MachineEvent
|
||||
import java.util.UUID
|
||||
import kotlin.math.min
|
||||
import kotlin.math.pow
|
||||
@@ -27,254 +28,50 @@ object Networking {
|
||||
enum class Visibility {
|
||||
// only it can see itself
|
||||
NONE,
|
||||
// can only see its direct connections
|
||||
DIRECT,
|
||||
// some, as determined by getPreferredFew()
|
||||
SOME,
|
||||
// Can see everything network-wide
|
||||
NETWORK,
|
||||
}
|
||||
|
||||
|
||||
abstract class Message(val sender: Node)
|
||||
abstract class Message(val sender: DeviceNode)
|
||||
|
||||
class ClassicPacket(sender: Node, val src: String, val dst: String, val port: Int, val data: List<Any>, val hopCount: Int) : Message(sender) {
|
||||
fun hop() = ClassicPacket(sender, src, dst, port, data, hopCount + 1);
|
||||
// null dst means broadcast
|
||||
class ClassicPacket(sender: DeviceNode, val src: String, val dst: String?, val port: Int, val data: List<Any>, val hopCount: Int) : Message(sender) {
|
||||
fun hop(sender: DeviceNode) = ClassicPacket(sender, src, dst, port, data, hopCount + 1);
|
||||
}
|
||||
|
||||
// for plugins and shi
|
||||
class ComputerCheckedSignal(sender: Node, val player: String?, val name: String, val data: Array<Any>): Message(sender)
|
||||
class ComputerUncheckedSignal(sender: Node, val name: String, val data: Array<Any>): Message(sender)
|
||||
class ComputerCheckedSignal(sender: DeviceNode, val player: String?, val name: String, val data: Array<Any>): Message(sender)
|
||||
class ComputerUncheckedSignal(sender: DeviceNode, val name: String, val data: Array<Any>): Message(sender)
|
||||
class ComputerEvent(sender: DeviceNode, val machineEvent: MachineEvent): Message(sender)
|
||||
|
||||
open class Node(_address: UUID? = null) {
|
||||
val connections = mutableSetOf<Node>()
|
||||
private var reachableCache: Set<Node>? = null
|
||||
var address = _address ?: UUID.randomUUID()
|
||||
|
||||
open var reachability = Visibility.NETWORK
|
||||
open var powerRole = PowerRole.CONSUMER
|
||||
open var energy: Long = 0
|
||||
open var energyCapacity: Long = 0
|
||||
// give energy, returns how much was actually given
|
||||
// cannot exceed amount specified
|
||||
open fun giveEnergy(amount: Long): Long {
|
||||
val maximum = min(amount, energyCapacity - energy)
|
||||
energy += maximum
|
||||
return maximum
|
||||
}
|
||||
// take energy out, returns how much was actually taken
|
||||
// cannot exceed amount specified
|
||||
open fun withdrawEnergy(amount: Long): Long {
|
||||
val maximum = min(amount, energy)
|
||||
energy -= maximum
|
||||
return maximum
|
||||
}
|
||||
|
||||
fun getChargerNodes(): Set<Node> = getReachable().filter { it.powerRole != PowerRole.CONSUMER }.toSet()
|
||||
fun totalEnergyInConnections(): Long = getChargerNodes().fold(0) { acc, node -> acc + node.energy }
|
||||
fun maxEnergyInConnections(): Long = getChargerNodes().fold(0) { acc, node -> acc + node.energyCapacity }
|
||||
|
||||
// attempts to consume
|
||||
fun consumeEnergy(energy: Long): Boolean {
|
||||
// consumes energy, returns false if not enough
|
||||
val total = totalEnergyInConnections() + this.energy
|
||||
if(energy > total) return false
|
||||
|
||||
var remaining = energy
|
||||
remaining -= withdrawEnergy(remaining)
|
||||
if(remaining <= 0) return true
|
||||
|
||||
for (charger in getChargerNodes()) {
|
||||
if(remaining <= 0) break
|
||||
remaining -= charger.withdrawEnergy(remaining)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// PLEASE only call if consumer, in the name of all that is holy
|
||||
fun tryToChargeFully() {
|
||||
var remaining = energyCapacity - energy
|
||||
if(remaining <= 0) return
|
||||
for (charger in getChargerNodes()) {
|
||||
if(remaining <= 0) break
|
||||
val amount = charger.withdrawEnergy(remaining)
|
||||
val given = giveEnergy(amount)
|
||||
remaining -= given
|
||||
if(given < amount) {
|
||||
val delta = amount - given // amount lost while given back
|
||||
if(charger.giveEnergy(delta) < delta) {
|
||||
NeoComputers.LOGGER.warn("LOSING ENERGY! Tried giving $delta back to $charger and we're losing our marbles!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// only call if storage
|
||||
fun balanceStorage() {
|
||||
for(battery in getReachable()) {
|
||||
if(battery.powerRole != PowerRole.STORAGE) continue
|
||||
// its so if for example we have a battery with 2x the capacity
|
||||
// we don't try to even the energy between them since that's just bad
|
||||
// and might pointless delete energy over time
|
||||
val capacityRatio = energyCapacity.toDouble() / battery.energyCapacity
|
||||
|
||||
val meaningfulSurplus = (battery.energy * capacityRatio - energy).toLong()
|
||||
|
||||
if(meaningfulSurplus <= 0) {
|
||||
// WE'RE greedy (or negligible surplus)? Do nothing
|
||||
continue
|
||||
}
|
||||
|
||||
// steal from this greedy mf
|
||||
val toSteal = meaningfulSurplus / 2
|
||||
if(toSteal == 0L) continue // broke storahh
|
||||
|
||||
val stolen = battery.withdrawEnergy(toSteal)
|
||||
if(giveEnergy(stolen) < stolen) {
|
||||
NeoComputers.LOGGER.warn("LOSING ENERGY IN NODE $this!!!! THIS IS REALLY BAD!!!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rob the generators
|
||||
fun stealGeneratorPower() {
|
||||
var remaining = energyCapacity - energy
|
||||
|
||||
for(generator in getReachable()) {
|
||||
if(generator.powerRole != PowerRole.GENERATOR) continue
|
||||
// rob this mf
|
||||
val robbed = generator.withdrawEnergy(remaining)
|
||||
val taken = giveEnergy(robbed)
|
||||
if(taken < robbed) {
|
||||
NeoComputers.LOGGER.warn("energy caught being DELETED in the big 26")
|
||||
}
|
||||
remaining -= taken
|
||||
}
|
||||
}
|
||||
|
||||
open fun tick() {
|
||||
if(powerRole == PowerRole.CONSUMER) tryToChargeFully()
|
||||
if(powerRole == PowerRole.STORAGE) {
|
||||
stealGeneratorPower()
|
||||
balanceStorage()
|
||||
}
|
||||
}
|
||||
// processes a received message
|
||||
open fun received(message: Message) {}
|
||||
|
||||
// called when a new direct connection is made
|
||||
open fun onConnect(node: Node) {}
|
||||
// called when a direct connection is lost
|
||||
open fun onDisconnect(node: Node) {}
|
||||
|
||||
// called when a new node is added globally
|
||||
open fun onNodeAdded(node: Node) {
|
||||
reachableCache = null;
|
||||
}
|
||||
|
||||
// called when a node is removed globally
|
||||
open fun onNodeRemoved(node: Node) {
|
||||
reachableCache = null;
|
||||
}
|
||||
|
||||
fun getReachable(): Set<Node> {
|
||||
if(reachableCache == null) {
|
||||
reachableCache = computeReachable();
|
||||
}
|
||||
return reachableCache!!;
|
||||
}
|
||||
|
||||
fun invalidateReachableCache() {
|
||||
reachableCache = null
|
||||
}
|
||||
|
||||
fun computeReachable(): Set<Node> {
|
||||
if(reachability == Visibility.NONE) {
|
||||
return setOf();
|
||||
}
|
||||
if(reachability == Visibility.DIRECT) {
|
||||
return connections.minus(this);
|
||||
}
|
||||
if(reachability == Visibility.NETWORK) {
|
||||
// absolute cinema
|
||||
val working = mutableSetOf<Node>();
|
||||
val pending = mutableListOf(this);
|
||||
var iterCount = 0;
|
||||
while(iterCount < maxHopCount && pending.isNotEmpty()) {
|
||||
iterCount++;
|
||||
val subnode = pending.removeFirst();
|
||||
if(subnode in working) continue;
|
||||
working.add(subnode);
|
||||
pending.addAll(subnode.connections);
|
||||
}
|
||||
// cannot send to itself!
|
||||
working.remove(this);
|
||||
return working;
|
||||
}
|
||||
throw NotImplementedError("visibility not implemented");
|
||||
}
|
||||
|
||||
fun connectTo(other: Node) {
|
||||
this.directConnectTo(other);
|
||||
other.directConnectTo(this);
|
||||
}
|
||||
|
||||
fun disconnectFrom(other: Node) {
|
||||
this.directDisconnectFrom(other);
|
||||
other.directDisconnectFrom(this);
|
||||
}
|
||||
|
||||
fun directConnectTo(other: Node) {
|
||||
if(other == this) return;
|
||||
if(other in connections) return;
|
||||
connections.add(other);
|
||||
this.onConnect(other);
|
||||
}
|
||||
|
||||
fun directDisconnectFrom(other: Node) {
|
||||
if(other !in connections) return;
|
||||
connections.remove(other);
|
||||
this.onDisconnect(other);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class WirelessEndpoint(address: UUID?) : Node(address) {
|
||||
|
||||
abstract fun getRange(): Double
|
||||
abstract fun getDimension(): Int
|
||||
abstract fun getPosition(): BlockPos
|
||||
// separate from process for simplicity
|
||||
abstract fun receiveWireless(message: Message, emitter: WirelessEndpoint)
|
||||
}
|
||||
|
||||
val wirelessNodes = ThreadLocal.withInitial { mutableSetOf<WirelessEndpoint>() }
|
||||
val allNodes = ThreadLocal.withInitial { mutableMapOf<UUID, Node>() }
|
||||
val wirelessNodes = ThreadLocal.withInitial { HashSet<WirelessEndpoint>() }
|
||||
val allNodes = ThreadLocal.withInitial { HashMap<UUID, DeviceNode>() }
|
||||
|
||||
// node may differ from message.sender in the case of relays,
|
||||
// as they might have DIRECT reachability but
|
||||
fun emitMessage(node: Node, message: Message) {
|
||||
node.getReachable().forEach { it.received(message) }
|
||||
fun emitMessage(deviceNode: DeviceNode, message: Message, exclude: Set<DeviceNode> = setOf()) {
|
||||
deviceNode.getReachable().forEach { if(it !in exclude) it.received(message) }
|
||||
}
|
||||
|
||||
fun computeRangeAllowedByHardness(src: BlockPos, dst: BlockPos): Double {
|
||||
fun computeRangeAllowedByHardness(level: Level, src: BlockPos, dst: BlockPos): Double {
|
||||
return Double.POSITIVE_INFINITY // TODO: math
|
||||
}
|
||||
|
||||
fun distanceBetween(a: BlockPos, b: BlockPos): Double {
|
||||
return sqrt((a.x - b.x + a.y - b.y + a.z - b.z).toDouble().pow(2.0));
|
||||
}
|
||||
|
||||
fun emitWirelessMessage(starter: WirelessEndpoint, range: Double, message: Message) {
|
||||
val startPos = starter.getPosition();
|
||||
val startDim = starter.getDimension();
|
||||
val range = starter.getRange();
|
||||
val startPos = starter.getEndpointPosition()
|
||||
val startDim = starter.getEndpointDimension()
|
||||
val level = starter.getEndpointLevel()
|
||||
wirelessNodes.get().forEach {
|
||||
if(it.getDimension() != startDim) return;
|
||||
val pos = it.getPosition();
|
||||
val d = distanceBetween(startPos, pos);
|
||||
var trueRange = min(it.getRange(), range);
|
||||
trueRange = min(trueRange, computeRangeAllowedByHardness(startPos, pos));
|
||||
if(d > trueRange) return;
|
||||
it.receiveWireless(message, starter);
|
||||
if(it.getEndpointDimension() != startDim) return
|
||||
val pos = it.getEndpointPosition()
|
||||
val d = startPos.distanceTo(pos)
|
||||
var trueRange = min(it.getEndpointRange(), range)
|
||||
trueRange = min(trueRange, computeRangeAllowedByHardness(level, BlockPos.containing(startPos), BlockPos.containing(pos)))
|
||||
if(d > trueRange) return
|
||||
it.receiveWireless(message, starter)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,69 +80,80 @@ object Networking {
|
||||
tickCount++
|
||||
}
|
||||
|
||||
fun getNode(address: UUID): Node? = allNodes.get()[address]
|
||||
fun getNode(address: UUID): DeviceNode? = allNodes.get()[address]
|
||||
|
||||
// TODO: use setter, more convenient
|
||||
fun changeNodeAddress(node: Node, address: UUID) {
|
||||
if(node.address.equals(address)) return
|
||||
if(node.address !in allNodes.get()) return
|
||||
allNodes.get().remove(node.address)
|
||||
node.address = address
|
||||
allNodes.get()[address] = node
|
||||
fun changeNodeAddress(deviceNode: DeviceNode, address: UUID): Boolean {
|
||||
if(deviceNode.address.equals(address)) return false
|
||||
if(deviceNode.address !in allNodes.get()) return false
|
||||
if(address in allNodes.get()) return false
|
||||
allNodes.get().remove(deviceNode.address)
|
||||
deviceNode.address = address
|
||||
allNodes.get()[address] = deviceNode
|
||||
return true
|
||||
}
|
||||
|
||||
fun addNode(node: Node) {
|
||||
if(node.address in allNodes.get()) return
|
||||
allNodes.get()[node.address] = node
|
||||
if(node is WirelessEndpoint) {
|
||||
wirelessNodes.get().add(node);
|
||||
fun addNode(deviceNode: DeviceNode) {
|
||||
if(deviceNode.address in allNodes.get()) return
|
||||
allNodes.get()[deviceNode.address] = deviceNode
|
||||
if(deviceNode is WirelessEndpoint) {
|
||||
wirelessNodes.get().add(deviceNode);
|
||||
}
|
||||
// notify at the end so it is notified of its own creation
|
||||
allNodes.get().forEach { it.value.onNodeAdded(node) }
|
||||
allNodes.get().forEach { it.value.onNodeAdded(deviceNode) }
|
||||
}
|
||||
|
||||
fun addNodes(vararg nodes: Node) {
|
||||
nodes.forEach { addNode(it) }
|
||||
fun addNodes(deviceNodes: Iterable<DeviceNode>) {
|
||||
deviceNodes.forEach { addNode(it) }
|
||||
}
|
||||
|
||||
fun removeNode(node: Node) {
|
||||
if(node.address !in allNodes.get()) return
|
||||
allNodes.get().forEach { it.value.onNodeRemoved(node) }
|
||||
fun addNodes(vararg deviceNodes: DeviceNode) {
|
||||
addNodes(deviceNodes.asIterable())
|
||||
}
|
||||
|
||||
fun removeNode(deviceNode: DeviceNode) {
|
||||
if(deviceNode.address !in allNodes.get()) return
|
||||
NodeSynchronizer.nodeErased(deviceNode)
|
||||
allNodes.get().forEach { it.value.onNodeRemoved(deviceNode) }
|
||||
// toList() in order to copy it
|
||||
node.connections.toList().forEach {
|
||||
node.disconnectFrom(it)
|
||||
deviceNode.connections.toList().forEach {
|
||||
deviceNode.disconnectFrom(it)
|
||||
}
|
||||
// actually remove at the end so it can listen to its own removal
|
||||
allNodes.get().remove(node.address)
|
||||
if(node is WirelessEndpoint) {
|
||||
wirelessNodes.get().remove(node);
|
||||
allNodes.get().remove(deviceNode.address)
|
||||
if(deviceNode is WirelessEndpoint) {
|
||||
wirelessNodes.get().remove(deviceNode);
|
||||
}
|
||||
}
|
||||
|
||||
fun removeNodes(vararg nodes: Node) {
|
||||
nodes.forEach { removeNode(it) }
|
||||
fun removeNodes(deviceNodes: Iterable<DeviceNode>) {
|
||||
deviceNodes.forEach { removeNode(it) }
|
||||
}
|
||||
|
||||
val channels = ThreadLocal.withInitial { mutableMapOf<String, MutableSet<Node>>() }
|
||||
fun removeNodes(vararg deviceNodes: DeviceNode) {
|
||||
removeNodes(deviceNodes.asIterable())
|
||||
}
|
||||
|
||||
fun addToChannel(channel: String, node: Node) {
|
||||
val channels = ThreadLocal.withInitial { HashMap<String, MutableSet<DeviceNode>>() }
|
||||
|
||||
fun addToChannel(channel: String, deviceNode: DeviceNode) {
|
||||
val localChannels = channels.get()
|
||||
if(!localChannels.containsKey(channel)) {
|
||||
localChannels[channel] = mutableSetOf();
|
||||
}
|
||||
localChannels[channel]!!.add(node);
|
||||
localChannels[channel]!!.add(deviceNode);
|
||||
}
|
||||
|
||||
fun removeFromChannel(channel: String, node: Node) {
|
||||
fun removeFromChannel(channel: String, deviceNode: DeviceNode) {
|
||||
val localChannels = channels.get()
|
||||
if(!localChannels.containsKey(channel)) return;
|
||||
localChannels[channel]?.remove(node);
|
||||
localChannels[channel]?.remove(deviceNode);
|
||||
if(localChannels[channel].isNullOrEmpty()) {
|
||||
localChannels.remove(channel);
|
||||
}
|
||||
}
|
||||
|
||||
fun emitChannelMessage(starter: Node, channel: String, message: Message) {
|
||||
fun emitChannelMessage(starter: DeviceNode, channel: String, message: Message) {
|
||||
val localChannels = channels.get()
|
||||
val c = localChannels[channel] ?: return;
|
||||
c.forEach { if(it != starter) it.received(message); };
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
package org.neoflock.neocomputers.network
|
||||
|
||||
import dev.architectury.networking.NetworkManager
|
||||
import io.netty.buffer.Unpooled
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.network.codec.StreamCodec
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.level.Level
|
||||
import org.neoflock.neocomputers.NeoComputers
|
||||
import java.time.Duration
|
||||
|
||||
object NodeSynchronizer {
|
||||
val MAX_STATE_DISTANCE_ALLOWED = 128
|
||||
|
||||
class DeviceBlockStatePayload(var blockPos: BlockPos, var buffers: List<FriendlyByteBuf>): CustomPacketPayload {
|
||||
companion object {
|
||||
val BLOCKDEV_SYNC_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "blockdev_sync")
|
||||
val TYPE = CustomPacketPayload.Type<DeviceBlockStatePayload>(BLOCKDEV_SYNC_ID)
|
||||
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, DeviceBlockStatePayload> {
|
||||
override fun decode(buf: RegistryFriendlyByteBuf): DeviceBlockStatePayload {
|
||||
val blockPos = buf.readBlockPos()
|
||||
val bufferCount = buf.readVarInt()
|
||||
val buffers = List(bufferCount) {
|
||||
val bytes = buf.readByteArray()
|
||||
val rawBuf = Unpooled.buffer(bytes.size)
|
||||
rawBuf.writeBytes(bytes)
|
||||
FriendlyByteBuf(rawBuf)
|
||||
}
|
||||
return DeviceBlockStatePayload(blockPos, buffers)
|
||||
}
|
||||
|
||||
override fun encode(buf: RegistryFriendlyByteBuf, payload: DeviceBlockStatePayload) {
|
||||
buf.writeBlockPos(payload.blockPos)
|
||||
buf.writeVarInt(payload.buffers.size)
|
||||
payload.buffers.forEach {
|
||||
buf.writeByteArray(it.array())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun type() = TYPE
|
||||
}
|
||||
|
||||
class DeviceBlockStateRequest(var blockPos: BlockPos): CustomPacketPayload {
|
||||
companion object {
|
||||
val BLOCKDEV_REQ_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "blockdev_statereq")
|
||||
val TYPE = CustomPacketPayload.Type<DeviceBlockStateRequest>(BLOCKDEV_REQ_ID)
|
||||
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, DeviceBlockStateRequest> {
|
||||
override fun decode(buf: RegistryFriendlyByteBuf): DeviceBlockStateRequest {
|
||||
val blockPos = buf.readBlockPos()
|
||||
return DeviceBlockStateRequest(blockPos)
|
||||
}
|
||||
|
||||
override fun encode(buf: RegistryFriendlyByteBuf, payload: DeviceBlockStateRequest) {
|
||||
buf.writeBlockPos(payload.blockPos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun type() = TYPE
|
||||
}
|
||||
|
||||
class ScreenPayload(var buffer: FriendlyByteBuf): CustomPacketPayload {
|
||||
companion object {
|
||||
val SCREEN_SYNC_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "screen_sync")
|
||||
val TYPE = CustomPacketPayload.Type<ScreenPayload>(SCREEN_SYNC_ID)
|
||||
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, ScreenPayload> {
|
||||
override fun decode(buf: RegistryFriendlyByteBuf): ScreenPayload {
|
||||
val buffer = FriendlyByteBuf(buf.copy(buf.readerIndex(), buf.readableBytes()))
|
||||
return ScreenPayload(buffer)
|
||||
}
|
||||
|
||||
override fun encode(buf: RegistryFriendlyByteBuf, payload: ScreenPayload) {
|
||||
buf.writeBytes(payload.buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun type() = TYPE
|
||||
}
|
||||
|
||||
class ScreenDataPayload(var buffer: FriendlyByteBuf): CustomPacketPayload {
|
||||
companion object {
|
||||
val SCREEN_DATA_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "screen_data")
|
||||
val TYPE = CustomPacketPayload.Type<ScreenDataPayload>(SCREEN_DATA_ID)
|
||||
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, ScreenDataPayload> {
|
||||
override fun decode(buf: RegistryFriendlyByteBuf): ScreenDataPayload {
|
||||
val buffer = FriendlyByteBuf(buf.copy(buf.readerIndex(), buf.readableBytes()))
|
||||
return ScreenDataPayload(buffer)
|
||||
}
|
||||
|
||||
override fun encode(buf: RegistryFriendlyByteBuf, payload: ScreenDataPayload) {
|
||||
buf.writeBytes(payload.buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun type() = TYPE
|
||||
}
|
||||
|
||||
class BeepDataPayload(val pos: BlockPos, val pattern: String, val freq: Int, val duration: Duration, val volume: Double): CustomPacketPayload {
|
||||
companion object {
|
||||
val BEEP_DATA_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "beep_data")
|
||||
val TYPE = CustomPacketPayload.Type<BeepDataPayload>(BEEP_DATA_ID)
|
||||
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, BeepDataPayload> {
|
||||
override fun decode(buf: RegistryFriendlyByteBuf): BeepDataPayload {
|
||||
val pos = buf.readBlockPos()
|
||||
val pattern = buf.readUtf()
|
||||
val freq = buf.readVarInt()
|
||||
val duration = buf.readVarLong()
|
||||
val volume = buf.readDouble()
|
||||
return BeepDataPayload(pos, pattern, freq, Duration.ofMillis(duration), volume)
|
||||
}
|
||||
|
||||
override fun encode(buf: RegistryFriendlyByteBuf, payload: BeepDataPayload) {
|
||||
buf.writeBlockPos(payload.pos)
|
||||
buf.writeUtf(payload.pattern)
|
||||
buf.writeVarInt(payload.freq)
|
||||
buf.writeVarLong(payload.duration.toMillis())
|
||||
buf.writeDouble(payload.volume)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun type() = TYPE
|
||||
}
|
||||
|
||||
val screenMap = HashMap<ServerPlayer, DeviceNode>()
|
||||
|
||||
fun playerScreenClosed(player: ServerPlayer) {
|
||||
screenMap.remove(player)
|
||||
}
|
||||
|
||||
fun registerPlayerScreen(player: ServerPlayer, devNode: DeviceNode) {
|
||||
screenMap[player] = devNode
|
||||
}
|
||||
|
||||
fun nodeErased(node: DeviceNode) {
|
||||
var player: ServerPlayer? = null
|
||||
for((p, n) in screenMap) {
|
||||
if(n == node) player = p
|
||||
}
|
||||
if(player != null) screenMap.remove(player)
|
||||
}
|
||||
|
||||
fun syncScreens() {
|
||||
for((player, ent) in screenMap) {
|
||||
val buf = FriendlyByteBuf(Unpooled.buffer())
|
||||
ent.encodeScreenData(player, buf)
|
||||
NetworkManager.sendToPlayer(player, ScreenPayload(buf))
|
||||
}
|
||||
}
|
||||
|
||||
fun sendScreenInteraction(friendlyByteBuf: FriendlyByteBuf) {
|
||||
NetworkManager.sendToServer(ScreenDataPayload(friendlyByteBuf))
|
||||
}
|
||||
|
||||
fun emitBeep(level: Level, beepDataPayload: BeepDataPayload) {
|
||||
if(level is ServerLevel) {
|
||||
level.players().forEach {
|
||||
NetworkManager.sendToPlayer(it, beepDataPayload)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +1,46 @@
|
||||
package org.neoflock.neocomputers.network
|
||||
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||
import org.neoflock.neocomputers.block.DeviceBlockEntity
|
||||
//? if fabric {
|
||||
import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext
|
||||
import org.neoflock.neocomputers.block.NodeBlockEntity
|
||||
/*import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext
|
||||
import net.minecraft.core.Direction
|
||||
import team.reborn.energy.api.EnergyStorage;
|
||||
//?}
|
||||
*///?}
|
||||
|
||||
// our soul purpose is to fuse bullshit power APIs together
|
||||
// the NodeBlockEntity and Node given us a way to get power from a block, we just
|
||||
// need to tell mods how to do it as well
|
||||
object PowerManager {
|
||||
fun<T: NodeBlockEntity> registerPowerBlockEntity(blockEntityType: BlockEntityType<T>) {
|
||||
fun<T: DeviceBlockEntity> registerPowerDevice(blockEntityType: BlockEntityType<T>) {
|
||||
//? if fabric {
|
||||
EnergyStorage.SIDED.registerForBlockEntity({
|
||||
entity, dir -> object : EnergyStorage {
|
||||
override fun getAmount() = entity.node.energy
|
||||
override fun getCapacity() = entity.node.energyCapacity
|
||||
override fun supportsExtraction() = entity.node.powerRole != PowerRole.CONSUMER && entity.node.energyCapacity > 0
|
||||
override fun supportsInsertion() = entity.node.powerRole != PowerRole.GENERATOR
|
||||
override fun extract(maxAmount: Long, transaction: TransactionContext?): Long {
|
||||
if(entity.node.powerRole == PowerRole.CONSUMER) return 0
|
||||
val taken = entity.node.withdrawEnergy(maxAmount)
|
||||
transaction?.addCloseCallback {
|
||||
ctx, res -> if(res.wasAborted() || !res.wasCommitted()) entity.node.giveEnergy(taken)
|
||||
/*EnergyStorage.SIDED.registerForBlockEntity({
|
||||
// TODO: as this is currently written, if the node instance changes and the mod cached the conversion, we're boned. Consider fixing it.
|
||||
entity, dir ->
|
||||
val node = entity.getNodeFromSide(dir ?: Direction.UP)
|
||||
if(node == null) null else object : EnergyStorage {
|
||||
override fun getAmount() = node.energy
|
||||
override fun getCapacity() = node.energyCapacity
|
||||
override fun supportsExtraction() = node.powerRole != PowerRole.CONSUMER && node.energyCapacity > 0
|
||||
override fun supportsInsertion() = node.powerRole != PowerRole.GENERATOR
|
||||
override fun extract(maxAmount: Long, transaction: TransactionContext?): Long {
|
||||
if(node.powerRole == PowerRole.CONSUMER) return 0
|
||||
val taken = node.withdrawEnergy(maxAmount)
|
||||
transaction?.addCloseCallback {
|
||||
ctx, res -> if(res.wasAborted() || !res.wasCommitted()) node.giveEnergy(taken)
|
||||
}
|
||||
return taken
|
||||
}
|
||||
return taken
|
||||
}
|
||||
override fun insert(maxAmount: Long, transaction: TransactionContext?): Long {
|
||||
if(entity.node.powerRole == PowerRole.GENERATOR) return 0
|
||||
val given = entity.node.giveEnergy(maxAmount)
|
||||
transaction?.addCloseCallback { ctx, res ->
|
||||
if (res.wasAborted() || !res.wasCommitted()) entity.node.withdrawEnergy(given)
|
||||
override fun insert(maxAmount: Long, transaction: TransactionContext?): Long {
|
||||
if(node.powerRole == PowerRole.GENERATOR) return 0
|
||||
val given = node.giveEnergy(maxAmount)
|
||||
transaction?.addCloseCallback { ctx, res ->
|
||||
if (res.wasAborted() || !res.wasCommitted()) node.withdrawEnergy(given)
|
||||
}
|
||||
return given
|
||||
}
|
||||
return given
|
||||
}
|
||||
}
|
||||
}, blockEntityType);
|
||||
//?}
|
||||
*///?}
|
||||
}
|
||||
}
|
||||
@@ -99,7 +99,6 @@ object Sounds {
|
||||
fun checkDone(): Boolean {
|
||||
if(dead) return true
|
||||
if(AL10.alGetSourcei(source, AL10.AL_SOURCE_STATE) == AL10.AL_PLAYING) return false
|
||||
NeoComputers.LOGGER.info("sound buffer stopped")
|
||||
dead = true
|
||||
AL10.alDeleteSources(source)
|
||||
AL10.alDeleteBuffers(buffer)
|
||||
@@ -146,10 +145,6 @@ object Sounds {
|
||||
}
|
||||
}
|
||||
finalBuf.rewind()
|
||||
val l = mutableListOf<Int>()
|
||||
while(finalBuf.hasRemaining()) l.addLast(finalBuf.get().toInt())
|
||||
finalBuf.rewind()
|
||||
NeoComputers.LOGGER.info("$l")
|
||||
|
||||
val sound = CustomSoundBuffer()
|
||||
val soundErr = sound.start(pos.x.toFloat(), pos.y.toFloat(), pos.z.toFloat(), finalBuf, gain.toFloat())
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
package org.neoflock.neocomputers.utils
|
||||
|
||||
// based off the ImplementedContainer of https://docs.fabricmc.net/develop/blocks/block-containers
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat
|
||||
import com.mojang.blaze3d.vertex.VertexFormat
|
||||
import dev.architectury.registry.menu.MenuRegistry
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.components.AbstractWidget
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener
|
||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
|
||||
import net.minecraft.client.renderer.RenderStateShard
|
||||
import net.minecraft.client.renderer.RenderStateShard.ShaderStateShard
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
@@ -68,7 +75,7 @@ abstract class GenericContainerMenu(menuType: MenuType<*>, id: Int, var containe
|
||||
// Based off the code in ChestMenu
|
||||
for (i in 0..2) {
|
||||
for (j in 0..8) {
|
||||
this.addSlot(Slot(inventory, j + i * 9 + 9, 8 + j * 18, 84 + i * 18))
|
||||
this.addSlot(Slot(inventory, j + i * 9 + 9, 8 + j * 18, y + i * 18))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,6 +135,15 @@ abstract class GenericContainerScreen<T: GenericContainerMenu>(menu: T, inventor
|
||||
val imageY: Int
|
||||
get() = (height - imageHeight) / 2
|
||||
|
||||
var widgets = mutableListOf<AbstractWidget>()
|
||||
|
||||
val RENDER_TYPE = { r: ResourceLocation ->
|
||||
RenderType.create("nc_gui_bg", DefaultVertexFormat.POSITION_TEX, VertexFormat.Mode.QUADS, RenderType.TRANSIENT_BUFFER_SIZE, RenderType.CompositeState.builder()
|
||||
.setShaderState(ShaderStateShard.POSITION_TEX_SHADER)
|
||||
.setTextureState(RenderStateShard.TextureStateShard(r, false, false))
|
||||
.createCompositeState(false))
|
||||
}
|
||||
|
||||
override fun init() {
|
||||
super.init()
|
||||
|
||||
@@ -138,24 +154,50 @@ abstract class GenericContainerScreen<T: GenericContainerMenu>(menu: T, inventor
|
||||
val menuTex = findMenuTexture()
|
||||
val cx = (width - imageWidth) / 2
|
||||
val cy = (height - imageHeight) / 2
|
||||
guiGraphics.pose().pushPose()
|
||||
guiGraphics.pose().translate(cx.toFloat(), cy.toFloat(), 0f)
|
||||
|
||||
guiGraphics.blit(menuTex, imageX, imageY, 0, 0, imageWidth, imageHeight)
|
||||
guiGraphics.blit(menuTex, 0, 0, 0, 0, imageWidth, imageHeight)
|
||||
renderbg(guiGraphics, f, i-cx, j-cy)
|
||||
|
||||
for (widget in widgets) {
|
||||
widget.render(guiGraphics, i-cx, j-cy, f)
|
||||
}
|
||||
|
||||
for (slot in menu.slots) {
|
||||
if (slot is DynamicSlot) {
|
||||
// NeoComputers.LOGGER.info("slot")
|
||||
slot.draw(guiGraphics, cx, cy, i, j)
|
||||
slot.draw(guiGraphics, i-cx, j-cy)
|
||||
}
|
||||
}
|
||||
|
||||
guiGraphics.pose().popPose()
|
||||
}
|
||||
|
||||
open fun renderCustomOverlay(graphics: GuiGraphics, mouseX: Int, mouseY: Int, blend: Float) {
|
||||
open fun renderbg(guiGraphics: GuiGraphics, partialTick: Float, mouseX: Int, mouseY: Int) {}
|
||||
|
||||
}
|
||||
open fun renderCustomOverlay(graphics: GuiGraphics, mouseX: Int, mouseY: Int, blend: Float) { }
|
||||
|
||||
override fun render(graphics: GuiGraphics, mouseX: Int, mouseY: Int, something: Float) {
|
||||
super.render(graphics, mouseX, mouseY, something)
|
||||
renderCustomOverlay(graphics, mouseX, mouseY, something)
|
||||
|
||||
graphics.pose().pushPose()
|
||||
graphics.pose().translate(imageX.toFloat(), imageY.toFloat(), 0f)
|
||||
renderCustomOverlay(graphics, mouseX-imageX, mouseY-imageY, something)
|
||||
graphics.pose().popPose() // not even doing this because it's better anymore, im just doing this because i dont want to change it back
|
||||
|
||||
if(shouldRenderTooltip()) super.renderTooltip(graphics, mouseX, mouseY)
|
||||
}
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
super.mouseClicked(mouseX, mouseY, button)
|
||||
for (widget in widgets) {
|
||||
if (widget.mouseClicked(mouseX-imageX, mouseY-imageY, button)) return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
fun addWidget(widget: AbstractWidget) {
|
||||
widgets.add(widget)
|
||||
}
|
||||
}
|
||||
162
src/main/kotlin/org/neoflock/neocomputers/utils/TextBuffer.kt
Normal file
162
src/main/kotlin/org/neoflock/neocomputers/utils/TextBuffer.kt
Normal file
@@ -0,0 +1,162 @@
|
||||
package org.neoflock.neocomputers.utils
|
||||
|
||||
import com.mojang.blaze3d.platform.NativeImage
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.renderer.texture.DynamicTexture
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.ResourceLocationPattern
|
||||
import org.neoflock.neocomputers.gui.widget.DynamicSlot
|
||||
import kotlin.experimental.and
|
||||
import kotlin.math.min
|
||||
|
||||
data class GPUChar(val c: Char, val fg: Int =0xFFFFFF, val bg: Int = 0) // all is bgr
|
||||
|
||||
// TODO: wrapper over NN buffer
|
||||
class TextBuffer(var width: Int, var height: Int) {
|
||||
// val CHARW = 8
|
||||
// val CHARH = 16
|
||||
//
|
||||
// val texwidth: Int
|
||||
// get() = width*CHARW
|
||||
//
|
||||
// val texheight: Int
|
||||
// get() = height*CHARH
|
||||
//
|
||||
// var image = NativeImage(texwidth, texheight, true)
|
||||
// var tex = DynamicTexture(image)
|
||||
|
||||
|
||||
val blank = GPUChar(' ')
|
||||
var buf = Array(width*height) { blank }
|
||||
// init {
|
||||
// Minecraft.getInstance().textureManager.register(this.id, tex)
|
||||
// }
|
||||
|
||||
// fun toRGBA(color: Int): Int {
|
||||
// // Minecaft lies, its AGBR
|
||||
// return java.lang.Integer.reverseBytes((color.toLong() * 256 + 0xFF).toInt())
|
||||
// }
|
||||
//
|
||||
// fun drawGlyph(x: Int, y: Int, c: Char, fg: Int) {
|
||||
// var glyph: ArrayList<Byte> = FontProvider.map[c]!!
|
||||
//
|
||||
// for (j in 0..<CHARH) {
|
||||
// for (i in 0..<CHARW) {
|
||||
// // var pixel = ((glyph[j] and ((1 shl (CHARW - i - 1)).toByte())).toInt()) ushr (CHARW - i - 1) // retardation
|
||||
// var pixel = (glyph[j] and (0b10000000 ushr i).toByte()).toInt()
|
||||
// if (pixel > 0) image.setPixelRGBA(x+i, y+j, toRGBA(fg))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun drawBuffer() {
|
||||
// for (i in 0..<width) {
|
||||
// for (j in 0..<height) {
|
||||
// var char: GPUChar = buf[j*height+i]
|
||||
// var x = i*CHARW
|
||||
// var y = j*CHARH
|
||||
// image.fillRect(x, y, CHARW, CHARH, toRGBA(char.bg))
|
||||
// if (char.c != ' ' && char.c != '\u0000') drawGlyph(x, y, char.c, char.fg)
|
||||
// }
|
||||
// }
|
||||
// tex.upload()
|
||||
// }
|
||||
//
|
||||
// fun clean() {
|
||||
// Minecraft.getInstance().textureManager.release(this.id)
|
||||
// image.close()
|
||||
// tex.close()
|
||||
// }
|
||||
|
||||
fun encodeContents(buf: FriendlyByteBuf) {
|
||||
// 0x01 means set fg, 0x02 means set bg,
|
||||
// 0x03 means set char+count
|
||||
var lastFg = 0xFFFFFF
|
||||
var lastBg = 0x000000
|
||||
|
||||
buf.writeVarInt(width)
|
||||
buf.writeVarInt(height)
|
||||
|
||||
var i = 0
|
||||
while(i < this.buf.size) {
|
||||
val px = this.buf[i]
|
||||
if(px.fg != lastFg) {
|
||||
buf.writeByte(0x01)
|
||||
buf.writeVarInt(px.fg)
|
||||
lastFg = px.fg
|
||||
}
|
||||
if(px.bg != lastBg) {
|
||||
buf.writeByte(0x02)
|
||||
buf.writeVarInt(px.bg)
|
||||
lastBg = px.bg
|
||||
}
|
||||
var charWritten = 1
|
||||
while((i+charWritten) < this.buf.size && this.buf[i+charWritten].c == px.c) charWritten++
|
||||
buf.writeByte(0x03)
|
||||
buf.writeVarInt(px.c.code)
|
||||
buf.writeVarInt(charWritten)
|
||||
i += charWritten
|
||||
}
|
||||
}
|
||||
|
||||
fun decodeContents(buf: FriendlyByteBuf) {
|
||||
var lastFg = 0xFFFFFF
|
||||
var lastBg = 0x000000
|
||||
|
||||
width = buf.readVarInt()
|
||||
height = buf.readVarInt()
|
||||
|
||||
if(width*height != this.buf.size) {
|
||||
this.buf = Array(width * height) { blank }
|
||||
}
|
||||
|
||||
var i = 0
|
||||
while(i < width*height) {
|
||||
val op = buf.readByte().toInt()
|
||||
if(op == 0x01) {
|
||||
lastFg = buf.readVarInt()
|
||||
}
|
||||
if(op == 0x02) {
|
||||
lastBg = buf.readVarInt()
|
||||
}
|
||||
if(op == 0x03) {
|
||||
val c = buf.readVarInt().toChar()
|
||||
val n = buf.readVarInt()
|
||||
|
||||
for(o in 0..<n) {
|
||||
this.buf[i+o] = GPUChar(c, lastFg, lastBg)
|
||||
}
|
||||
i += n
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun inBounds(x: Int, y: Int) = x >= 0 && y >= 0 && x < width && y < height
|
||||
fun get(x: Int, y: Int) = if(inBounds(x, y)) buf[x+y*width] else blank
|
||||
fun _set(x: Int, y: Int, pixel: GPUChar) {
|
||||
if(!inBounds(x, y)) return
|
||||
buf[x+y*width] = pixel
|
||||
// image.fillRect(x, y, CHARW, CHARH, toRGBA(pixel.bg))
|
||||
// if (pixel.c != ' ' && pixel.c != '\u0000') drawGlyph(x, y, pixel.c, pixel.fg)
|
||||
}
|
||||
fun set(x: Int, y: Int, text: String, fg: Int = 0xFFFFFF, bg: Int = 0x000000, vertical: Boolean = false) {
|
||||
for ((i, c) in text.toCharArray().withIndex()) {
|
||||
val cx = if(vertical) x else x + i
|
||||
val cy = if(vertical) y + i else y
|
||||
_set(cx, cy, GPUChar(c, fg, bg))
|
||||
}
|
||||
// tex.upload()
|
||||
}
|
||||
fun fill(x: Int, y: Int, w: Int, h: Int, pixel: GPUChar = blank) {
|
||||
// turn it into values we can fw
|
||||
val fw = min(w, width)
|
||||
val fh = min(h, height)
|
||||
for(py in y..<y+fh) {
|
||||
for (px in x..<x + fw) {
|
||||
_set(px, py, pixel)
|
||||
}
|
||||
}
|
||||
// tex.upload()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"variants": {
|
||||
"": { "model": "neocomputers:block/assembler" }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
{
|
||||
"multipart": [
|
||||
{ "apply": { "model": "neocomputers:block/cable/cable_center" }},
|
||||
{ "when": { "south": true },
|
||||
"apply": { "model": "neocomputers:block/cable/cable_connection" }},
|
||||
{ "when": { "east": true},
|
||||
"apply": { "model": "neocomputers:block/cable/cable_connection", "y": -90}},
|
||||
{ "when": { "west": true },
|
||||
"apply": { "model": "neocomputers:block/cable/cable_connection", "y": 90}},
|
||||
{ "when": { "north": true },
|
||||
"apply": { "model": "neocomputers:block/cable/cable_connection", "y": 180}},
|
||||
{ "when": { "up": true },
|
||||
"apply": { "model": "neocomputers:block/cable/cable_connection", "x": 90}},
|
||||
{ "when": { "down": true },
|
||||
"apply": { "model": "neocomputers:block/cable/cable_connection", "x": -90}},
|
||||
{
|
||||
"when": {
|
||||
"south": false,
|
||||
"north": false,
|
||||
"east": false,
|
||||
"west": false,
|
||||
"up": false,
|
||||
"down": false
|
||||
},
|
||||
"apply": { "model": "neocomputers:block/cable/cable_caps" }
|
||||
},
|
||||
{
|
||||
"when": {
|
||||
"south": true,
|
||||
"north": false,
|
||||
"east": false,
|
||||
"west": false,
|
||||
"up": false,
|
||||
"down": false
|
||||
},
|
||||
"apply": { "model": "neocomputers:block/cable/cable_cap" }
|
||||
},
|
||||
{
|
||||
"when": {
|
||||
"south": false,
|
||||
"north": true,
|
||||
"east": false,
|
||||
"west": false,
|
||||
"up": false,
|
||||
"down": false
|
||||
},
|
||||
"apply": { "model": "neocomputers:block/cable/cable_cap", "y": 180 }
|
||||
},
|
||||
{
|
||||
"when": {
|
||||
"south": false,
|
||||
"north": false,
|
||||
"east": true,
|
||||
"west": false,
|
||||
"up": false,
|
||||
"down": false
|
||||
},
|
||||
"apply": { "model": "neocomputers:block/cable/cable_cap", "y": -90 }
|
||||
},
|
||||
{
|
||||
"when": {
|
||||
"south": false,
|
||||
"north": false,
|
||||
"east": false,
|
||||
"west": true,
|
||||
"up": false,
|
||||
"down": false
|
||||
},
|
||||
"apply": { "model": "neocomputers:block/cable/cable_cap", "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": {
|
||||
"south": false,
|
||||
"north": false,
|
||||
"east": false,
|
||||
"west": false,
|
||||
"up": true,
|
||||
"down": false
|
||||
},
|
||||
"apply": { "model": "neocomputers:block/cable/cable_cap", "x": 90 }
|
||||
},
|
||||
{
|
||||
"when": {
|
||||
"south": false,
|
||||
"north": false,
|
||||
"east": false,
|
||||
"west": false,
|
||||
"up": false,
|
||||
"down": true
|
||||
},
|
||||
"apply": { "model": "neocomputers:block/cable/cable_cap", "x": -90 }
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"variants": {
|
||||
"": { "model": "neocomputers:block/rack"}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "neocomputers:block/relay"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "neocomputers:block/robot"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,57 @@
|
||||
{
|
||||
"variants": {
|
||||
"facing=north": {
|
||||
"facing_horiz=north,facing_verti=1": {
|
||||
"model": "neocomputers:block/screen"
|
||||
},
|
||||
"facing=east": {
|
||||
"facing_horiz=east,facing_verti=1": {
|
||||
"model": "neocomputers:block/screen",
|
||||
"y": 90
|
||||
},
|
||||
"facing=west": {
|
||||
"facing_horiz=west,facing_verti=1": {
|
||||
"model": "neocomputers:block/screen",
|
||||
"y": -90
|
||||
},
|
||||
"facing=south": {
|
||||
"facing_horiz=south,facing_verti=1": {
|
||||
"model": "neocomputers:block/screen",
|
||||
"y": 180
|
||||
},
|
||||
"facing=up": {
|
||||
"facing_horiz=north,facing_verti=0": {
|
||||
"model": "neocomputers:block/screen",
|
||||
"x": 90
|
||||
},
|
||||
"facing_horiz=east,facing_verti=0": {
|
||||
"model": "neocomputers:block/screen",
|
||||
"x": 90,
|
||||
"y": 90
|
||||
},
|
||||
"facing_horiz=west,facing_verti=0": {
|
||||
"model": "neocomputers:block/screen",
|
||||
"x": 90,
|
||||
"y": -90
|
||||
},
|
||||
"facing_horiz=south,facing_verti=0": {
|
||||
"model": "neocomputers:block/screen",
|
||||
"x": 90,
|
||||
"y": 180
|
||||
},
|
||||
"facing_horiz=north,facing_verti=2": {
|
||||
"model": "neocomputers:block/screen",
|
||||
"x": -90
|
||||
},
|
||||
"facing=down": {
|
||||
"facing_horiz=east,facing_verti=2": {
|
||||
"model": "neocomputers:block/screen",
|
||||
"x": 90
|
||||
"x": -90,
|
||||
"y": 90
|
||||
},
|
||||
"facing_horiz=west,facing_verti=2": {
|
||||
"model": "neocomputers:block/screen",
|
||||
"x": -90,
|
||||
"y": -90
|
||||
},
|
||||
"facing_horiz=south,facing_verti=2": {
|
||||
"model": "neocomputers:block/screen",
|
||||
"x": -90,
|
||||
"y": 180
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,9 @@
|
||||
"block.neocomputers.capacitor": "Small Capacitor",
|
||||
"block.neocomputers.capacitor2": "Medium Capacitor",
|
||||
"block.neocomputers.capacitor3": "Large Capacitor",
|
||||
"block.neocomputers.case": "Case (Untiered)",
|
||||
"block.neocomputers.cable": "Cable",
|
||||
"block.neocomputers.relay": "Relay",
|
||||
"item.neocomputers.eeprom0": "EEPROM (Tier 1)",
|
||||
"item.neocomputers.cpu0": "CPU (Tier 1)",
|
||||
"item.neocomputers.cpu1": "CPU (Tier 2)",
|
||||
@@ -38,16 +41,27 @@
|
||||
"item.neocomputers.hdd0": "Hard Disk Drive (Tier 1)",
|
||||
"item.neocomputers.hdd1": "Hard Disk Drive (Tier 2)",
|
||||
"item.neocomputers.hdd2": "Hard Disk Drive (Tier 3)",
|
||||
"neocomputers.errors.ENOCPU": "no CPU",
|
||||
"neocomputers.errors.E2BIG": "too many components",
|
||||
"neocomputers.errors.ENOENJ": "dangerously low energy",
|
||||
"neocomputers.errors.ENOMEM": "missing memory",
|
||||
"neocomputers.wlan.range": "Range: %1$s blocks",
|
||||
"neocomputers.data.limit": "Memory: %1$s",
|
||||
"neocomputers.gpu.vram": "Video Memory: %1$spx",
|
||||
"neocomputers.disk.spaceused": "Space Used: %1$s / %2$s",
|
||||
"neocomputers.gpu.vram": "Video memory: %1$spx",
|
||||
"neocomputers.disk.spaceused": "Space used: %1$s / %2$s",
|
||||
"neocomputers.readonly": "Read-Only",
|
||||
"neocomputers.readwrite": "Read-Write",
|
||||
"neocomputers.noaddr": "No address assigned",
|
||||
"neocomputers.computer.on": "ON",
|
||||
"neocomputers.computer.off": "OFF",
|
||||
"neocomputers.computer.errorNoMsg": "Error: ",
|
||||
"neocomputers.computer.energy": "Energy: %1$s / %2$s J",
|
||||
"neocomputers.computer.memory": "Memory: %1$s / %2$s",
|
||||
"neocomputers.computer.components": "Components: %1$s / %2$s",
|
||||
"neocomputers.memory.capacity": "Capacity: %1$s",
|
||||
"neocomputers.eeprom.codeused": "Code Storage: %1$s / %2$s",
|
||||
"neocomputers.eeprom.dataused": "Data Storage: %1$s / %2$s",
|
||||
"neocomputers.tunnel.channel": "Linked Channel: %1$s",
|
||||
"sounds.neocomputers.computer_running": "Computer Fans"
|
||||
"neocomputers.arch": "Architecture: %1$s",
|
||||
"neocomputers.eeprom.codeused": "Code stored: %1$s / %2$s",
|
||||
"neocomputers.eeprom.dataused": "Data stored: %1$s / %2$s",
|
||||
"neocomputers.tunnel.channel": "Linked channel: %1$s",
|
||||
"sounds.neocomputers.computer_running": "Computer fans"
|
||||
}
|
||||
67
src/main/resources/assets/neocomputers/lang/fr_fr.json
Normal file
67
src/main/resources/assets/neocomputers/lang/fr_fr.json
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"neocomputers.confirm": "Confirmer",
|
||||
"neocomputers.cancel": "Annuler",
|
||||
"block.neocomputers.combustgen": "Générateur à combustion",
|
||||
"block.neocomputers.redio": "Controleur de redstone",
|
||||
"item.neocomputers.redio0": "Carte redstone (niveau 1)",
|
||||
"item.neocomputers.redio1": "Carte redstone (niveau 2)",
|
||||
"block.neocomputers.solargen": "Panneau solaire",
|
||||
"block.neocomputers.screen": "Écran (sans niveau)",
|
||||
"block.neocomputers.capacitor": "Petit condensateur",
|
||||
"block.neocomputers.capacitor2": "Condensateur moyen",
|
||||
"block.neocomputers.capacitor3": "Grand condensateur",
|
||||
"block.neocomputers.case": "Boîtier (sans niveau)",
|
||||
"block.neocomputers.cable": "Cable",
|
||||
"block.neocomputers.relay": "Relais",
|
||||
"item.neocomputers.eeprom0": "EEPROM (niveau 1)",
|
||||
"item.neocomputers.cpu0": "Processeur (niveau 1)",
|
||||
"item.neocomputers.cpu1": "Processeur (niveau 2)",
|
||||
"item.neocomputers.cpu2": "Processeur (niveau 3)",
|
||||
"item.neocomputers.cbus0": "Bus informatique (niveau 1)",
|
||||
"item.neocomputers.cbus1": "Bus informatique (niveau 2)",
|
||||
"item.neocomputers.cbus2": "Bus informatique (niveau 3)",
|
||||
"item.neocomputers.cbus_creative": "Bus informatique (créatif)",
|
||||
"item.neocomputers.memory0": "Mémoire (niveau 1)",
|
||||
"item.neocomputers.memory1": "Mémoire (niveau 1,5)",
|
||||
"item.neocomputers.memory2": "Mémoire (niveau 2)",
|
||||
"item.neocomputers.memory3": "Mémoire (niveau 2,5)",
|
||||
"item.neocomputers.memory4": "Mémoire (niveau 3)",
|
||||
"item.neocomputers.memory5": "Mémoire (niveau 3,5)",
|
||||
"item.neocomputers.inet": "Carte internet",
|
||||
"item.neocomputers.lan": "Carte réseau sans fil",
|
||||
"item.neocomputers.wlan0": "Carte réseau sans fil (niveau 1)",
|
||||
"item.neocomputers.wlan1": "Carte réseau sans fil (niveau 2)",
|
||||
"item.neocomputers.tunnel": "Carte liée",
|
||||
"item.neocomputers.data0": "Carte de données (niveau 1)",
|
||||
"item.neocomputers.data1": "Carte de données (niveau 2)",
|
||||
"item.neocomputers.data2": "Carte de données (niveau 3)",
|
||||
"item.neocomputers.gpu0": "Carte graphiques (niveau 1)",
|
||||
"item.neocomputers.gpu1": "Carte graphiques (niveau 2)",
|
||||
"item.neocomputers.gpu2": "Carte graphiques (niveau 3)",
|
||||
"item.neocomputers.hdd0": "Disque dur (niveau 1)",
|
||||
"item.neocomputers.hdd1": "Disque dur (niveau 2)",
|
||||
"item.neocomputers.hdd2": "Disque dur (niveau 3)",
|
||||
"neocomputers.errors.ENOCPU": "absence d'un processeur",
|
||||
"neocomputers.errors.E2BIG": "trop de composants",
|
||||
"neocomputers.errors.ENOENJ": "niveau d'énergie dangereusement bas",
|
||||
"neocomputers.errors.ENOMEM": "absence de mémoire",
|
||||
"neocomputers.wlan.range": "Portée: %1$s blocs",
|
||||
"neocomputers.data.limit": "Mémoire: %1$s",
|
||||
"neocomputers.gpu.vram": "Mémoire vidéo: %1$spx",
|
||||
"neocomputers.disk.spaceused": "Espace utilisé: %1$s / %2$s",
|
||||
"neocomputers.readonly": "Lecture seule",
|
||||
"neocomputers.readwrite": "Lecture-écriture",
|
||||
"neocomputers.noaddr": "Pas d'adresse attribué",
|
||||
"neocomputers.computer.on": "ALLUMÉ",
|
||||
"neocomputers.computer.off": "ÉTEINT",
|
||||
"neocomputers.computer.errorNoMsg": "Erreur: ",
|
||||
"neocomputers.computer.energy": "Énergie: %1$s / %2$s J",
|
||||
"neocomputers.computer.memory": "Mémoire: %1$s / %2$s",
|
||||
"neocomputers.computer.components": "Composants: %1$s / %2$s",
|
||||
"neocomputers.memory.capacity": "Capacité: %1$s",
|
||||
"neocomputers.arch": "Architecture: %1$s",
|
||||
"neocomputers.eeprom.codeused": "Code stocké: %1$s / %2$s",
|
||||
"neocomputers.eeprom.dataused": "Données stockées: %1$s / %2$s",
|
||||
"neocomputers.tunnel.channel": "Chaîne connectée: %1$s",
|
||||
"sounds.neocomputers.computer_running": "Ventilateurs d'ordinateur"
|
||||
}
|
||||
67
src/main/resources/assets/neocomputers/lang/nl_nl.json
Normal file
67
src/main/resources/assets/neocomputers/lang/nl_nl.json
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"neocomputers.confirm": "Bevestigen",
|
||||
"neocomputers.cancel": "Annuleren",
|
||||
"block.neocomputers.combustgen": "Verbrandingsgenerator",
|
||||
"block.neocomputers.redio": "Redstone I/O",
|
||||
"item.neocomputers.redio0": "Redstonekaart (niveau 1)",
|
||||
"item.neocomputers.redio1": "Redstonekaart (niveau 2)",
|
||||
"block.neocomputers.solargen": "Zonnegenerator",
|
||||
"block.neocomputers.screen": "Scherm (niveauloos)",
|
||||
"block.neocomputers.capacitor": "Kleine condensator",
|
||||
"block.neocomputers.capacitor2": "Middelgrote condensator",
|
||||
"block.neocomputers.capacitor3": "Grote condensator",
|
||||
"block.neocomputers.case": "Behuizing (niveauloos)",
|
||||
"block.neocomputers.cable": "Kabel",
|
||||
"block.neocomputers.relay": "Doorgever",
|
||||
"item.neocomputers.eeprom0": "EEPROM (niveau 1)",
|
||||
"item.neocomputers.cpu0": "Processor (niveau 1)",
|
||||
"item.neocomputers.cpu1": "Processor (niveau 2)",
|
||||
"item.neocomputers.cpu2": "Processor (niveau 3)",
|
||||
"item.neocomputers.cbus0": "Componentenbus (niveau 1)",
|
||||
"item.neocomputers.cbus1": "Componentenbus (niveau 2)",
|
||||
"item.neocomputers.cbus2": "Componentenbus (niveau 3)",
|
||||
"item.neocomputers.cbus_creative": "Componentenbus (creatief)",
|
||||
"item.neocomputers.memory0": "Geheugen (niveau 1)",
|
||||
"item.neocomputers.memory1": "Geheugen (niveau 1,5)",
|
||||
"item.neocomputers.memory2": "Geheugen (niveau 2)",
|
||||
"item.neocomputers.memory3": "Geheugen (niveau 2,5)",
|
||||
"item.neocomputers.memory4": "Geheugen (niveau 3)",
|
||||
"item.neocomputers.memory5": "Geheugen (niveau 3,5)",
|
||||
"item.neocomputers.inet": "Internetkaart",
|
||||
"item.neocomputers.lan": "Bedrade netwerkkaart",
|
||||
"item.neocomputers.wlan0": "Draadloze netwerkkaart (niveau 1)",
|
||||
"item.neocomputers.wlan1": "Draadloze netwerkkaart (niveau 2)",
|
||||
"item.neocomputers.tunnel": "Gekoppelde kaart",
|
||||
"item.neocomputers.data0": "Datakaart (niveau 1)",
|
||||
"item.neocomputers.data1": "Datakaart (niveau 2)",
|
||||
"item.neocomputers.data2": "Datakaart (niveau 3)",
|
||||
"item.neocomputers.gpu0": "Videokaart (niveau 1)",
|
||||
"item.neocomputers.gpu1": "Videokaart (niveau 2)",
|
||||
"item.neocomputers.gpu2": "Videokaart (niveau 3)",
|
||||
"item.neocomputers.hdd0": "Harde schijf (niveau 1)",
|
||||
"item.neocomputers.hdd1": "Harde schijf (niveau 2)",
|
||||
"item.neocomputers.hdd2": "Harde schijf (niveau 3)",
|
||||
"neocomputers.errors.ENOCPU": "geen processor",
|
||||
"neocomputers.errors.E2BIG": "te veel componenten",
|
||||
"neocomputers.errors.ENOENJ": "gevaarlijk weinig stroom",
|
||||
"neocomputers.errors.ENOMEM": "geen geheugen",
|
||||
"neocomputers.wlan.range": "Bereik: %1$s blokken",
|
||||
"neocomputers.data.limit": "Geheugen: %1$s",
|
||||
"neocomputers.gpu.vram": "Videogeheugen: %1$spx",
|
||||
"neocomputers.disk.spaceused": "Gebruikte ruimte: %1$s / %2$s",
|
||||
"neocomputers.readonly": "Alleen-lezen",
|
||||
"neocomputers.readwrite": "Lezen-schrijven",
|
||||
"neocomputers.noaddr": "Geen adres toegewezen",
|
||||
"neocomputers.computer.on": "AAN",
|
||||
"neocomputers.computer.off": "UIT",
|
||||
"neocomputers.computer.errorNoMsg": "Fout: ",
|
||||
"neocomputers.computer.energy": "Stroom: %1$s / %2$s J",
|
||||
"neocomputers.computer.memory": "Geheugen: %1$s / %2$s",
|
||||
"neocomputers.computer.components": "Componenten: %1$s / %2$s",
|
||||
"neocomputers.memory.capacity": "Capaciteit: %1$s",
|
||||
"neocomputers.arch": "Architectuur: %1$s",
|
||||
"neocomputers.eeprom.codeused": "Opgeslagen code: %1$s / %2$s",
|
||||
"neocomputers.eeprom.dataused": "Opgeslagen data: %1$s / %2$s",
|
||||
"neocomputers.tunnel.channel": "Gekoppeld kanaal: %1$s",
|
||||
"sounds.neocomputers.computer_running": "Computerventilatoren"
|
||||
}
|
||||
68
src/main/resources/assets/neocomputers/lang/ro_ro.json
Normal file
68
src/main/resources/assets/neocomputers/lang/ro_ro.json
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"neocomputers.ro_ro.diacritics": "ĂăÂâÎîȘșȚț",
|
||||
"neocomputers.confirm": "Confirmă",
|
||||
"neocomputers.cancel": "Anulează",
|
||||
"block.neocomputers.combustgen": "Generator de Ardere",
|
||||
"block.neocomputers.redio": "Controlor Redstone",
|
||||
"item.neocomputers.redio0": "Placă Redstone (Grad 1)",
|
||||
"item.neocomputers.redio1": "Placă Redstone (Grad 2)",
|
||||
"block.neocomputers.solargen": "Generator Solar",
|
||||
"block.neocomputers.screen": "Ecran (fără grad)",
|
||||
"block.neocomputers.capacitor": "Condensator Electric Mic",
|
||||
"block.neocomputers.capacitor2": "Condensator Electric Mediu",
|
||||
"block.neocomputers.capacitor3": "Condensator Electric Mare",
|
||||
"block.neocomputers.case": "Carcasă (fără grad)",
|
||||
"block.neocomputers.cable": "Cabluri",
|
||||
"block.neocomputers.relay": "Releu",
|
||||
"item.neocomputers.eeprom0": "Memorie Programabilă Electronic (Grad 1)",
|
||||
"item.neocomputers.cpu0": "Procesor Central (Grad 1)",
|
||||
"item.neocomputers.cpu1": "Procesor Central (Grad 2)",
|
||||
"item.neocomputers.cpu2": "Procesor Central (Grad 3)",
|
||||
"item.neocomputers.cbus0": "Magistrală de Componente (Grad 1)",
|
||||
"item.neocomputers.cbus1": "Magistrală de Componente (Grad 2)",
|
||||
"item.neocomputers.cbus2": "Magistrală de Componente (Grad 3)",
|
||||
"item.neocomputers.cbus_creative": "Magistrală de Componente (Creativ)",
|
||||
"item.neocomputers.memory0": "Memorie (Grad 1)",
|
||||
"item.neocomputers.memory1": "Memorie (Grad 1.5)",
|
||||
"item.neocomputers.memory2": "Memorie (Grad 2)",
|
||||
"item.neocomputers.memory3": "Memorie (Grad 2.5)",
|
||||
"item.neocomputers.memory4": "Memorie (Grad 3)",
|
||||
"item.neocomputers.memory5": "Memorie (Grad 3.5)",
|
||||
"item.neocomputers.inet": "Placă de Internet",
|
||||
"item.neocomputers.lan": "Placă de Rețea pe Fir",
|
||||
"item.neocomputers.wlan0": "Placă de Rețea fără Fir (Grad 1)",
|
||||
"item.neocomputers.wlan1": "Placă de Rețea fără Fir (Grad 2)",
|
||||
"item.neocomputers.tunnel": "Placă Legată",
|
||||
"item.neocomputers.data0": "Placă de Date (Grad 1)",
|
||||
"item.neocomputers.data1": "Placă de Date (Grad 2)",
|
||||
"item.neocomputers.data2": "Placă de Date (Grad 3)",
|
||||
"item.neocomputers.gpu0": "Placă Video (Grad 1)",
|
||||
"item.neocomputers.gpu1": "Placă Video (Grad 2)",
|
||||
"item.neocomputers.gpu2": "Placă Video (Grad 3)",
|
||||
"item.neocomputers.hdd0": "Disc Dur (Grad 1)",
|
||||
"item.neocomputers.hdd1": "Disc Dur (Grad 2)",
|
||||
"item.neocomputers.hdd2": "Disc Dur (Grad 3)",
|
||||
"neocomputers.errors.ENOCPU": "fără procesor",
|
||||
"neocomputers.errors.E2BIG": "prea multe componente",
|
||||
"neocomputers.errors.ENOENJ": "prea puțină energie",
|
||||
"neocomputers.errors.ENOMEM": "fără memorie",
|
||||
"neocomputers.wlan.range": "Distanță maximă: %1$s blocks",
|
||||
"neocomputers.data.limit": "Memorie: %1$s",
|
||||
"neocomputers.gpu.vram": "Memorie video: %1$spx",
|
||||
"neocomputers.disk.spaceused": "Spațiu utilizat: %1$s / %2$s",
|
||||
"neocomputers.readonly": "Citit-Doar",
|
||||
"neocomputers.readwrite": "Citit-Scris",
|
||||
"neocomputers.noaddr": "Fără adresă",
|
||||
"neocomputers.computer.on": "PORNIT",
|
||||
"neocomputers.computer.off": "OPRIT",
|
||||
"neocomputers.computer.errorNoMsg": "Problemă: ",
|
||||
"neocomputers.computer.energy": "Energie: %1$s / %2$s J",
|
||||
"neocomputers.computer.memory": "Memorie: %1$s / %2$s",
|
||||
"neocomputers.computer.components": "Componente: %1$s / %2$s",
|
||||
"neocomputers.memory.capacity": "Capacitate: %1$s",
|
||||
"neocomputers.arch": "Arhitectură: %1$s",
|
||||
"neocomputers.eeprom.codeused": "Cod ținut: %1$s / %2$s",
|
||||
"neocomputers.eeprom.dataused": "Date ținute: %1$s / %2$s",
|
||||
"neocomputers.tunnel.channel": "Canal de legătură: %1$s",
|
||||
"sounds.neocomputers.computer_running": "Ventilatoare"
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"parent": "block/block",
|
||||
"textures": {
|
||||
"bottom": "neocomputers:block/generic_top",
|
||||
"top": "neocomputers:block/assembler_top",
|
||||
"side": "neocomputers:block/assembler_side",
|
||||
"particle": "neocomputers:block/generic_top"
|
||||
},
|
||||
"elements": [
|
||||
{ "from": [ 0, 0, 0 ],
|
||||
"to": [ 16, 7, 16 ],
|
||||
"faces": {
|
||||
"up": { "uv": [ 0, 0, 16, 16 ], "texture": "#top" },
|
||||
"down": { "uv": [ 0, 0, 16, 16 ], "texture": "#bottom" },
|
||||
"north": { "uv": [ 0, 0, 16, 7 ], "texture": "#side" },
|
||||
"south": { "uv": [ 0, 0, 16, 7 ], "texture": "#side" },
|
||||
"west": { "uv": [ 0, 0, 16, 7 ], "texture": "#side" },
|
||||
"east": { "uv": [ 0, 0, 16, 7 ], "texture": "#side" }
|
||||
}
|
||||
},
|
||||
{ "from": [ 2, 7, 2 ],
|
||||
"to": [ 14, 9, 14 ],
|
||||
"faces": {
|
||||
"up": { "uv": [ 2, 2, 14, 14 ], "texture": "#top" },
|
||||
"down": { "uv": [ 2, 2, 14, 14 ], "texture": "#bottom" },
|
||||
"north": { "uv": [ 2, 7, 14, 9 ], "texture": "#side" },
|
||||
"south": { "uv": [ 2, 7, 14, 9 ], "texture": "#side" },
|
||||
"west": { "uv": [ 2, 7, 14, 9 ], "texture": "#side" },
|
||||
"east": { "uv": [ 2, 7, 14, 9 ], "texture": "#side" }
|
||||
}
|
||||
},
|
||||
{ "from": [ 0, 9, 0 ],
|
||||
"to": [ 16, 16, 16 ],
|
||||
"faces": {
|
||||
"up": { "uv": [ 0, 0, 16, 16 ], "texture": "#top" },
|
||||
"down": { "uv": [ 0, 0, 16, 16 ], "texture": "#bottom" },
|
||||
"north": { "uv": [ 0, 9, 16, 16 ], "texture": "#side" },
|
||||
"south": { "uv": [ 0, 9, 16, 16 ], "texture": "#side" },
|
||||
"west": { "uv": [ 0, 9, 16, 16 ], "texture": "#side" },
|
||||
"east": { "uv": [ 0, 9, 16, 16 ], "texture": "#side" }
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"parent": "minecraft:block/block",
|
||||
"render_type": "minecraft:solid",
|
||||
"textures": {
|
||||
"cap": "neocomputers:block/cable_cap",
|
||||
"particle": "neocomputers:block/cable_cap"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [6, 6, 5],
|
||||
"to": [10, 10, 6],
|
||||
"faces": {
|
||||
"east": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"west": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"up": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"down": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"north": { "uv": [6, 6, 10, 10], "texture": "#cap"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"parent": "minecraft:block/block",
|
||||
"render_type": "minecraft:solid",
|
||||
"textures": {
|
||||
"cap": "neocomputers:block/cable_cap",
|
||||
"particle": "neocomputers:block/cable_cap"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [6, 6, 5],
|
||||
"to": [10, 10, 6],
|
||||
"faces": {
|
||||
"east": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"west": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"up": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"down": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"north": { "uv": [6,6,10,10], "texture": "#cap"},
|
||||
"south": { "uv": [0,0,4,4], "texture": "#cap"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [6, 6, 10],
|
||||
"to": [10, 10, 11],
|
||||
"faces": {
|
||||
"east": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"west": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"up": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"down": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"north": { "uv": [0,0,4,4], "texture": "#cap"},
|
||||
"south": { "uv": [6,6,10,10], "texture": "#cap"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [5, 6, 6],
|
||||
"to": [6, 10, 10],
|
||||
"faces": {
|
||||
"east": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"west": { "uv": [6,6,10,10], "texture": "#cap" },
|
||||
"up": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"down": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"north": { "uv": [0,0,4,4], "texture": "#cap"},
|
||||
"south": { "uv": [0,0,4,4], "texture": "#cap"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [10, 6, 6],
|
||||
"to": [11, 10, 10],
|
||||
"faces": {
|
||||
"east": { "uv": [6,6,10,10], "texture": "#cap" },
|
||||
"west": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"up": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"down": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"north": { "uv": [0,0,4,4], "texture": "#cap"},
|
||||
"south": { "uv": [0,0,4,4], "texture": "#cap"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [6, 5, 6],
|
||||
"to": [10, 6, 10],
|
||||
"faces": {
|
||||
"east": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"west": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"up": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"down": { "uv": [6,6,10,10], "texture": "#cap" },
|
||||
"north": { "uv": [0,0,4,4], "texture": "#cap"},
|
||||
"south": { "uv": [0,0,4,4], "texture": "#cap"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [6, 10, 6],
|
||||
"to": [10, 11, 10],
|
||||
"faces": {
|
||||
"east": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"west": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"up": { "uv": [6,6,10,10], "texture": "#cap" },
|
||||
"down": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"north": { "uv": [0,0,4,4], "texture": "#cap"},
|
||||
"south": { "uv": [0,0,4,4], "texture": "#cap"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"parent": "minecraft:block/block",
|
||||
"render_type": "minecraft:solid",
|
||||
"textures": {
|
||||
"body": "neocomputers:block/cable_body",
|
||||
"particle": "neocomputers:block/cable_cap"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [6, 6, 6],
|
||||
"to": [10, 10, 10],
|
||||
"faces": {
|
||||
"north": { "uv": [6,6,10,10], "texture": "#body", "tintindex": 0 },
|
||||
"east": { "uv": [6,6,10,10], "texture": "#body", "tintindex": 0 },
|
||||
"west": { "uv": [6,6,10,10], "texture": "#body", "tintindex": 0 },
|
||||
"south": { "uv": [6,6,10,10], "texture": "#body", "tintindex": 0 },
|
||||
"up": { "uv": [0,0, 5, 5], "texture": "#body", "tintindex": 0 },
|
||||
"down": { "uv": [0,0, 5, 5], "texture": "#body", "tintindex": 0 }
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"parent": "minecraft:block/block",
|
||||
"render_type": "minecraft:solid",
|
||||
"textures": {
|
||||
"cap": "neocomputers:block/cable_cap",
|
||||
"body": "neocomputers:block/cable_body",
|
||||
"particle": "neocomputers:block/cable_cap"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [6, 6, 10],
|
||||
"to": [10, 10, 16],
|
||||
"faces": {
|
||||
"east": { "uv": [4,4,11,11], "texture": "#body", "tintindex": 0 },
|
||||
"west": { "uv": [4,4,11,11], "texture": "#body", "tintindex": 0 },
|
||||
"up": { "uv": [4,4,11,11], "texture": "#body", "tintindex": 0 },
|
||||
"down": { "uv": [4,4,11,11], "texture": "#body", "tintindex": 0 },
|
||||
"south": { "uv": [6, 6, 10, 10], "texture": "#cap", "tintindex": 0}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"parent": "minecraft:block/block",
|
||||
"render_type": "minecraft:solid",
|
||||
"textures": {
|
||||
"cap": "neocomputers:block/cable_cap",
|
||||
"body": "neocomputers:block/cable_body",
|
||||
"particle": "neocomputers:block/cable_cap"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [6, 1, 6],
|
||||
"to": [10, 15, 10],
|
||||
"faces": {
|
||||
"east": { "uv": [0,0,5,16], "texture": "#body", "tintindex": 0 },
|
||||
"west": { "uv": [0,0,5,16], "texture": "#body", "tintindex": 0 },
|
||||
"north": { "uv": [0,0,5,16], "texture": "#body", "tintindex": 0 },
|
||||
"south": { "uv": [0,0,5,16], "texture": "#body", "tintindex": 0 },
|
||||
"up": { "uv": [0,0,5,16], "texture": "#body", "tintindex": 0 },
|
||||
"down": { "uv": [0,0,5,16], "texture": "#body", "tintindex": 0 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [4, 0, 4],
|
||||
"to": [12, 1, 12],
|
||||
"faces": {
|
||||
"east": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"west": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"up": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"down": { "uv": [4, 4, 12, 12], "texture": "#cap" },
|
||||
"north": { "uv": [0,0,4,4], "texture": "#cap"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [4, 15, 4],
|
||||
"to": [12, 16, 12],
|
||||
"faces": {
|
||||
"east": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"west": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"up": { "uv": [4, 4, 12, 12], "texture": "#cap" },
|
||||
"down": { "uv": [0,0,4,4], "texture": "#cap" },
|
||||
"north": { "uv": [0,0,4,4], "texture": "#cap"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"parent": "minecraft:block/block",
|
||||
"render_type": "minecraft:solid",
|
||||
"textures": {
|
||||
"side": "neocomputers:block/rack_side",
|
||||
"top": "neocomputers:block/generic_top"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [0, 0, 0],
|
||||
"to": [1, 16, 16],
|
||||
"faces": {
|
||||
"west": { "uv": [0, 0, 16, 16], "texture": "side", "tint_index": 0 },
|
||||
"east": { "uv": [0, 0, 16, 16], "texture": "side", "tint_index": 0 },
|
||||
"north": { "uv": [0, 0, 16, 1], "texture": "side", "tint_index": 0 },
|
||||
"south": { "uv": [0, 0, 16, 1], "texture": "side", "tint_index": 0 },
|
||||
"up": { "uv": [0, 0, 16, 1], "texture": "side", "tint_index": 0 },
|
||||
"down": { "uv": [0, 0, 16, 1], "texture": "side", "tint_index": 0 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [1, 0, 0],
|
||||
"to": [16, 16, 1],
|
||||
"faces": {
|
||||
"north": { "uv": [0, 0, 15, 16], "texture": "side", "tint_index": 0 },
|
||||
"south": { "uv": [1, 0, 16, 16], "texture": "side", "tint_index": 0 },
|
||||
"west": { "uv": [0, 0, 1, 16], "texture": "side", "tint_index": 0 },
|
||||
"east": { "uv": [0, 0, 1, 16], "texture": "side", "tint_index": 0 },
|
||||
"up": { "uv": [0, 0, 16, 1], "texture": "side", "tint_index": 0 },
|
||||
"down": { "uv": [0, 0, 16, 1], "texture": "side", "tint_index": 0 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [1, 0, 15],
|
||||
"to": [16, 16, 16],
|
||||
"faces": {
|
||||
"north": { "uv": [0, 0, 15, 16], "texture": "side", "tint_index": 0 },
|
||||
"south": { "uv": [1, 0, 16, 16], "texture": "side", "tint_index": 0 },
|
||||
"west": { "uv": [0, 0, 1, 16], "texture": "side", "tint_index": 0 },
|
||||
"east": { "uv": [0, 0, 1, 16], "texture": "side", "tint_index": 0 },
|
||||
"up": { "uv": [0, 0, 16, 1], "texture": "side", "tint_index": 0 },
|
||||
"down": { "uv": [0, 0, 16, 1], "texture": "side", "tint_index": 0 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [1, 0, 1],
|
||||
"to": [16, 2, 15],
|
||||
"faces": {
|
||||
"north": { "uv": [0, 0, 1, 16], "texture": "top", "tint_index": 0 },
|
||||
"south": { "uv": [0, 0, 1, 16], "texture": "top", "tint_index": 0 },
|
||||
"west": { "uv": [0, 0, 1, 16], "texture": "top", "tint_index": 0 },
|
||||
"east": { "uv": [0, 0, 1, 16], "texture": "top", "tint_index": 0 },
|
||||
"up": { "uv": [2, 1, 16, 15], "texture": "top", "tint_index": 0 },
|
||||
"down": { "uv": [0, 0, 1, 1], "texture": "top", "tint_index": 0 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [1, 14, 1],
|
||||
"to": [16, 16, 15],
|
||||
"faces": {
|
||||
"north": { "uv": [0, 0, 1, 16], "texture": "top", "tint_index": 0 },
|
||||
"south": { "uv": [0, 0, 1, 16], "texture": "top", "tint_index": 0 },
|
||||
"west": { "uv": [0, 0, 1, 16], "texture": "top", "tint_index": 0 },
|
||||
"east": { "uv": [1, 0, 15, 2], "texture": "top", "tint_index": 0 },
|
||||
"up": { "uv": [1, 1, 16, 15], "texture": "top", "tint_index": 0 },
|
||||
"down": { "uv": [0, 0, 1, 1], "texture": "top", "tint_index": 0 }
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"parent": "minecraft:block/cube",
|
||||
"textures": {
|
||||
"up": "neocomputers:block/relay_top",
|
||||
"down": "neocomputers:block/screen_bottom",
|
||||
"north": "neocomputers:block/relay_side",
|
||||
"south": "neocomputers:block/relay_side",
|
||||
"east": "neocomputers:block/relay_side",
|
||||
"west": "neocomputers:block/relay_side",
|
||||
"particle": "neocomputers:block/case_top"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"parent": "neocomputers:block/cable/cable_item"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"parent": "neocomputers:block/rack"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user