Compare commits

...

40 Commits

Author SHA1 Message Date
97ed29fc23 changed something. 2026-05-20 20:18:22 +02:00
1c03653fee todo slop 2026-05-19 21:58:35 +02:00
c016cebb0f accuracy slop 2026-05-19 21:51:20 +02:00
885f594ca0 dutch translation but it sucks 2026-05-19 21:46:52 +02:00
45831b780a FRENCH ew 2026-05-19 21:42:16 +02:00
6b0c4468ec FRENCH 2026-05-19 21:37:51 +02:00
d15b34939e models and shi 2026-05-08 03:47:03 +03:00
3f95944314 rack stateslop 2026-05-07 22:43:42 +02:00
21493fec04 add proper container and do some syncy stuff and save 2026-05-07 00:30:08 +02:00
42331390e7 clicky 2026-05-06 17:00:31 +02:00
cdb98bd85e all rack rendering (afaik) and basic right click logic stuff and refactors nobody asked for 2026-05-05 21:39:40 +02:00
7f58fdf55b server hit stuff 2026-05-03 19:06:37 +02:00
17bc614eb9 textures 2026-05-03 18:24:07 +02:00
b78cc44d89 Merge branch 'main' of https://gitea.codersquack.nl/NeoFlock/NeoComputers 2026-05-03 17:21:34 +02:00
4d37483057 render a singular server 2026-05-03 17:21:24 +02:00
4d84ec2ed4 todo stuff 2026-05-03 16:04:38 +03:00
5249832bd6 work on optimized networking 2026-05-02 23:28:02 +03:00
e9885940e2 robot stuff wip i hate minecraft 2026-05-02 22:01:49 +02:00
c63912c1f3 fix 2026-05-02 09:00:51 +02:00
323d213291 render robot model with blockentrenderer 2026-05-01 23:25:22 +02:00
b8968942f8 Merge branch 'main' of https://gitea.codersquack.nl/NeoFlock/NeoComputers 2026-05-01 00:27:16 +02:00
0eee9f5163 robot model 2026-05-01 00:27:09 +02:00
9fd6ea8881 transistor and some random card textures 2026-04-30 22:20:24 +02:00
c6fc9ed9e9 made relay no longer violate physics 2026-04-30 18:14:21 +03:00
9ea3727dfb cables are fully cabling now 2026-04-30 17:47:30 +03:00
21516ee923 FIXED THE EAST BUG! WE ARE SO BACK!! 2026-04-30 07:18:26 +03:00
d8e79d8719 almost fully fixing cables
fixes 1 edge-case, but the east bug is still goofed
2026-04-30 00:50:12 +03:00
5dbd0b8734 bugfix 2026-04-30 00:04:20 +03:00
710547a014 todo: stuff 2026-04-29 21:58:43 +03:00
424f77ba10 relay renderer go brrr 2026-04-29 14:20:45 +03:00
02c0c5d60c relay bugfix and graphics 2026-04-29 14:15:26 +03:00
0b33eda8a8 oopsies 2026-04-29 12:22:57 +03:00
cd909dbd80 half the todo is done 2026-04-28 23:21:34 +03:00
8fb4921e30 cases can do stuff now 2026-04-28 21:35:58 +03:00
86b3486622 fixed the worst oversight of mankind 2026-04-28 21:34:18 +03:00
9a733e0a81 fixed a fixable unfixed problem 2026-04-28 21:14:16 +03:00
740318c020 linguistics or smth idfk 2026-04-28 21:00:34 +03:00
149cfec3ed got rid of some warnings 2026-04-28 20:52:22 +03:00
4d2cb14e45 Merge remote-tracking branch 'origin/main' 2026-04-28 20:50:19 +03:00
7c27955c14 relay blockstates and capacitor magic 2026-04-28 20:50:14 +03:00
78 changed files with 1796 additions and 339 deletions

37
TODO.md
View File

@@ -1,31 +1,21 @@
# Networking
> Pretty important here
> All that is left is optimization
## Auto-connect
## Mergeable device nodes
Rework the auto-connect system of device blocks to be more stable.
Prob re-scan the network continuously
For optimization of screen grouping and cables, we should add a system that allows merging nodes
## Synchronization
## 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
Move the state logic into the node, as it was meant to be.
Note, addresses on the client are allowed to be complete bullshit at least for a bit of time.
`ComponentItem`s should no longer allow a node on the client (at least for now), it serves no
purpose currently, and also is not designed well.
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.
## Get rid of NodeBlockEntity
## Optimize power balancing
It is basically throw-away stitched together garbage.
Replace it with a new abstract class, which allows different nodes on different sides,
handles synchronizing those nodes according to their state changes.
Also implement an equivalent for LivingEntities, like drones or other addon stuff.
## Optimizations
Optimize the networking, both synchronization using smaller encodings,
and emitting messages or adding/removing nodes. The goal is to have as little of
the CPU time on the server thread taken by NC as we can.
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
@@ -38,3 +28,8 @@ Also because it is a capable engine and has a good API for architectures, and NC
## 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.

BIN
rack.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -13,8 +13,7 @@ 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.entity.render.CaseEntityRenderer;
import org.neoflock.neocomputers.entity.render.ScreenEntityRenderer;
import org.neoflock.neocomputers.entity.render.*;
import org.neoflock.neocomputers.item.Items;
import org.neoflock.neocomputers.platforms.fabric.client.model.ModelLoader;
@@ -22,8 +21,11 @@ public class NeoComputersFabricClient implements ClientModInitializer {
@Override
public void onInitializeClient() {
ModelLoadingPlugin.register(new ModelLoader());
BlockEntityRenderers.register(BlockEntities.INSTANCE.getSCREEN_ENTITY().get(), ScreenEntityRenderer::new);
BlockEntityRenderers.register(BlockEntities.INSTANCE.getSCREEN_ENTITY().get(), ScreenEntityRenderer::new); // TODO: put this in common
BlockEntityRenderers.register(BlockEntities.INSTANCE.getCASE_ENTITY().get(), CaseEntityRenderer::new);
BlockEntityRenderers.register(BlockEntities.INSTANCE.getRELAY_ENTITY().get(), RelayEntityRenderer::new);
BlockEntityRenderers.register(BlockEntities.INSTANCE.getROBOT_ENTITY().get(), RobotEntityRenderer::new);
BlockEntityRenderers.register(BlockEntities.INSTANCE.getRACK_ENTITY().get(), RackEntityRenderer::new);
ColorProviderRegistry.BLOCK.register((state, world, pos, index) -> {
if (index == 0) {

View File

@@ -1,138 +0,0 @@
//package org.neoflock.neocomputers.platforms.fabric.client.model;
//
//import net.fabricmc.fabric.api.renderer.v1.Renderer;
//import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
//import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
//import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder;
//import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
//import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
//import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
//import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
//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.*;
//import net.minecraft.core.BlockPos;
//import net.minecraft.core.Direction;
//import net.minecraft.resources.ResourceLocation;
//import net.minecraft.util.RandomSource;
//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 java.util.ArrayList;
//import java.util.Collection;
//import java.util.List;
//import java.util.function.Function;
//import java.util.function.Supplier;
//
//// this totally could have been done with datagen, why do i do this
//public class CableModel implements BakedModel, UnbakedModel, FabricBakedModel {
//// private TextureAtlasSprite sprite = Minecraft
//// TextureAtlasSprite sprite = atlas.apply(new Material(TextureAtlas.LOCATION_BLOCKS, ResourceLocation.withDefaultNamespace("block/furnace_top")));
//
// private float MIN = 6/16F;
// private float MAX = 10/16F;
//
// private BlockState state;
//
// private Mesh mesh;
// @Override
// public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction direction, RandomSource random) {
//// NeoComputers.INSTANCE.getLOGGER().info("Obtained blockstate!");
// this.state = state;
// return List.of();
// }
//
// @Override
// public boolean useAmbientOcclusion() {
// return false;
// }
//
// @Override
// public boolean isGui3d() {
// return true;
// }
//
// @Override
// public boolean usesBlockLight() {
// return true;
// }
//
// @Override
// public boolean isCustomRenderer() {
// return false;
// }
//
// @Override
// public TextureAtlasSprite getParticleIcon() {
// Function<ResourceLocation, TextureAtlasSprite> atlas = Minecraft.getInstance().getTextureAtlas(TextureAtlas.LOCATION_BLOCKS);
// return atlas.apply(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "block/teto"));
// }
//
// @Override
// public ItemTransforms getTransforms() {
// return ItemTransforms.NO_TRANSFORMS;
// }
//
// @Override
// public ItemOverrides getOverrides() {
// return ItemOverrides.EMPTY;
// }
//
// @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) {
// TextureAtlasSprite sprite = spriteGetter.apply(new Material(TextureAtlas.LOCATION_BLOCKS, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "block/teto")));
//
// Renderer renderer = RendererAccess.INSTANCE.getRenderer();
// MeshBuilder builder = renderer.meshBuilder();
// QuadEmitter emitter = builder.getEmitter();
//
// bakeCenter(emitter, sprite);
//
//
// mesh = builder.build();
// return this;
// }
//
// @Override
// public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier<RandomSource> randomSupplier, RenderContext context) {
// mesh.outputTo(context.getEmitter());
// }
//
// public void bakeCenter(QuadEmitter emitter, TextureAtlasSprite sprite) {
// for (Direction dir : Direction.values()) {
// emitter.square(dir, MIN, MIN, MAX, MAX, MIN);
// emitter.spriteBake(sprite, MutableQuadView.BAKE_LOCK_UV);
// emitter.color(-1, -1, -1, -1);
// emitter.emit();
// }
// }
// public void bakeConnection(Direction dir, QuadEmitter emitter, TextureAtlasSprite sprite) {
// int mag = dir.getStepX()+dir.getStepZ(); // i dont want to hear it
// float bottom = dir.getStepY()==0 ? 6/16F : (dir.getStepY()==1 ? 10/16F : 0F);
//
// for (Direction d : dir.getAxis().getPlane().faces) {
// emitter.square(d, (6/16F)+0.5F*mag, bottom, 6/16F)
// }
//
// }
//
//// @Override
//// public boolean isVanillaAdapter() {
//// return false; // TODO: let this be true so maybe forge and fabric can be unified
//// }
//}

View File

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

View File

@@ -1,24 +1,22 @@
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 CABLE = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "cable");
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().getNamespace().equals(NeoComputers.MODID)) NeoComputers.INSTANCE.getLOGGER().info("{} {} {}", id.id().getNamespace(), id.id().getPath(), id.id().getPath().equals(CABLE.id().getPath()));
// if (id != null && id.id().equals(CABLE)) {
////// NeoComputers.INSTANCE.getLOGGER().error("DOING CABLEEEEEEE");
// original.
// } else {
// return original;
// }
final ModelResourceLocation id = context.topLevelId();
if (id != null && id.id().equals(ROBOT)) {
return new FabricModelWrapper(new RobotModel());
}
return original;
});
}

View File

@@ -56,6 +56,9 @@ object NeoComputers {
EnvExecutor.runInEnv(Env.CLIENT) {{
ClientLifecycleEvent.CLIENT_SETUP.register {
Menus.registerScreens()
Networking.allNodes.remove()
Networking.wirelessNodes.remove()
Networking.channels.remove()
}
ClientLifecycleEvent.CLIENT_STARTED.register {
FontProvider.load(ResourceLocation.fromNamespaceAndPath(MODID, "font/unscii.hex"))
@@ -81,12 +84,6 @@ object NeoComputers {
Networking.channels.remove()
}
ClientLifecycleEvent.CLIENT_SETUP.register {
Networking.allNodes.remove()
Networking.wirelessNodes.remove()
Networking.channels.remove()
}
PlayerEvent.CLOSE_MENU.register {
player, menu ->
if(player is ServerPlayer) NodeSynchronizer.playerScreenClosed(player)

View File

@@ -35,6 +35,8 @@ object Blocks {
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() }
fun registerBlockItems() {
BLOCKS.forEach(Consumer { sup: RegistrySupplier<Block> ->

View File

@@ -152,6 +152,7 @@ class CableBlock() : DeviceBlock(Properties.of()), EntityBlock {
// 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)
@@ -164,6 +165,10 @@ class CableBlock() : DeviceBlock(Properties.of()), EntityBlock {
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

View File

@@ -1,6 +1,5 @@
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
@@ -8,7 +7,6 @@ import net.minecraft.nbt.CompoundTag
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.level.Level
@@ -42,9 +40,9 @@ open class CapacitorEntity(val capacity: Long, type: BlockEntityType<*>, pos: Bl
override fun getDeviceNodes() = listOf(deviceNode)
override fun getNodeFromSide(directionToRequester: Direction) = deviceNode
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
super.loadAdditional(compoundTag, provider)
deviceNode.energy = min(compoundTag.getLong("energy"), deviceNode.energyCapacity)
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) {

View File

@@ -34,7 +34,7 @@ import org.neoflock.neocomputers.entity.MachineEntity
import org.neoflock.neocomputers.network.NodeSynchronizer
import org.neoflock.neocomputers.sounds.Sounds
class CaseBlock() : DeviceBlock(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")!!
@@ -59,6 +59,8 @@ class CaseBlock() : DeviceBlock(Properties.of().sound(SoundType.METAL).lightLeve
return level.getBlockEntity(blockPos) as CaseBlockEntity
}
override fun isSignalSource(state: BlockState): Boolean = true
override fun getSignal(
blockState: BlockState,
blockGetter: BlockGetter,

View File

@@ -9,8 +9,11 @@ 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
@@ -18,6 +21,8 @@ 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
@@ -31,8 +36,10 @@ abstract class SingleDeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos,
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>
@@ -72,20 +79,35 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state:
open fun handleConnectionsFor(direction: Direction) {
// refuse connections on no node to reduce CPU load
val node = getNodeFromSide(direction.opposite) ?: return
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) {
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 and sync here
// 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
@@ -93,6 +115,10 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state:
if(!alreadySetup) {
initNetworking()
}
if(connectionsAreDirty) {
connectionsAreDirty = false
Direction.entries.forEach { handleConnectionsFor(it) }
}
}
open fun sendCommitsToClient(level: Level) {
@@ -159,6 +185,7 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state:
for (node in getDeviceNodes()) {
node.markChanged()
}
connectionsAreDirty = true
receivedServerState = false
}
}
@@ -186,9 +213,30 @@ abstract class DeviceBlock(properties: Properties = Properties.of()): BaseBlock(
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,

View 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
}
}

View File

@@ -10,6 +10,7 @@ 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
@@ -27,6 +28,7 @@ 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
@@ -59,7 +61,8 @@ class RelayEntity(blockPos: BlockPos, blockState: BlockState): SingleDeviceBlock
fun computeRelayCapacity(): Int = computeRelayBufferSize() + computeRelayQueueSize()
val queue = mutableListOf<Networking.ClassicPacket>()
var active = false
val justReceived = mutableListOf<Networking.ClassicPacket>()
var activityTickLeft = 0
var ticksUntilQueue = 0
override val deviceNode = object : DeviceNode() {
@@ -67,8 +70,10 @@ class RelayEntity(blockPos: BlockPos, blockState: BlockState): SingleDeviceBlock
override fun received(message: Networking.Message) {
super.received(message)
if(message.sender == this) return
if(message is Networking.ClassicPacket && message.hopCount <= 5 && queue.size < computeRelayCapacity()) {
queue.addLast(message)
if(message is Networking.ClassicPacket && message.hopCount < 5 && (queue.size + justReceived.size) < computeRelayCapacity()) {
justReceived.addLast(message)
activityTickLeft = 20
markChanged()
}
}
@@ -77,18 +82,20 @@ class RelayEntity(blockPos: BlockPos, blockState: BlockState): SingleDeviceBlock
buf.writeVarInt(computeRelayInterval())
buf.writeVarInt(computeRelayBufferSize())
buf.writeVarInt(computeRelayQueueSize())
buf.writeVarInt(queue.size)
buf.writeVarInt(queue.size + justReceived.size)
}
override fun writeFullStateCommit(buf: FriendlyByteBuf) {
super.writeFullStateCommit(buf)
buf.writeBoolean(active)
buf.writeVarInt(activityTickLeft)
}
override fun processCommit(buf: FriendlyByteBuf) {
super.processCommit(buf)
active = buf.readBoolean()
activityTickLeft = buf.readVarInt()
}
override fun getComponent() = NNComponent("relay")
}
fun sendQueuedPacket() {
@@ -97,13 +104,13 @@ class RelayEntity(blockPos: BlockPos, blockState: BlockState): SingleDeviceBlock
for(connection in deviceNode.connections) {
// skip unwanted loopback
if(connection !in pack.sender.getReachable()) continue
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)
Networking.emitMessage(connection, hopped, setOf(deviceNode))
}
}
}
@@ -111,6 +118,14 @@ class RelayEntity(blockPos: BlockPos, blockState: BlockState): SingleDeviceBlock
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()
@@ -119,9 +134,7 @@ class RelayEntity(blockPos: BlockPos, blockState: BlockState): SingleDeviceBlock
sendQueuedPacket()
}
}
val cap = computeRelayCapacity()
while(queue.size > cap) queue.removeLast()
active = queue.isNotEmpty()
deviceNode.markChanged()
}
override fun getMachineBlockPosition() = blockPos!!
@@ -167,4 +180,15 @@ class RelayBlock: DeviceBlock(Properties.of().sound(SoundType.METAL)) {
}
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)
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -94,6 +94,18 @@ object BlockEntities {
)
}
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()
)
}
fun registerPowerBlocks() {
PowerManager.registerPowerDevice(CAPACITOR_ENTITY.get())
PowerManager.registerPowerDevice(CAPACITOR2_ENTITY.get())

View File

@@ -10,6 +10,7 @@ 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
@@ -38,6 +39,9 @@ class CableEntity(pos: BlockPos, state: BlockState) : SingleDeviceBlockEntity(Bl
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
}
}
}
}

View File

@@ -25,6 +25,7 @@ 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
@@ -106,6 +107,15 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): SingleDeviceB
}
}
}
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}
@@ -170,6 +180,7 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): SingleDeviceB
}
// Server-side stuff!!
sendMachineEvent(MachinePowerEvent(this, isOn))
Networking.emitMessage(deviceNode, Networking.ClassicPacket(deviceNode, deviceNode.address.toString(), null, 1, listOf(), 0))
}
override fun start(): Boolean {
@@ -252,7 +263,7 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): SingleDeviceB
override fun getMachineMemoryTotal(): Long = stacks.mapNotNull { (it.item as? ComponentItem)?.getMemoryCapacity(it) }.sum().toLong()
override fun getMachineMemoryUsed(): Long = 0
override fun getMachineComponentsUsed(): Long = deviceNode.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()
@@ -269,11 +280,11 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): SingleDeviceB
override fun stillValid(player: Player): Boolean = !this.isRemoved
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
super.loadAdditional(compoundTag, provider)
deviceNode.energy = min(deviceNode.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) {

View 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)
}
}

View File

@@ -0,0 +1,16 @@
package org.neoflock.neocomputers.entity
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.core.BlockPos
import net.minecraft.world.level.block.entity.BlockEntity
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,) {
val body: ModelPart? = null
val name = "Diddyx" //TODO: names
init {
NeoComputers.LOGGER.info("yooo")
}
}

View File

@@ -1,4 +1,4 @@
package org.neoflock.neocomputers.entity;
package org.neoflock.neocomputers.entity
import net.minecraft.core.BlockPos
import net.minecraft.locale.Language
@@ -11,6 +11,7 @@ import org.neoflock.neocomputers.NeoComputers
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.utils.GPUChar
import org.neoflock.neocomputers.utils.TextBuffer
@@ -59,40 +60,42 @@ class ScreenEntity(blockPos: BlockPos, blockState: BlockState) :
override fun processCommit(buf: FriendlyByteBuf) {
super.processCommit(buf)
if(Networking.changeNodeAddress(this, buf.readUUID())) createscreenstuffs()
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
private var cleanRenderer: () -> Unit = { } // TODO: THIS SUCKS, FIND A BETTER WAY
override fun tickDevice(level: Level) {
super.tickDevice(level)
cleanrenderer()
createscreenstuffs()
cleanRenderer()
createScreenTexture()
}
override fun setRemoved() {
super.setRemoved()
bound = "screen/unbound" // ensure no missing texture is displayed
cleanrenderer()
cleanRenderer()
}
private fun createscreenstuffs() {
private fun createScreenTexture() {
bound = "screen/"+deviceNode.address.toString().replace("-", "_")
if (level!!.isClientSide) {
if(lastError == null) {
if(!isOn) {
textBuf.fill(0, 0, textBuf.width, textBuf.height)
}
var renderer = BufferRenderer(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, bound), textBuf)
val renderer = BufferRenderer(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, bound), textBuf)
renderer.drawBuffer()
cleanrenderer = { renderer.clean() }
cleanRenderer = { renderer.clean() }
} else {
var trueError = lastError!!
if(trueError.startsWith("@")) {
@@ -105,9 +108,9 @@ class ScreenEntity(blockPos: BlockPos, blockState: BlockState) :
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)
var renderer = BufferRenderer(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, bound), throwAwayBuf)
val renderer = BufferRenderer(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, bound), throwAwayBuf)
renderer.drawBuffer()
cleanrenderer = { renderer.clean() }
cleanRenderer = { renderer.clean() }
}
}
}

View File

@@ -5,12 +5,14 @@ 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
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider
import net.minecraft.core.Direction
import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.block.CaseBlock
import org.neoflock.neocomputers.entity.CaseBlockEntity
@@ -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.diskActivityTime > 0) 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) {

View File

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

View File

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

View File

@@ -0,0 +1,122 @@
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.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.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)
.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
poseStack.popPose()
renderTag(ent, Component.literal(ent.name), poseStack, bufferSource, packedLight, partialTick)
}
// 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.disableDepthTest()
context.font.drawInBatch(name, halfwidth.toFloat(), 2f, 0xFFFFFF, false, stack.last().pose(), source, Font.DisplayMode.SEE_THROUGH, alpha, light)
RenderSystem.enableDepthTest()
stack.popPose()
}
}

View File

@@ -12,6 +12,7 @@ import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.gui.menu.ScreenMenu
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
@@ -22,11 +23,14 @@ object Menus {
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 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)
}
}

View File

@@ -0,0 +1,192 @@
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
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)
}
}

View File

@@ -55,14 +55,10 @@ class RelaySlot(container: Container, slot: Int, x: Int, y: Int, val role: Strin
override fun getMaxStackSize() = 1
override fun getMaxStackSize(stack: ItemStack) = 1
override fun draw(graphics: GuiGraphics, relX: Int, relY: Int, mouseX: Int, mouseY: Int) {
super.draw(graphics, relX, relY, mouseX, mouseY)
override fun draw(graphics: GuiGraphics, mouseX: Int, mouseY: Int) {
super.draw(graphics, mouseX, mouseY)
if(!hasItem()) {
RenderSystem.enableBlend()
RenderSystem.setShaderTexture(0, ComponentRoles.getTextureFor(role))
RenderSystem.setShader { GameRenderer.getPositionTexShader() }
drawQuad(relX + x - 1, relY + y - 1, 18, 18, 0F, 0F, 15F, 15F)
RenderSystem.disableBlend()
drawQuad(graphics, ComponentRoles.getTextureFor(role), x-1, y-1, 18, 18, 0f, 0f, 15f, 15f)
}
}
}

View File

@@ -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
@@ -77,7 +78,7 @@ class CaseScreen : GenericContainerScreen<CaseMenu> {
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)
) {
@@ -85,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) {
@@ -105,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)
}
}

View File

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

View File

@@ -46,6 +46,8 @@ class ScreenScreen : GenericContainerScreen<ScreenMenu>{
}
}
override fun renderLabels(guiGraphics: GuiGraphics, mouseX: Int, mouseY: Int) { }
// override fun onClose() {
// super.onClose()
// renderer.

View File

@@ -84,13 +84,13 @@ 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: ComponentUser?, 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)
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)
// RenderSystem.enableBlend()
// RenderSystem.setShaderTexture(0, ComponentRoles.getTextureFor(requirement.role))
// RenderSystem.setShader { GameRenderer.getPositionTexShader() }
drawQuad(graphics, ComponentRoles.getTextureFor(requirement.role), x - 1, y - 1, 18, 18, 0F, 0F, 15F, 15F)
if (requirement.tier > 0) {
RenderSystem.setShaderTexture(
0,
@@ -99,10 +99,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()
}
}

View File

@@ -5,9 +5,12 @@ 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
@@ -17,29 +20,26 @@ import org.neoflock.neocomputers.NeoComputers
open class DynamicSlot(container: Container, slot: Int, x: Int, y: Int) : 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)
}
}

View File

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

View File

@@ -10,7 +10,7 @@ import org.neoflock.neocomputers.gui.widget.ComponentRoles
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: ComponentUser?, newRole: String) {
if(machine != null) ensureHasAddress(itemStack)

View File

@@ -46,4 +46,6 @@ object Items {
val REDIO0 = ITEMS.register("redio0") { RedstoneCard0() }
val REDIO1 = ITEMS.register("redio1") { RedstoneCard1() }
val SERVER0 = ITEMS.register("server0") { ServerItem() }
}

View 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()
}
}

View File

@@ -0,0 +1,26 @@
package org.neoflock.neocomputers.item
import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.client.renderer.MultiBufferSource
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) {
}
}

View File

@@ -55,6 +55,7 @@ object Tabs {
output.accept(ItemStack(Items.REDIO1.get()))
output.accept(ItemStack(Items.EE0.get()))
output.accept(ItemStack(Items.SERVER0.get()))
// Criminal black magic to put LuaBIOS EEPROM in the tabs
do {

View File

@@ -1,8 +1,9 @@
package org.neoflock.neocomputers.network
import net.minecraft.core.BlockPos
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
@@ -10,6 +11,9 @@ 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
@@ -146,66 +150,72 @@ open class DeviceNode(_address: UUID? = null) {
fun getReachable(): Set<DeviceNode> {
if(reachableCache == null) {
reachableCache = computeReachable();
reachableCache = computeReachable()
}
return reachableCache!!;
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();
return setOf()
}
if(reachability == Visibility.DIRECT) {
return connections.minus(this);
if(reachability == Visibility.SOME) {
return getPreferredFew()
}
if(reachability == Visibility.NETWORK) {
// absolute cinema
val working = HashSet<DeviceNode>();
val pending = mutableListOf(this);
var iterCount = 0;
val working = HashSet<DeviceNode>()
val pending = mutableListOf(this)
var iterCount = 0
while(iterCount < maxHopCount && pending.isNotEmpty()) {
iterCount++;
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.DIRECT) {
working.addAll(subnode.connections)
} else if(subnode.reachability == Visibility.SOME) {
pending.addAll(subnode.getPreferredFew())
}
}
// cannot send to itself!
working.remove(this);
return working;
working.remove(this)
return working
}
throw NotImplementedError("visibility not implemented");
throw NotImplementedError("visibility not implemented")
}
fun connectTo(other: DeviceNode) {
this.directConnectTo(other);
other.directConnectTo(this);
this.directConnectTo(other)
other.directConnectTo(this)
}
fun disconnectFrom(other: DeviceNode) {
this.directDisconnectFrom(other);
other.directDisconnectFrom(this);
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);
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);
if(other !in connections) return
connections.remove(other)
this.onDisconnect(other)
invalidateReachableCache()
}
// Network synchronization with the NodeSynchronizer
@@ -225,6 +235,8 @@ open class DeviceNode(_address: UUID? = null) {
// client-side, meant to bring state forward
open fun processCommit(buf: FriendlyByteBuf) {}
open fun getComponent(): NNComponent? = null
}
// Used by the relay
@@ -235,9 +247,10 @@ interface ConventionalNetworkDevice {
abstract class WirelessEndpoint(address: UUID?) : DeviceNode(address) {
abstract fun getRange(): Double
abstract fun getDimension(): Int
abstract fun getPosition(): BlockPos
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)
}

View File

@@ -1,6 +1,7 @@
package org.neoflock.neocomputers.network
import net.minecraft.core.BlockPos
import net.minecraft.world.level.Level
import org.neoflock.neocomputers.entity.MachineEvent
import java.util.UUID
import kotlin.math.min
@@ -27,8 +28,8 @@ 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,
}
@@ -36,7 +37,8 @@ object Networking {
abstract class Message(val sender: DeviceNode)
class ClassicPacket(sender: DeviceNode, val src: String, val dst: String, val port: Int, val data: List<Any>, val hopCount: Int) : Message(sender) {
// 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);
}
@@ -50,30 +52,26 @@ object Networking {
// node may differ from message.sender in the case of relays,
// as they might have DIRECT reachability but
fun emitMessage(deviceNode: DeviceNode, message: Message) {
deviceNode.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)
}
}

View File

@@ -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)
}
}
open fun renderCustomOverlay(graphics: GuiGraphics, mouseX: Int, mouseY: Int, blend: Float) {
guiGraphics.pose().popPose()
}
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)
}
}

View File

@@ -0,0 +1,8 @@
{
"sources": [
{
"type": "single",
"source": "neocomputers:block/relay_top"
}
]
}

View File

@@ -0,0 +1,5 @@
{
"variants": {
"": { "model": "neocomputers:block/rack"}
}
}

View File

@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "neocomputers:block/relay"
}
}
}

View File

@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "neocomputers:block/robot"
}
}
}

View File

@@ -12,6 +12,7 @@
"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)",

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

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

View File

@@ -13,6 +13,7 @@
"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)",

View File

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

View File

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

View File

@@ -0,0 +1,3 @@
{
"parent": "neocomputers:block/rack"
}

View File

@@ -0,0 +1,3 @@
{
"parent": "neocomputers:block/relay"
}

View File

@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "neocomputers:item/server0"
}
}

View File

@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "neocomputers:item/server1"
}
}

View File

@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "neocomputers:item/server2"
}
}

View File

@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "neocomputers:item/server_creative"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 934 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 271 KiB

After

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 B

After

Width:  |  Height:  |  Size: 718 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 547 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 B

After

Width:  |  Height:  |  Size: 471 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 618 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 394 B

After

Width:  |  Height:  |  Size: 623 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 417 B

After

Width:  |  Height:  |  Size: 618 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 B

After

Width:  |  Height:  |  Size: 465 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 473 B

After

Width:  |  Height:  |  Size: 579 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 472 B

After

Width:  |  Height:  |  Size: 602 B

View File

@@ -1,4 +1,4 @@
accessWidener v2 named
accessible method net/minecraft/world/level/block/entity/BlockEntityType <init> (Lnet/minecraft/world/level/block/entity/BlockEntityType$BlockEntitySupplier;Ljava/util/Set;)V
# accessible method net/minecraft/world/level/block/entity/BlockEntityType <init> (Lnet/minecraft/world/level/block/entity/BlockEntityType$BlockEntitySupplier;Ljava/util/Set;)V
accessible field net/minecraft/core/Direction$Plane faces [Lnet/minecraft/core/Direction;