Compare commits

..

62 Commits

Author SHA1 Message Date
a65cb6f261 stuff 2026-06-06 13:27:03 +02:00
d5202067d1 Add 1.21.1-neoforge, still doesn't work though 2026-06-06 13:00:36 +02:00
a362658371 just in case i fuck everything up 2026-06-06 12:56:01 +02:00
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
71899c0013 Merge branch 'main' of https://gitea.codersquack.nl/NeoFlock/NeoComputers 2026-04-28 19:38:35 +02:00
ced17282f9 new relay textures 2026-04-28 19:38:29 +02:00
a57fca82e5 Merge remote-tracking branch 'origin/main' 2026-04-28 20:32:16 +03:00
3b7e2b02b6 experimental relay bullshit 2026-04-28 20:32:11 +03:00
c968b97faf added oc relay textures 2026-04-28 19:29:42 +02:00
6ef6826483 fuck you have this 2026-04-28 17:13:31 +02:00
ba826b47a8 fuck you have this 2026-04-28 17:05:25 +02:00
02114fc02a reduced network bill by 99.99999% trust 2026-04-28 17:57:48 +03:00
9ac53a0f0e atom how did you miss another one 2026-04-28 16:18:19 +02:00
1f1a456f1d damn you atom 2026-04-28 16:17:31 +02:00
43255b1caf NodeBlockEntity is dead, long live SingleDeviceBlockEntity + cables function 2026-04-28 17:16:33 +03:00
464584877c block textures :) 2026-04-28 15:15:29 +02:00
79053b277a textures 2026-04-28 15:07:55 +02:00
80130a68e1 rip capacitors (WIP refactor)
if anyone touches this while I'm working on it, I will find you, and I will refactor you too
2026-04-27 19:04:26 +03:00
fc8a4aaa58 linguistics 2026-04-27 17:42:02 +03:00
cb380880e4 optimize cable and fix 2026-04-27 11:45:28 +02:00
26ec989a4c Merge branch 'main' of https://gitea.codersquack.nl/NeoFlock/NeoComputers 2026-04-27 11:21:17 +02:00
883833351c cable stuff 2026-04-27 11:20:22 +02:00
400a773a04 get out of here, missing texture 2026-04-27 01:30:44 +03:00
283 changed files with 3303 additions and 1038 deletions

37
TODO.md
View File

@@ -1,31 +1,21 @@
# Networking # 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. For optimization of screen grouping and cables, we should add a system that allows merging nodes
Prob re-scan the network continuously
## 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. We should implement this, as it not only makes behavior match better, but also optimizes
Note, addresses on the client are allowed to be complete bullshit at least for a bit of time. it a lot. We do need to replace the NEIGHBORS rule with implementing the SOME visibility.
`ComponentItem`s should no longer allow a node on the client (at least for now), it serves no A direct port is not needed, just taking heavy inspiration from OC.
purpose currently, and also is not designed well.
## Get rid of NodeBlockEntity ## Optimize power balancing
It is basically throw-away stitched together garbage. Use a smarter algorithm to prevent N storage nodes from iterating N^2 nodes each tick
Replace it with a new abstract class, which allows different nodes on different sides, to balance power.
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.
# Computation # Computation
> Pretty important for a computer mod > 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 ## Worker threads
Computers need worker threads for running non-synchronized code, because otherwise we're cooked 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.

View File

@@ -26,9 +26,16 @@ base {
archivesName.set("${mod.id}-$loader") archivesName.set("${mod.id}-$loader")
} }
//val foid = ["forge", "fabric", "neoforge"]
//architectury.common(foid)
//architectury.common(["forge", "fabric"])
//println(stonecutter.current.project.split('-').subList(1, 2))
//architectury.common(stonecutter.current.project.split('-').subList(1, 2))
//architectury.common(stonecutter.current.version)
architectury.common(stonecutter.tree.branches.mapNotNull { architectury.common(stonecutter.tree.branches.mapNotNull {
if (stonecutter.current.project !in it) null // println(stonecutter.current.project !in it)
else it.prop("loom.platform") if (stonecutter.current.project !in it) return null
else return it.prop("loom.platform")
}) })
repositories { repositories {
@@ -118,8 +125,8 @@ dependencies {
// } // }
// }) // })
if (minecraft=="1.21.9" || minecraft=="1.21.11") modApi("dev.architectury:architectury-neoforge:${archversion}") if (minecraft=="1.21.1" || minecraft=="1.21.9" || minecraft=="1.21.11") modApi("dev.architectury:architectury-neoforge:${archversion}")
else modApi("dev.architectury:architectury-forge:${archversion}") // NOTE: this could be wrong else modApi("dev.architectury:architectury-neoforge:${archversion}") // NOTE: this could be wrong
implementation("thedarkcolour:kotlinforforge-neoforge:6.0.0") implementation("thedarkcolour:kotlinforforge-neoforge:6.0.0")
} }

View File

@@ -27,7 +27,7 @@ stonecutter {
mc("forge", "1.20.1") mc("forge", "1.20.1")
//WARNING: neoforge uses mods.toml instead of neoforge.mods.toml for versions 1.20.4 (?) and earlier //WARNING: neoforge uses mods.toml instead of neoforge.mods.toml for versions 1.20.4 (?) and earlier
//mc("neoforge", "1.20.4", "1.21.1", "1.21.3", "1.21.4", "1.21.5", "1.21.6", "1.21.7", "1.21.8", "1.21.9", "1.21.10", "1.21.11") //mc("neoforge", "1.20.4", "1.21.1", "1.21.3", "1.21.4", "1.21.5", "1.21.6", "1.21.7", "1.21.8", "1.21.9", "1.21.10", "1.21.11")
mc("neoforge", "1.20.4", "1.21.9", "1.21.11") mc("neoforge", "1.20.4", "1.21.1", "1.21.9", "1.21.11")
} }
create(rootProject) create(rootProject)
} }

View File

@@ -1,5 +1,5 @@
//? if fabric { //? if fabric {
package org.neoflock.neocomputers.platforms.fabric; /*package org.neoflock.neocomputers.platforms.fabric;
import com.terraformersmc.modmenu.api.ConfigScreenFactory; import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi; import com.terraformersmc.modmenu.api.ModMenuApi;
@@ -10,4 +10,4 @@ public class ModMenuIntegration implements ModMenuApi {
return ConfigScreen::createConfigScreen; return ConfigScreen::createConfigScreen;
} }
} }
//?} *///?}

View File

@@ -1,5 +1,5 @@
//? if fabric { //? if fabric {
package org.neoflock.neocomputers.platforms.fabric; /*package org.neoflock.neocomputers.platforms.fabric;
import org.neoflock.neocomputers.ModPlatform; import org.neoflock.neocomputers.ModPlatform;
import net.fabricmc.api.ModInitializer; import net.fabricmc.api.ModInitializer;
@@ -24,4 +24,4 @@ public class NeoComputersFabric implements ModInitializer {
} }
} }
} }
//?} *///?}

View File

@@ -2,17 +2,36 @@ package org.neoflock.neocomputers.platforms.fabric.client;
import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin; import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin;
import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry;
import net.minecraft.client.color.item.ItemColor;
import net.minecraft.client.color.item.ItemColors;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderers; import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.level.ItemLike;
import org.neoflock.neocomputers.NeoComputers;
import org.neoflock.neocomputers.block.Blocks;
import org.neoflock.neocomputers.block.CableBlock;
import org.neoflock.neocomputers.entity.BlockEntities; import org.neoflock.neocomputers.entity.BlockEntities;
import org.neoflock.neocomputers.entity.render.CaseEntityRenderer; import org.neoflock.neocomputers.entity.render.*;
import org.neoflock.neocomputers.entity.render.ScreenEntityRenderer; import org.neoflock.neocomputers.item.Items;
import org.neoflock.neocomputers.platforms.fabric.client.model.ModelLoader; import org.neoflock.neocomputers.platforms.fabric.client.model.ModelLoader;
public class NeoComputersFabricClient implements ClientModInitializer { public class NeoComputersFabricClient implements ClientModInitializer {
@Override @Override
public void onInitializeClient() { public void onInitializeClient() {
ModelLoadingPlugin.register(new ModelLoader()); ModelLoadingPlugin.register(new ModelLoader());
BlockEntityRenderers.register(BlockEntities.INSTANCE.getSCREEN_ENTITY().get(), ScreenEntityRenderer::new);
BlockEntityRenderers.register(BlockEntities.INSTANCE.getCASE_ENTITY().get(), CaseEntityRenderer::new); ColorProviderRegistry.BLOCK.register((state, world, pos, index) -> {
if (index == 0) {
return state.getValue(CableBlock.Companion.getCOLOR()).getTextureDiffuseColor();
} else {
return 0xFFFFFF;
}
}, Blocks.INSTANCE.getCABLE_BLOCK().get());
ColorProviderRegistry.ITEM.register((stack, index)-> {
return DyeColor.LIGHT_GRAY.getTextureDiffuseColor();
}, Items.INSTANCE.getITEMS().getRegistrar().get(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "cable")));
} }
} }

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; 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.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin;
import net.minecraft.client.resources.model.ModelResourceLocation; import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import org.neoflock.neocomputers.NeoComputers; import org.neoflock.neocomputers.NeoComputers;
import org.neoflock.neocomputers.block.model.RobotModel;
public class ModelLoader implements ModelLoadingPlugin { 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 @Override
public void onInitializeModelLoader(Context pluginContext) { public void onInitializeModelLoader(Context pluginContext) {
pluginContext.modifyModelOnLoad().register((original, context) -> { pluginContext.modifyModelOnLoad().register((original, context) -> {
// final ModelResourceLocation id = context.topLevelId(); 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(ROBOT)) {
// if (id != null && id.id().equals(CABLE)) { return new FabricModelWrapper(new RobotModel());
//// NeoComputers.INSTANCE.getLOGGER().error("DOING CABLEEEEEEE"); }
// return new CableModel();
// } else {
// return original;
// }
return original; return original;
}); });
} }

View File

@@ -1,5 +1,5 @@
//? if neoforge { //? if neoforge {
/*package org.neoflock.neocomputers.platforms.neoforge; package org.neoflock.neocomputers.platforms.neoforge;
import org.neoflock.neocomputers.ConfigScreen; import org.neoflock.neocomputers.ConfigScreen;
import org.neoflock.neocomputers.ModPlatform; import org.neoflock.neocomputers.ModPlatform;
@@ -8,8 +8,8 @@ import net.neoforged.fml.ModLoadingContext;
import net.neoforged.fml.common.Mod; import net.neoforged.fml.common.Mod;
import org.neoflock.neocomputers.NeoComputers; import org.neoflock.neocomputers.NeoComputers;
//? if <1.21 { //? if <1.21 {
/^import net.neoforged.neoforge.client.ConfigScreenHandler; /*import net.neoforged.neoforge.client.ConfigScreenHandler;
^///?} else { *///?} else {
import net.neoforged.neoforge.client.gui.IConfigScreenFactory; import net.neoforged.neoforge.client.gui.IConfigScreenFactory;
//?} //?}
@Mod("neocomputers") @Mod("neocomputers")
@@ -18,11 +18,11 @@ public class NeoComputersNeoForge {
NeoComputers.INSTANCE.entrypoint(new NeoForgePlatform()); NeoComputers.INSTANCE.entrypoint(new NeoForgePlatform());
ModLoadingContext.get().registerExtensionPoint( ModLoadingContext.get().registerExtensionPoint(
//? if <1.21 { //? if <1.21 {
/^ConfigScreenHandler.ConfigScreenFactory.class, /*ConfigScreenHandler.ConfigScreenFactory.class,
() -> new ConfigScreenHandler.ConfigScreenFactory( () -> new ConfigScreenHandler.ConfigScreenFactory(
((client, parent) -> ConfigScreen.createConfigScreen(parent)) ((client, parent) -> ConfigScreen.createConfigScreen(parent))
) )
^///?} else { *///?} else {
IConfigScreenFactory.class, IConfigScreenFactory.class,
() -> (client, parent) -> ConfigScreen.createConfigScreen(parent) () -> (client, parent) -> ConfigScreen.createConfigScreen(parent)
//?} //?}
@@ -40,4 +40,4 @@ public class NeoComputersNeoForge {
} }
} }
} }
*///?} //?}

View File

@@ -1,7 +1,5 @@
package org.neoflock.neocomputers package org.neoflock.neocomputers
import com.mojang.blaze3d.vertex.DefaultVertexFormat
import com.mojang.blaze3d.vertex.VertexFormat
import dev.architectury.event.events.client.ClientLifecycleEvent import dev.architectury.event.events.client.ClientLifecycleEvent
import dev.architectury.event.events.common.LifecycleEvent import dev.architectury.event.events.common.LifecycleEvent
import dev.architectury.event.events.common.PlayerEvent import dev.architectury.event.events.common.PlayerEvent
@@ -15,24 +13,22 @@ import org.neoflock.neocomputers.gui.menu.Menus
import dev.architectury.utils.Env import dev.architectury.utils.Env
import dev.architectury.utils.EnvExecutor import dev.architectury.utils.EnvExecutor
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.RenderStateShard import net.minecraft.client.renderer.blockentity.BlockEntityRenderers
import net.minecraft.client.renderer.RenderType
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import org.neoflock.neocomputers.block.NodeBlockEntity import org.neoflock.neocomputers.block.DeviceBlockEntity
import org.neoflock.neocomputers.block.NodeSynchronizer import org.neoflock.neocomputers.entity.render.EntityRenderers
import org.neoflock.neocomputers.gui.buffer.BufferRenderer
import org.neoflock.neocomputers.gui.render.ScreenRenderer import org.neoflock.neocomputers.gui.render.ScreenRenderer
import org.neoflock.neocomputers.gui.widget.ComponentRoles import org.neoflock.neocomputers.gui.widget.ComponentRoles
import org.neoflock.neocomputers.item.GPUCard
import org.neoflock.neocomputers.item.Items import org.neoflock.neocomputers.item.Items
import org.neoflock.neocomputers.item.Tabs import org.neoflock.neocomputers.item.Tabs
import org.neoflock.neocomputers.network.DeviceNode
import org.neoflock.neocomputers.network.Networking import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.network.NodeSynchronizer
import org.neoflock.neocomputers.sounds.Sounds import org.neoflock.neocomputers.sounds.Sounds
import org.neoflock.neocomputers.utils.FontProvider import org.neoflock.neocomputers.utils.FontProvider
import org.neoflock.neocomputers.utils.GenericContainerScreen import org.neoflock.neocomputers.utils.GenericContainerScreen
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.nio.Buffer
object NeoComputers { object NeoComputers {
const val MODID: String = "neocomputers" const val MODID: String = "neocomputers"
@@ -58,10 +54,14 @@ object NeoComputers {
Tabs.TABS.register() Tabs.TABS.register()
Sounds.SOUNDS.register() Sounds.SOUNDS.register()
ComponentRoles.mapDefaultTextures() ComponentRoles.mapDefaultTextures()
// i dont know why architectury wants two lambdas but whatever // I don't know why architectury wants two lambdas but whatever
EnvExecutor.runInEnv(Env.CLIENT) {{ EnvExecutor.runInEnv(Env.CLIENT) {{
ClientLifecycleEvent.CLIENT_SETUP.register { ClientLifecycleEvent.CLIENT_SETUP.register {
Menus.registerScreens() Menus.registerScreens()
Networking.allNodes.remove()
Networking.wirelessNodes.remove()
Networking.channels.remove()
EntityRenderers.registerBlockEntityRenderers()
} }
ClientLifecycleEvent.CLIENT_STARTED.register { ClientLifecycleEvent.CLIENT_STARTED.register {
FontProvider.load(ResourceLocation.fromNamespaceAndPath(MODID, "font/unscii.hex")) FontProvider.load(ResourceLocation.fromNamespaceAndPath(MODID, "font/unscii.hex"))
@@ -87,12 +87,6 @@ object NeoComputers {
Networking.channels.remove() Networking.channels.remove()
} }
ClientLifecycleEvent.CLIENT_STARTED.register {
Networking.allNodes.remove()
Networking.wirelessNodes.remove()
Networking.channels.remove()
}
PlayerEvent.CLOSE_MENU.register { PlayerEvent.CLOSE_MENU.register {
player, menu -> player, menu ->
if(player is ServerPlayer) NodeSynchronizer.playerScreenClosed(player) if(player is ServerPlayer) NodeSynchronizer.playerScreenClosed(player)
@@ -111,19 +105,35 @@ object NeoComputers {
packet, ctx -> packet, ctx ->
val player = ctx.player val player = ctx.player
if(player is ServerPlayer) { if(player is ServerPlayer) {
NodeSynchronizer.screenMap[player]?.processScreenInteraction(player, packet.buffer) val ent = NodeSynchronizer.screenMap[player]
if(ent is DeviceNode) {
ent.processScreenInteraction(player, packet.buffer)
}
}
})
NetworkManager.registerReceiver(NetworkManager.c2s(),NodeSynchronizer.DeviceBlockStateRequest.TYPE, NodeSynchronizer.DeviceBlockStateRequest.CODEC, {
packet, ctx ->
val player = ctx.player
val level = player.level()
val dist = packet.blockPos.center.distanceTo(player.position())
if(player is ServerPlayer && dist <= NodeSynchronizer.MAX_STATE_DISTANCE_ALLOWED) {
val ent = level.getBlockEntity(packet.blockPos)
if(ent is DeviceBlockEntity) {
ent.sendStateToPlayer(player)
}
} }
}) })
} }
// we have to do this because the datagen task runs in the physical server // we have to do this because the datagen task runs in the physical server
EnvExecutor.runInEnv(Env.CLIENT) {{ EnvExecutor.runInEnv(Env.CLIENT) {{
NetworkManager.registerReceiver(NetworkManager.s2c(),NodeSynchronizer.StatePayload.TYPE, NodeSynchronizer.StatePayload.CODEC, { NetworkManager.registerReceiver(NetworkManager.s2c(),NodeSynchronizer.DeviceBlockStatePayload.TYPE, NodeSynchronizer.DeviceBlockStatePayload.CODEC, {
packet, ctx -> packet, ctx ->
val level = ctx.player.level() val level = ctx.player.level()
val ent = level.getBlockEntity(packet.blockPos) val ent = level.getBlockEntity(packet.blockPos)
if(ent is NodeBlockEntity) { if(ent is DeviceBlockEntity) {
ent.syncWithUpstream(packet.buffer) ent.processCommits(packet.buffers)
} }
}) })
@@ -143,7 +153,7 @@ object NeoComputers {
}} }}
EnvExecutor.runInEnv(Env.SERVER) {{ EnvExecutor.runInEnv(Env.SERVER) {{
// https://github.com/architectury/architectury-api/issues/518 // https://github.com/architectury/architectury-api/issues/518
NetworkManager.registerS2CPayloadType(NodeSynchronizer.StatePayload.TYPE, NodeSynchronizer.StatePayload.CODEC) NetworkManager.registerS2CPayloadType(NodeSynchronizer.DeviceBlockStatePayload.TYPE, NodeSynchronizer.DeviceBlockStatePayload.CODEC)
NetworkManager.registerS2CPayloadType(NodeSynchronizer.ScreenPayload.TYPE, NodeSynchronizer.ScreenPayload.CODEC) NetworkManager.registerS2CPayloadType(NodeSynchronizer.ScreenPayload.TYPE, NodeSynchronizer.ScreenPayload.CODEC)
NetworkManager.registerS2CPayloadType(NodeSynchronizer.BeepDataPayload.TYPE, NodeSynchronizer.BeepDataPayload.CODEC) NetworkManager.registerS2CPayloadType(NodeSynchronizer.BeepDataPayload.TYPE, NodeSynchronizer.BeepDataPayload.CODEC)
}} }}

View File

@@ -0,0 +1,16 @@
package org.neoflock.neocomputers.block
import net.minecraft.core.BlockPos
import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
import org.neoflock.neocomputers.entity.AssemblerEntity
class AssemblerBlock : BaseBlock(), EntityBlock { // TODO: component stuff
override fun newBlockEntity(
pos: BlockPos,
state: BlockState
): BlockEntity? {
return AssemblerEntity(pos, state)
}
}

View File

@@ -5,6 +5,7 @@ import dev.architectury.registry.registries.DeferredRegister
import dev.architectury.registry.registries.Registrar import dev.architectury.registry.registries.Registrar
import dev.architectury.registry.registries.RegistrarManager import dev.architectury.registry.registries.RegistrarManager
import dev.architectury.registry.registries.RegistrySupplier import dev.architectury.registry.registries.RegistrySupplier
import net.minecraft.client.renderer.RenderType
import net.minecraft.core.registries.Registries import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.resources.ResourceKey import net.minecraft.resources.ResourceKey
@@ -34,6 +35,10 @@ object Blocks {
val CASE_BLOCK: RegistrySupplier<Block> = BaseBlock.register("case") { CaseBlock() } val CASE_BLOCK: RegistrySupplier<Block> = BaseBlock.register("case") { CaseBlock() }
val REDSTONEIO_BLOCK: RegistrySupplier<Block> = BaseBlock.register("redio") { RedstoneIOBlock() } val REDSTONEIO_BLOCK: RegistrySupplier<Block> = BaseBlock.register("redio") { RedstoneIOBlock() }
val CABLE_BLOCK: RegistrySupplier<Block> = BaseBlock.register("cable") { CableBlock() } val CABLE_BLOCK: RegistrySupplier<Block> = BaseBlock.register("cable") { CableBlock() }
val RELAY_BLOCK: RegistrySupplier<Block> = BaseBlock.register("relay") { RelayBlock() }
val ROBOT_BLOCK: RegistrySupplier<Block> = BaseBlock.register("robot") { RobotBlock() }
val RACK_BLOCK: RegistrySupplier<Block> = BaseBlock.register("rack") { RackBlock() }
val ASSEMBLER_BLOCK: RegistrySupplier<Block> = BaseBlock.register("assembler") { AssemblerBlock() }
fun registerBlockItems() { fun registerBlockItems() {
BLOCKS.forEach(Consumer { sup: RegistrySupplier<Block> -> BLOCKS.forEach(Consumer { sup: RegistrySupplier<Block> ->

View File

@@ -3,6 +3,13 @@ package org.neoflock.neocomputers.block
import net.minecraft.client.renderer.blockentity.PistonHeadRenderer import net.minecraft.client.renderer.blockentity.PistonHeadRenderer
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.world.InteractionHand
import net.minecraft.world.ItemInteractionResult
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.DyeItem
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraft.world.level.BlockGetter import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block import net.minecraft.world.level.block.Block
@@ -11,13 +18,16 @@ import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.properties.BooleanProperty import net.minecraft.world.level.block.state.properties.BooleanProperty
import net.minecraft.world.level.block.state.properties.EnumProperty
import net.minecraft.world.phys.BlockHitResult
import net.minecraft.world.phys.shapes.BooleanOp import net.minecraft.world.phys.shapes.BooleanOp
import net.minecraft.world.phys.shapes.CollisionContext import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.Shapes import net.minecraft.world.phys.shapes.Shapes
import net.minecraft.world.phys.shapes.VoxelShape import net.minecraft.world.phys.shapes.VoxelShape
import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.entity.CableEntity import org.neoflock.neocomputers.entity.CableEntity
class CableBlock() : BaseBlock(Properties.of()), EntityBlock { class CableBlock() : DeviceBlock(Properties.of()), EntityBlock {
companion object { companion object {
val NORTH = BooleanProperty.create("north") val NORTH = BooleanProperty.create("north")
val EAST = BooleanProperty.create("east") val EAST = BooleanProperty.create("east")
@@ -26,26 +36,41 @@ class CableBlock() : BaseBlock(Properties.of()), EntityBlock {
val UP = BooleanProperty.create("up") val UP = BooleanProperty.create("up")
val DOWN = BooleanProperty.create("down") val DOWN = BooleanProperty.create("down")
val COLOR = EnumProperty<DyeColor>.create("color", DyeColor::class.java)
val MIN = 0.375 val MIN = 0.375
val MAX = 1-MIN val MAX = 1-MIN
// val shapeCache: Array<VoxelShape?> = arrayOfNulls(Direction.entries.size*Direction.entries.size*Direction.entries.size*Direction.entries.size*Direction.entries.size*Direction.entries.size) val shapeCache: Array<VoxelShape?> = arrayOfNulls(Direction.entries.size*Direction.entries.size*Direction.entries.size*Direction.entries.size*Direction.entries.size*Direction.entries.size)
//
// fun makeShapes() { // screw perf fun calcIdx(north: Boolean, south: Boolean, east: Boolean, west: Boolean, up: Boolean, down: Boolean): Int {
// for (north in arrayOf(false, true)) { // shut up var idx = if (down) 1 else 0
// for (east in arrayOf(false, true)) { idx += 2*(if (up) 1 else 0)
// for (west in arrayOf(false, true)) { idx += 4*(if (west) 1 else 0)
// for (south in arrayOf(false, true)) { idx += 8*(if (east) 1 else 0)
// for (up in arrayOf(false, true)) { idx += 16*(if (south) 1 else 0)
// for (down in arrayOf(false, true)) { idx += 32*(if (north) 1 else 0)
// val shape = makeShape(north, south, east, west, up, down) return idx
// } }
// }
// } fun makeShapes() {
// } NeoComputers.LOGGER.info("[CABLE] recomputing shapes")
// } for (north in arrayOf(false, true)) { // shut up
// } for (south in arrayOf(false, true)) {
// } for (east in arrayOf(false, true)) {
for (west in arrayOf(false, true)) {
for (up in arrayOf(false, true)) {
for (down in arrayOf(false, true)) {
val shape = makeShape(north, south, east, west, up, down)
val idx = calcIdx(north, south, east,west, up, down)
shapeCache[idx] = shape;
}
}
}
}
}
}
}
fun makeShape(north: Boolean, south: Boolean, east: Boolean, west: Boolean, up: Boolean, down: Boolean): VoxelShape { fun makeShape(north: Boolean, south: Boolean, east: Boolean, west: Boolean, up: Boolean, down: Boolean): VoxelShape {
var shape = Shapes.box(MIN, MIN, MIN, MAX, MAX, MAX) var shape = Shapes.box(MIN, MIN, MIN, MAX, MAX, MAX)
@@ -68,6 +93,24 @@ class CableBlock() : BaseBlock(Properties.of()), EntityBlock {
Direction.DOWN -> DOWN Direction.DOWN -> DOWN
} }
} }
fun shouldConnect(pos: BlockPos, npos: BlockPos, level: Level): Boolean {
val ent = level.getBlockEntity(npos)
val blockState = level.getBlockState(pos)
val theirState = level.getBlockState(npos)
val universal = DyeColor.LIGHT_GRAY
if(ent is CableEntity) {
val ourColor = blockState.getValue(COLOR)
val theirColor = theirState.getValue(COLOR)
if(ourColor.equals(universal)) return true
if(theirColor.equals(universal)) return true
if(ourColor.equals(theirColor)) return true
return false
}
return ent is DeviceBlockEntity
}
} }
init { init {
@@ -78,7 +121,9 @@ class CableBlock() : BaseBlock(Properties.of()), EntityBlock {
.setValue(SOUTH, false) .setValue(SOUTH, false)
.setValue(UP, false) .setValue(UP, false)
.setValue(DOWN, false) .setValue(DOWN, false)
.setValue(COLOR, DyeColor.LIGHT_GRAY)
) )
makeShapes()
} }
@@ -89,15 +134,16 @@ class CableBlock() : BaseBlock(Properties.of()), EntityBlock {
.add(SOUTH) .add(SOUTH)
.add(WEST) .add(WEST)
.add(UP) .add(UP)
.add(DOWN)) .add(DOWN)
.add(COLOR))
} }
override fun newBlockEntity(pos: BlockPos, state: BlockState): BlockEntity? { override fun newBlockEntity(pos: BlockPos, state: BlockState) = CableEntity(pos, state)
return CableEntity(pos, state)
}
override fun getShape(state: BlockState, level: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape? { override fun getShape(state: BlockState, level: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape? {
return makeShape(state.getValue(NORTH), state.getValue(SOUTH), state.getValue(EAST), state.getValue(WEST), state.getValue(UP), state.getValue(DOWN)) val idx = calcIdx(state.getValue(NORTH), state.getValue(SOUTH), state.getValue(EAST), state.getValue(WEST), state.getValue(UP), state.getValue(DOWN))
return shapeCache[idx];
// return makeShape(state.getValue(NORTH), state.getValue(SOUTH), state.getValue(EAST), state.getValue(WEST), state.getValue(UP), state.getValue(DOWN))
} }
override fun neighborChanged(state: BlockState, level: Level, pos: BlockPos, neighborBlock: Block, neighborPos: BlockPos, movedByPiston: Boolean) { override fun neighborChanged(state: BlockState, level: Level, pos: BlockPos, neighborBlock: Block, neighborPos: BlockPos, movedByPiston: Boolean) {
@@ -106,10 +152,25 @@ class CableBlock() : BaseBlock(Properties.of()), EntityBlock {
// val ent = level.getBlockEntity(blockPos.relative(dir)) // val ent = level.getBlockEntity(blockPos.relative(dir))
// level.setBlockAndUpdate(blockPos, blockState.setValue(getPropByDirection(dir), (ent is NodeBlockEntity || ent is CableEntity))) // 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 diff = pos.subtract(neighborPos)
val dir = Direction.fromDelta(diff.x, diff.y, diff.z)!!.opposite val dir = Direction.fromDelta(diff.x, diff.y, diff.z)!!.opposite
val ent = level.getBlockEntity(neighborPos) val ent = level.getBlockEntity(neighborPos)
val value = ent is NodeBlockEntity || ent is CableEntity // val value = ent is NodeBlockEntity || (ent is CableEntity && (level.getBlockState(neighborPos).getValue(COLOR).equals(state.getValue(COLOR)) || state.getValue(COLOR).equals(DyeColor.LIGHT_GRAY)))
level.setBlockAndUpdate(pos, state.setValue(getPropByDirection(dir), value)) level.setBlockAndUpdate(pos, state.setValue(getPropByDirection(dir), shouldConnect(pos, neighborPos, level)))
}
override fun useItemOn(stack: ItemStack, state: BlockState, level: Level, pos: BlockPos, player: Player, hand: InteractionHand, hitResult: BlockHitResult): ItemInteractionResult? {
// return super.useItemOn(stack, state, level, pos, player, hand, hitResult)
if (stack.item is DyeItem) {
val dyeitem = stack.item as DyeItem
level.setBlockAndUpdate(pos, state.setValue(COLOR, dyeitem.dyeColor))
val ent = level.getBlockEntity(pos)
if(ent is CableEntity) {
ent.connectionsAreDirty = true
}
return ItemInteractionResult.SUCCESS
}
return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION
} }
} }

View File

@@ -1,9 +1,10 @@
package org.neoflock.neocomputers.block package org.neoflock.neocomputers.block
import net.minecraft.client.player.LocalPlayer
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.core.HolderLookup import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.chat.OutgoingChatMessage import net.minecraft.network.chat.OutgoingChatMessage
import net.minecraft.network.chat.PlayerChatMessage import net.minecraft.network.chat.PlayerChatMessage
import net.minecraft.world.InteractionResult import net.minecraft.world.InteractionResult
@@ -18,16 +19,30 @@ import org.neoflock.neocomputers.network.DeviceNode
import org.neoflock.neocomputers.network.PowerRole import org.neoflock.neocomputers.network.PowerRole
import kotlin.math.min import kotlin.math.min
open class CapacitorEntity(val capacity: Long, type: BlockEntityType<*>, pos: BlockPos, state: BlockState) : NodeBlockEntity(type, pos, state) { open class CapacitorEntity(val capacity: Long, type: BlockEntityType<*>, pos: BlockPos, state: BlockState) : DeviceBlockEntity(type, pos, state) {
override val deviceNode = object : DeviceNode() { val deviceNode = object : DeviceNode() {
override var powerRole = PowerRole.STORAGE override var powerRole = PowerRole.STORAGE
override var energyCapacity: Long = capacity override var energyCapacity: Long = capacity
override fun writeFullStateCommit(buf: FriendlyByteBuf) {
super.writeFullStateCommit(buf)
buf.writeVarLong(energy)
}
override fun processCommit(buf: FriendlyByteBuf) {
super.processCommit(buf)
energy = buf.readVarLong()
}
} }
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) { // TODO: cache list
super.loadAdditional(compoundTag, provider) override fun getDeviceNodes() = listOf(deviceNode)
deviceNode.energy = min(compoundTag.getLong("energy"), deviceNode.energyCapacity) override fun getNodeFromSide(directionToRequester: Direction) = deviceNode
override fun loadAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
super.loadAdditional(tag, registries)
deviceNode.energy = min(tag.getLong("energy"), deviceNode.energyCapacity)
} }
override fun saveAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) { override fun saveAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
@@ -40,7 +55,7 @@ class CapacitorEntityTier1(pos: BlockPos, state: BlockState): CapacitorEntity(20
class CapacitorEntityTier2(pos: BlockPos, state: BlockState): CapacitorEntity(50000, BlockEntities.CAPACITOR2_ENTITY.get(), pos, state) class CapacitorEntityTier2(pos: BlockPos, state: BlockState): CapacitorEntity(50000, BlockEntities.CAPACITOR2_ENTITY.get(), pos, state)
class CapacitorEntityTier3(pos: BlockPos, state: BlockState): CapacitorEntity(100000, BlockEntities.CAPACITOR3_ENTITY.get(), pos, state) class CapacitorEntityTier3(pos: BlockPos, state: BlockState): CapacitorEntity(100000, BlockEntities.CAPACITOR3_ENTITY.get(), pos, state)
class CapacitorBlock(val tier: Int) : NodeBlock() { class CapacitorBlock(val tier: Int) : DeviceBlock() {
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity { override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity {
val cap: CapacitorEntity = when(tier) { val cap: CapacitorEntity = when(tier) {
1 -> CapacitorEntityTier1(blockPos, blockState) 1 -> CapacitorEntityTier1(blockPos, blockState)
@@ -48,7 +63,7 @@ class CapacitorBlock(val tier: Int) : NodeBlock() {
3 -> CapacitorEntityTier3(blockPos, blockState) 3 -> CapacitorEntityTier3(blockPos, blockState)
else -> throw UnsupportedOperationException("unsupported tier: $tier") else -> throw UnsupportedOperationException("unsupported tier: $tier")
} }
return cap.initNetworking() return cap
} }
override fun useWithoutItem( override fun useWithoutItem(
@@ -59,12 +74,11 @@ class CapacitorBlock(val tier: Int) : NodeBlock() {
blockHitResult: BlockHitResult blockHitResult: BlockHitResult
): InteractionResult { ): InteractionResult {
if(level.isClientSide()) { if(level.isClientSide()) {
val p = player as LocalPlayer
val ent = level.getBlockEntity(blockPos) val ent = level.getBlockEntity(blockPos)
if(ent is CapacitorEntity) { if(ent is CapacitorEntity) {
if(p.isCrouching) ent.deviceNode.giveEnergy(1) if(player.isCrouching) ent.deviceNode.giveEnergy(1)
val msg = PlayerChatMessage.system("energy: ${ent.deviceNode.energy} / ${ent.capacity} (${ent.computeEdges().size} edges, ${ent.deviceNode.getReachable().size} connected)") val msg = PlayerChatMessage.system("energy: ${ent.deviceNode.energy} / ${ent.capacity} (${ent.deviceNode.connections.size} connections, ${ent.deviceNode.getReachable().size} reachable)")
p.sendSystemMessage(OutgoingChatMessage.create(msg).content()) player.sendSystemMessage(OutgoingChatMessage.create(msg).content())
} }
} }
return InteractionResult.SUCCESS return InteractionResult.SUCCESS

View File

@@ -3,37 +3,25 @@ package org.neoflock.neocomputers.block;
import dev.architectury.registry.menu.MenuRegistry import dev.architectury.registry.menu.MenuRegistry
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundEvent
import net.minecraft.sounds.SoundEvents
import net.minecraft.sounds.SoundSource
import net.minecraft.util.RandomSource
import net.minecraft.world.Containers import net.minecraft.world.Containers
import net.minecraft.world.InteractionResult import net.minecraft.world.InteractionResult
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.context.BlockPlaceContext import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.BlockGetter import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.FurnaceBlock
import net.minecraft.world.level.block.SoundType import net.minecraft.world.level.block.SoundType
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.properties.BooleanProperty import net.minecraft.world.level.block.state.properties.BooleanProperty
import net.minecraft.world.level.block.state.properties.EnumProperty import net.minecraft.world.level.block.state.properties.EnumProperty
import net.minecraft.world.phys.BlockHitResult import net.minecraft.world.phys.BlockHitResult
import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.block.CombustionGeneratorBlock.Companion.COMBUSTGEN_ACTIVE
import org.neoflock.neocomputers.entity.BlockEntities import org.neoflock.neocomputers.entity.BlockEntities
import org.neoflock.neocomputers.entity.CaseBlockEntity import org.neoflock.neocomputers.entity.CaseBlockEntity
import org.neoflock.neocomputers.entity.MachineEntity import org.neoflock.neocomputers.network.NodeSynchronizer
import org.neoflock.neocomputers.sounds.Sounds
class CaseBlock() : NodeBlock(Properties.of().sound(SoundType.METAL).lightLevel(CaseBlock::getLuminance)) { // placeholder stuff class CaseBlock() : DeviceBlock(Properties.of().sound(SoundType.METAL).lightLevel(CaseBlock::getLuminance).noOcclusion()) { // placeholder stuff
companion object { companion object {
val FACING: EnumProperty<Direction> = EnumProperty.create<Direction>("facing", Direction::class.java) val FACING: EnumProperty<Direction> = EnumProperty.create<Direction>("facing", Direction::class.java)
val COMPUTER_RUNNING = BooleanProperty.create("running")!! val COMPUTER_RUNNING = BooleanProperty.create("running")!!
@@ -47,7 +35,7 @@ class CaseBlock() : NodeBlock(Properties.of().sound(SoundType.METAL).lightLevel(
registerDefaultState(stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(COMPUTER_RUNNING, false)) registerDefaultState(stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(COMPUTER_RUNNING, false))
} }
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState) = CaseBlockEntity(blockPos, blockState).initNetworking() override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState) = CaseBlockEntity(blockPos, blockState)
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block?, BlockState?>) { override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block?, BlockState?>) {
builder.add(COMPUTER_RUNNING) builder.add(COMPUTER_RUNNING)
@@ -58,17 +46,19 @@ class CaseBlock() : NodeBlock(Properties.of().sound(SoundType.METAL).lightLevel(
return level.getBlockEntity(blockPos) as CaseBlockEntity return level.getBlockEntity(blockPos) as CaseBlockEntity
} }
override fun isSignalSource(state: BlockState): Boolean = true
override fun getSignal( override fun getSignal(
blockState: BlockState, blockState: BlockState,
blockGetter: BlockGetter, blockGetter: BlockGetter,
blockPos: BlockPos, blockPos: BlockPos,
direction: Direction direction: Direction
): Int { ): Int {
return getMachine(blockGetter, blockPos).redstoneOut[dirToIdx(direction.opposite)] return getMachine(blockGetter, blockPos).redstoneOut[direction.opposite.ordinal]
} }
override fun onPlace( override fun onPlace(
blockState: BlockState, state: BlockState,
level: Level, level: Level,
blockPos: BlockPos, blockPos: BlockPos,
blockState2: BlockState, blockState2: BlockState,
@@ -78,7 +68,7 @@ class CaseBlock() : NodeBlock(Properties.of().sound(SoundType.METAL).lightLevel(
level.updateNeighborsAt(blockPos, this) level.updateNeighborsAt(blockPos, this)
getMachine(level, blockPos).refetchAllRedstone() getMachine(level, blockPos).refetchAllRedstone()
} }
super.onPlace(blockState, level, blockPos, blockState2, bl) super.onPlace(state, level, blockPos, blockState2, bl)
} }
override fun getStateForPlacement(context: BlockPlaceContext): BlockState? { override fun getStateForPlacement(context: BlockPlaceContext): BlockState? {
@@ -115,7 +105,7 @@ class CaseBlock() : NodeBlock(Properties.of().sound(SoundType.METAL).lightLevel(
} else { } else {
// Open menu // Open menu
MenuRegistry.openMenu(player as ServerPlayer, ent) MenuRegistry.openMenu(player as ServerPlayer, ent)
NodeSynchronizer.registerPlayerScreen(player, ent) NodeSynchronizer.registerPlayerScreen(player, ent.deviceNode)
} }
} }
return InteractionResult.SUCCESS return InteractionResult.SUCCESS

View File

@@ -0,0 +1,254 @@
package org.neoflock.neocomputers.block
import dev.architectury.networking.NetworkManager
import io.netty.buffer.Unpooled
import net.minecraft.client.Minecraft
import net.minecraft.client.multiplayer.ClientLevel
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.InteractionResult
import net.minecraft.world.entity.player.Player
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntityTicker
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.BlockHitResult
import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.network.DeviceNode
import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.network.NodeSynchronizer
abstract class SingleDeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: BlockState): DeviceBlockEntity(type, pos, state) {
abstract val deviceNode: DeviceNode
override fun getDeviceNodes() = listOf(deviceNode)
override fun getNodeFromSide(directionToRequester: Direction): DeviceNode? = deviceNode
}
abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: BlockState): BlockEntity(type, pos, state) {
val connetionsInDir = MutableList<DeviceNode?>(Direction.entries.size) { null }
val nodesInDir = MutableList<DeviceNode?>(Direction.entries.size) { null }
var alreadySetup = false
var receivedServerState = false
var connectionsAreDirty = true
abstract fun getDeviceNodes(): List<DeviceNode>
// Gets, if applicable, the node from a direction.
// The direction is from this block entity to the original requester,
// so it is Direction.UP if we asked from the one on the top side.
abstract fun getNodeFromSide(directionToRequester: Direction): DeviceNode?
open fun processCommits(commits: Iterable<FriendlyByteBuf>) {
receivedServerState = true
val devs = getDeviceNodes()
for (buf in commits) {
val idx = buf.readVarInt()
if(idx >= 0 && idx < devs.size) {
devs[idx].processCommit(buf)
}
}
}
open fun initNetworking(): DeviceBlockEntity {
if(hasLevel()) {
alreadySetup = true
Networking.addNodes(getDeviceNodes())
Direction.entries.forEach { handleConnectionsFor(it) }
}
return this
}
// Cables are 1 node
open fun getCurrentlyConnectedNodeIn(direction: Direction): DeviceNode? {
val ent = level?.getBlockEntity(blockPos.relative(direction))
if(ent is DeviceBlockEntity) {
return ent.getNodeFromSide(direction.opposite)
}
return null
}
open fun handleConnectionsFor(direction: Direction) {
// refuse connections on no node to reduce CPU load
val node = getNodeFromSide(direction)
val oldNode = nodesInDir[direction.ordinal]
nodesInDir[direction.ordinal] = node
val old = connetionsInDir[direction.ordinal]
val now = getCurrentlyConnectedNodeIn(direction)
if(node == null) {
if(old != null) oldNode?.disconnectFrom(old)
if(now != null) oldNode?.disconnectFrom(now)
return
}
if(oldNode != null && oldNode.address != node.address) {
if(old != null) oldNode.disconnectFrom(old)
if(now != null) oldNode.disconnectFrom(now)
}
if(old?.address != now?.address || oldNode == null) {
if(old != null) node.disconnectFrom(old)
if(now != null) node.connectTo(now)
}
// bullshit hack
if(now != null) {
node.connectTo(now)
}
connetionsInDir[direction.ordinal] = now
}
// TODO: optimize this sometime before our test computers melt
open fun tickDevice(level: Level) {
// Handles device connections
// we do it like this because stinky MC will call stuff before world is fully setup
// and then not notify us of neighbour changes
// this is because MC is considered shit
if(!alreadySetup) {
initNetworking()
}
if(connectionsAreDirty) {
connectionsAreDirty = false
Direction.entries.forEach { handleConnectionsFor(it) }
}
}
open fun sendCommitsToClient(level: Level) {
if(level !is ServerLevel) return
// synchronization!
val commits = mutableListOf<FriendlyByteBuf>()
val devs = getDeviceNodes()
for((i, dev) in devs.withIndex()) {
if(dev.outOfSync) {
dev.outOfSync = false
val buf = FriendlyByteBuf(Unpooled.buffer())
buf.writeVarInt(i)
dev.writeFullStateCommit(buf)
commits.addLast(buf)
}
}
if(commits.isNotEmpty()) {
level.players().forEach {
val dist = it.position().distanceTo(blockPos.center)
if(dist < 100) NetworkManager.sendToPlayer(it, NodeSynchronizer.DeviceBlockStatePayload(blockPos, commits))
}
}
}
open fun sendStateToPlayer(player: ServerPlayer) {
val world = level!!
if(world !is ServerLevel) return
// synchronization!
val commits = mutableListOf<FriendlyByteBuf>()
val devs = getDeviceNodes()
for((i, dev) in devs.withIndex()) {
val buf = FriendlyByteBuf(Unpooled.buffer())
buf.writeVarInt(i)
dev.writeFullStateCommit(buf)
commits.addLast(buf)
}
if(commits.isNotEmpty()) {
world.players().forEach {
val dist = it.position().distanceTo(blockPos.center)
if(dist <= NodeSynchronizer.MAX_STATE_DISTANCE_ALLOWED) NetworkManager.sendToPlayer(it, NodeSynchronizer.DeviceBlockStatePayload(blockPos, commits))
}
}
}
open fun requestServerState() {
// no point
if(receivedServerState) return
// we're the server bro :sob:
if(level?.isClientSide != true) return
val player = Minecraft.getInstance().player ?: return
// we assume the player will just reject, so we save on bandwidth
if(player.position().distanceTo(blockPos.center) > NodeSynchronizer.MAX_STATE_DISTANCE_ALLOWED) return
NetworkManager.sendToServer(NodeSynchronizer.DeviceBlockStateRequest(blockPos))
}
override fun setRemoved() {
super.setRemoved()
alreadySetup = false
Networking.removeNodes(getDeviceNodes())
}
override fun loadAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
super.loadAdditional(tag, registries)
for (node in getDeviceNodes()) {
node.markChanged()
}
connectionsAreDirty = true
receivedServerState = false
}
}
abstract class DeviceBlock(properties: Properties = Properties.of()): BaseBlock(properties), EntityBlock {
override fun <T : BlockEntity?> getTicker(
level: Level,
state: BlockState,
blockEntityType: BlockEntityType<T?>
): BlockEntityTicker<T> {
return object : BlockEntityTicker<T> {
override fun tick(level: Level, blockPos: BlockPos, blockState: BlockState, blockEntity: T & Any) {
if(blockEntity !is DeviceBlockEntity) return
blockEntity.tickDevice(level)
blockEntity.sendCommitsToClient(level)
if(level.isClientSide) {
blockEntity.requestServerState()
}
}
}
}
override fun onPlace(state: BlockState, level: Level, pos: BlockPos, oldState: BlockState, movedByPiston: Boolean) {
super.onPlace(state, level, pos, oldState, movedByPiston)
val ent = level.getBlockEntity(pos)
if(ent is DeviceBlockEntity) {
ent.initNetworking()
ent.connectionsAreDirty = true
}
}
override fun useWithoutItem(
state: BlockState,
level: Level,
pos: BlockPos,
player: Player,
hitResult: BlockHitResult
): InteractionResult? {
val ent = level.getBlockEntity(pos)
if(ent is DeviceBlockEntity && player is ServerPlayer) {
val dir = hitResult.direction
val node = ent.getNodeFromSide(dir)
if(node == null) {
player.sendSystemMessage(Component.literal("no node for dir $dir"))
} else {
player.sendSystemMessage(Component.literal("dir: $dir, address: ${node.address}, connections: ${node.connections.joinToString(", ")}"))
}
}
return super.useWithoutItem(state, level, pos, player, hitResult)
}
override fun neighborChanged(
state: BlockState,
level: Level,
pos: BlockPos,
neighborBlock: Block,
neighborPos: BlockPos,
movedByPiston: Boolean
) {
super.neighborChanged(state, level, pos, neighborBlock, neighborPos, movedByPiston)
val ent = level.getBlockEntity(pos)
if(ent is DeviceBlockEntity) {
ent.handleConnectionsFor(Direction.getNearest(neighborPos.center.subtract(pos.center)))
}
}
}

View File

@@ -23,13 +23,14 @@ import net.minecraft.world.phys.BlockHitResult
import org.neoflock.neocomputers.entity.BlockEntities import org.neoflock.neocomputers.entity.BlockEntities
import org.neoflock.neocomputers.entity.SolarGeneratorBlockEntity import org.neoflock.neocomputers.entity.SolarGeneratorBlockEntity
import org.neoflock.neocomputers.entity.CombustionGeneratorBlockEntity import org.neoflock.neocomputers.entity.CombustionGeneratorBlockEntity
import org.neoflock.neocomputers.network.NodeSynchronizer
class SolarGeneratorBlock : NodeBlock(), EntityBlock { class SolarGeneratorBlock : DeviceBlock(), EntityBlock {
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity = SolarGeneratorBlockEntity(blockPos, blockState).initNetworking() override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity = SolarGeneratorBlockEntity(blockPos, blockState)
} }
// TODO: make it glow when burning // TODO: make it glow when burning
class CombustionGeneratorBlock : NodeBlock, EntityBlock { class CombustionGeneratorBlock : DeviceBlock, EntityBlock {
companion object { companion object {
val COMBUSTGEN_ACTIVE = BooleanProperty.create("active") val COMBUSTGEN_ACTIVE = BooleanProperty.create("active")
@@ -42,7 +43,7 @@ class CombustionGeneratorBlock : NodeBlock, EntityBlock {
registerDefaultState(defaultBlockState().setValue(COMBUSTGEN_ACTIVE, false)) registerDefaultState(defaultBlockState().setValue(COMBUSTGEN_ACTIVE, false))
} }
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity = CombustionGeneratorBlockEntity(blockPos, blockState).initNetworking() override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity = CombustionGeneratorBlockEntity(blockPos, blockState)
override fun useWithoutItem( override fun useWithoutItem(
blockState: BlockState, blockState: BlockState,
@@ -54,7 +55,7 @@ class CombustionGeneratorBlock : NodeBlock, EntityBlock {
if(!level.isClientSide()) { if(!level.isClientSide()) {
val sp = player as ServerPlayer val sp = player as ServerPlayer
val ent = level.getBlockEntity(blockPos, BlockEntities.COMBUSTGEN_ENTITY.get()).get() val ent = level.getBlockEntity(blockPos, BlockEntities.COMBUSTGEN_ENTITY.get()).get()
NodeSynchronizer.registerPlayerScreen(sp, ent) NodeSynchronizer.registerPlayerScreen(sp, ent.deviceNode)
MenuRegistry.openMenu(sp, ent) MenuRegistry.openMenu(sp, ent)
} }
return InteractionResult.SUCCESS return InteractionResult.SUCCESS

View File

@@ -1,304 +0,0 @@
package org.neoflock.neocomputers.block
import dev.architectury.networking.NetworkManager
import io.netty.buffer.Unpooled
import net.minecraft.core.BlockPos
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.network.codec.StreamCodec
import net.minecraft.network.protocol.common.custom.CustomPacketPayload
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntityTicker
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.network.DeviceNode
import java.time.Duration
object NodeSynchronizer {
class StatePayload(var blockPos: BlockPos, var buffer: FriendlyByteBuf): CustomPacketPayload {
companion object {
val NODE_SYNC_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "node_sync")
val TYPE = CustomPacketPayload.Type<StatePayload>(NODE_SYNC_ID)
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, StatePayload> {
override fun decode(buf: RegistryFriendlyByteBuf): StatePayload {
val blockPos = buf.readBlockPos()
val buffer = FriendlyByteBuf(buf.copy(buf.readerIndex(), buf.readableBytes()))
return StatePayload(blockPos, buffer)
}
override fun encode(buf: RegistryFriendlyByteBuf, payload: StatePayload) {
buf.writeBlockPos(payload.blockPos)
buf.writeBytes(payload.buffer)
}
}
}
override fun type() = TYPE
}
class ScreenPayload(var entityTypeWireID: String, var buffer: FriendlyByteBuf): CustomPacketPayload {
companion object {
val SCREEN_SYNC_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "screen_sync")
val TYPE = CustomPacketPayload.Type<ScreenPayload>(SCREEN_SYNC_ID)
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, ScreenPayload> {
override fun decode(buf: RegistryFriendlyByteBuf): ScreenPayload {
val id = buf.readByteArray().decodeToString()
val buffer = FriendlyByteBuf(buf.copy(buf.readerIndex(), buf.readableBytes()))
return ScreenPayload(id, buffer)
}
override fun encode(buf: RegistryFriendlyByteBuf, payload: ScreenPayload) {
buf.writeByteArray(payload.entityTypeWireID.encodeToByteArray())
buf.writeBytes(payload.buffer)
}
}
}
override fun type() = TYPE
}
class ScreenDataPayload(var entityTypeWireID: String, var buffer: FriendlyByteBuf): CustomPacketPayload {
companion object {
val SCREEN_DATA_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "screen_data")
val TYPE = CustomPacketPayload.Type<ScreenDataPayload>(SCREEN_DATA_ID)
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, ScreenDataPayload> {
override fun decode(buf: RegistryFriendlyByteBuf): ScreenDataPayload {
val id = buf.readByteArray().decodeToString()
val buffer = FriendlyByteBuf(buf.copy(buf.readerIndex(), buf.readableBytes()))
return ScreenDataPayload(id, buffer)
}
override fun encode(buf: RegistryFriendlyByteBuf, payload: ScreenDataPayload) {
buf.writeByteArray(payload.entityTypeWireID.encodeToByteArray())
buf.writeBytes(payload.buffer)
}
}
}
override fun type() = TYPE
}
class BeepDataPayload(val pos: BlockPos, val pattern: String, val freq: Int, val duration: Duration, val volume: Double): CustomPacketPayload {
companion object {
val BEEP_DATA_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "beep_data")
val TYPE = CustomPacketPayload.Type<BeepDataPayload>(BEEP_DATA_ID)
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, BeepDataPayload> {
override fun decode(buf: RegistryFriendlyByteBuf): BeepDataPayload {
val pos = buf.readBlockPos()
val pattern = buf.readUtf()
val freq = buf.readVarInt()
val duration = buf.readVarLong()
val volume = buf.readDouble()
return BeepDataPayload(pos, pattern, freq, Duration.ofMillis(duration), volume)
}
override fun encode(buf: RegistryFriendlyByteBuf, payload: BeepDataPayload) {
buf.writeBlockPos(payload.pos)
buf.writeUtf(payload.pattern)
buf.writeVarInt(payload.freq)
buf.writeVarLong(payload.duration.toMillis())
buf.writeDouble(payload.volume)
}
}
}
override fun type() = TYPE
}
val screenMap = HashMap<ServerPlayer, NodeBlockEntity>()
fun playerScreenClosed(player: ServerPlayer) {
screenMap.remove(player)
}
fun nodeTypeToWireID(nodeType: BlockEntityType<*>): String = nodeType.javaClass.canonicalName
fun registerPlayerScreen(player: ServerPlayer, entity: NodeBlockEntity) {
screenMap[player] = entity
}
fun syncScreens() {
for((player, ent) in screenMap) {
val buf = FriendlyByteBuf(Unpooled.buffer())
ent.encodeScreenData(player, buf)
NetworkManager.sendToPlayer(player, ScreenPayload(nodeTypeToWireID(ent.type), buf))
}
}
fun sendScreenInteraction(friendlyByteBuf: FriendlyByteBuf) {
NetworkManager.sendToServer(ScreenDataPayload("", friendlyByteBuf))
}
fun emitBeep(level: Level, beepDataPayload: BeepDataPayload) {
if(level is ServerLevel) {
level.players().forEach {
NetworkManager.sendToPlayer(it, beepDataPayload)
}
}
}
}
abstract class NodeBlockEntity(blockEntityType: BlockEntityType<*>, blockPos: BlockPos, blockState: BlockState) : BlockEntity(blockEntityType, blockPos, blockState) {
abstract val deviceNode: DeviceNode
fun initNetworking(): NodeBlockEntity {
Networking.addNode(deviceNode)
invalidateNodeState()
return this
}
// runs on the server, meant to encode state to send to all players
open fun encodeDownstreamData(packet: FriendlyByteBuf) {
packet.writeUUID(deviceNode.address)
packet.writeLong(deviceNode.energy)
packet.writeLong(deviceNode.energyCapacity)
packet.writeEnum(deviceNode.reachability)
packet.writeEnum(deviceNode.powerRole)
}
// runs on the client, meant to decode server state packets to synchronize client state
open fun syncWithUpstream(packet: FriendlyByteBuf) {
Networking.changeNodeAddress(deviceNode, packet.readUUID())
deviceNode.energy = packet.readLong()
deviceNode.energyCapacity = packet.readLong()
deviceNode.reachability = packet.readEnum(deviceNode.reachability.javaClass)
deviceNode.powerRole = packet.readEnum(deviceNode.powerRole.javaClass)
}
// Encodes data meant for the associated screen of a player
open fun encodeScreenData(player: ServerPlayer, packet: FriendlyByteBuf) {}
open fun processScreenInteraction(player: ServerPlayer, packet: FriendlyByteBuf) {}
private var stateIsDirty = true
open fun getNeighbourEntities(): List<BlockEntity> {
val subpos = listOf(
blockPos.offset(0, 0, 1),
blockPos.offset(0, 0, -1),
blockPos.offset(0, 1, 0),
blockPos.offset(0, -1, 0),
blockPos.offset(1, 0, 0),
blockPos.offset(-1, 0, 0),
)
return subpos.mapNotNull { pos -> level?.getBlockEntity(pos) }
}
open fun computeEdges(): Set<NodeBlockEntity> {
val s = mutableSetOf<NodeBlockEntity>()
val neighbours = getNeighbourEntities()
for(neighbour in neighbours) {
if(neighbour is NodeBlockEntity) s.add(neighbour);
// TODO: handle cable entities
}
s.remove(this)
return s
}
open fun invalidateNodeState() {
stateIsDirty = true
}
open fun needsSynchronization() = stateIsDirty
open fun tickNode(level: Level) {
if(!level.isClientSide) {
val l = level as ServerLevel
val packetBuf = FriendlyByteBuf(Unpooled.buffer())
encodeDownstreamData(packetBuf)
l.players().forEach {
if(it.level().isLoaded(blockPos)) NetworkManager.sendToPlayer(it, NodeSynchronizer.StatePayload(blockPos, packetBuf))
}
}
if(!stateIsDirty) return
stateIsDirty = false
computeEdges().forEach {
deviceNode.connectTo(it.deviceNode)
}
}
override fun setChanged() {
invalidateNodeState()
computeEdges().forEach { it.invalidateNodeState() }
super.setChanged()
}
override fun setRemoved() {
super.setRemoved()
Networking.removeNode(deviceNode)
}
override fun clearRemoved() {
super.clearRemoved()
initNetworking()
}
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
super.loadAdditional(compoundTag, provider)
invalidateNodeState()
computeEdges().forEach { it.invalidateNodeState() }
}
}
abstract class NodeBlock(properties: Properties = Properties.of()): BaseBlock(properties), EntityBlock {
override fun <T : BlockEntity> getTicker(
level: Level,
blockState: BlockState,
blockEntityType: BlockEntityType<T>
): BlockEntityTicker<T>? {
return object : BlockEntityTicker<T> {
override fun tick(level: Level, blockPos: BlockPos, blockState: BlockState, blockEntity: T) {
if(blockEntity !is NodeBlockEntity) return
if(Networking.getNode(blockEntity.deviceNode.address) == null) blockEntity.initNetworking()
blockEntity.tickNode(level)
}
}
}
override fun onPlace(
blockState: BlockState,
level: Level,
blockPos: BlockPos,
blockState2: BlockState,
bl: Boolean
) {
super.onPlace(blockState, level, blockPos, blockState2, bl)
if(!level.isClientSide) {
val ent = level.getBlockEntity(blockPos)
if(ent is NodeBlockEntity) {
ent.invalidateNodeState()
ent.computeEdges().forEach { it.invalidateNodeState() }
}
level.updateNeighborsAt(blockPos, this)
}
}
override fun neighborChanged(
blockState: BlockState,
level: Level,
blockPos: BlockPos,
block: Block,
blockPos2: BlockPos,
bl: Boolean
) {
super.neighborChanged(blockState, level, blockPos, block, blockPos2, bl)
if(!level.isClientSide) {
val ent = level.getBlockEntity(blockPos)
if(ent is NodeBlockEntity) {
ent.invalidateNodeState()
}
}
}
}

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

@@ -15,9 +15,7 @@ import org.neoflock.neocomputers.entity.BlockEntities
import org.neoflock.neocomputers.network.Networking import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.network.DeviceNode import org.neoflock.neocomputers.network.DeviceNode
fun dirToIdx(direction: Direction) = Direction.entries.indexOf(direction) class RedstoneIOEntity(blockPos: BlockPos, blockState: BlockState): SingleDeviceBlockEntity(BlockEntities.REDSTONEIO_ENTITY.get(), blockPos, blockState) {
class RedstoneIOEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEntity(BlockEntities.REDSTONEIO_ENTITY.get(), blockPos, blockState) {
val redstoneIn = Array<Int>(Direction.entries.size) {0} val redstoneIn = Array<Int>(Direction.entries.size) {0}
val redstoneOut = Array<Int>(Direction.entries.size) {0} val redstoneOut = Array<Int>(Direction.entries.size) {0}
@@ -29,7 +27,7 @@ class RedstoneIOEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnt
fun refetch(dir: Direction) { fun refetch(dir: Direction) {
val src = blockPos.offset(dir.stepX, dir.stepY, dir.stepZ) val src = blockPos.offset(dir.stepX, dir.stepY, dir.stepZ)
val cur = level?.getSignal(src, dir) ?: 0 val cur = level?.getSignal(src, dir) ?: 0
val idx = dirToIdx(dir) val idx = dir.ordinal
if(redstoneIn[idx] != cur) { if(redstoneIn[idx] != cur) {
onRedstoneSignalChanged(dir, redstoneIn[idx], cur) onRedstoneSignalChanged(dir, redstoneIn[idx], cur)
} }
@@ -41,12 +39,12 @@ class RedstoneIOEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnt
} }
fun onRedstoneSignalChanged(dir: Direction, oldValue: Int, newValue: Int) { fun onRedstoneSignalChanged(dir: Direction, oldValue: Int, newValue: Int) {
Networking.emitMessage(deviceNode, Networking.ComputerUncheckedSignal(deviceNode, "redstone_changed", arrayOf(deviceNode.address.toString(), dirToIdx(dir), oldValue, newValue))) Networking.emitMessage(deviceNode, Networking.ComputerUncheckedSignal(deviceNode, "redstone_changed", arrayOf(deviceNode.address.toString(), dir.ordinal, oldValue, newValue)))
NeoComputers.LOGGER.info("redstone in direction ${dir.name} changed from $oldValue to $newValue") NeoComputers.LOGGER.info("redstone in direction ${dir.name} changed from $oldValue to $newValue")
} }
} }
class RedstoneIOBlock(): NodeBlock(Properties.of().isRedstoneConductor { state, getter, pos -> true }) { class RedstoneIOBlock(): DeviceBlock(Properties.of().isRedstoneConductor { state, getter, pos -> true }) {
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity = RedstoneIOEntity(blockPos, blockState) override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity = RedstoneIOEntity(blockPos, blockState)
fun getRedstoneIO(level: BlockGetter, blockPos: BlockPos): RedstoneIOEntity? { fun getRedstoneIO(level: BlockGetter, blockPos: BlockPos): RedstoneIOEntity? {
@@ -67,7 +65,7 @@ class RedstoneIOBlock(): NodeBlock(Properties.of().isRedstoneConductor { state,
): Int { ): Int {
val redstoneIO = getRedstoneIO(blockGetter, blockPos) val redstoneIO = getRedstoneIO(blockGetter, blockPos)
if(redstoneIO != null) { if(redstoneIO != null) {
return redstoneIO.redstoneOut[dirToIdx(direction.opposite)] return redstoneIO.redstoneOut[direction.opposite.ordinal]
} }
return super.getSignal(blockState, blockGetter, blockPos, direction) return super.getSignal(blockState, blockGetter, blockPos, direction)
} }
@@ -125,7 +123,7 @@ class RedstoneIOBlock(): NodeBlock(Properties.of().isRedstoneConductor { state,
val redio = getRedstoneIO(level, blockPos) val redio = getRedstoneIO(level, blockPos)
val dir = blockHitResult.direction val dir = blockHitResult.direction
if (redio != null) { if (redio != null) {
val idx = dirToIdx(dir) val idx = dir.ordinal
redio.redstoneOut[idx]++ redio.redstoneOut[idx]++
redio.redstoneOut[idx] %= 16 redio.redstoneOut[idx] %= 16
NeoComputers.LOGGER.info("outputting redstone level ${redio.redstoneOut[idx]} on ${dir.name}") NeoComputers.LOGGER.info("outputting redstone level ${redio.redstoneOut[idx]} on ${dir.name}")

View File

@@ -0,0 +1,194 @@
package org.neoflock.neocomputers.block
import dev.architectury.registry.menu.MenuRegistry
import net.minecraft.core.BlockPos
import net.minecraft.core.HolderLookup
import net.minecraft.core.NonNullList
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.ContainerHelper
import net.minecraft.world.Containers
import net.minecraft.world.InteractionResult
import net.minecraft.world.MenuProvider
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.SoundType
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.BlockHitResult
import org.neoflock.neocomputers.entity.BlockEntities
import org.neoflock.neocomputers.entity.ComponentUser
import org.neoflock.neocomputers.gui.menu.RelayMenu
import org.neoflock.neocomputers.item.RelayUpgrade
import org.neoflock.neocomputers.network.ConventionalNetworkDevice
import org.neoflock.neocomputers.network.DeviceNode
import org.neoflock.neocomputers.network.NNComponent
import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.network.NodeSynchronizer
import org.neoflock.neocomputers.utils.GenericContainer
class RelayEntity(blockPos: BlockPos, blockState: BlockState): SingleDeviceBlockEntity(BlockEntities.RELAY_ENTITY.get(), blockPos, blockState),
GenericContainer, ComponentUser, MenuProvider {
companion object RelaySlots {
val CARD = 0
val CPU = 1
val MEM = 2
val STORAGE = 3
val SLOT_COUNT = 4
}
val slots = NonNullList.withSize(SLOT_COUNT, ItemStack.EMPTY)!!
override fun getItems(): NonNullList<ItemStack> = slots
override fun stillValid(player: Player): Boolean = true
fun getUpgrade(slot: Int) = slots[slot].item as? RelayUpgrade
fun computeRelayInterval(): Int = getUpgrade(CPU)?.getRelayInterval(slots[CPU]) ?: 5
fun computeRelayBufferSize(): Int = getUpgrade(MEM)?.getRelayBufferSize(slots[MEM]) ?: 1
fun computeRelayQueueSize(): Int = getUpgrade(STORAGE)?.getRelayQueueSize(slots[STORAGE]) ?: 20
fun getRelaySender(): DeviceNode? = getUpgrade(CARD)?.getComponentNode(slots[CARD])
fun computeRelayCapacity(): Int = computeRelayBufferSize() + computeRelayQueueSize()
val queue = mutableListOf<Networking.ClassicPacket>()
val justReceived = mutableListOf<Networking.ClassicPacket>()
var activityTickLeft = 0
var ticksUntilQueue = 0
override val deviceNode = object : DeviceNode() {
override var reachability = Networking.Visibility.NONE
override fun received(message: Networking.Message) {
super.received(message)
if(message.sender == this) return
if(message is Networking.ClassicPacket && message.hopCount < 5 && (queue.size + justReceived.size) < computeRelayCapacity()) {
justReceived.addLast(message)
activityTickLeft = 20
markChanged()
}
}
override fun encodeScreenData(player: ServerPlayer, buf: FriendlyByteBuf) {
super.encodeScreenData(player, buf)
buf.writeVarInt(computeRelayInterval())
buf.writeVarInt(computeRelayBufferSize())
buf.writeVarInt(computeRelayQueueSize())
buf.writeVarInt(queue.size + justReceived.size)
}
override fun writeFullStateCommit(buf: FriendlyByteBuf) {
super.writeFullStateCommit(buf)
buf.writeVarInt(activityTickLeft)
}
override fun processCommit(buf: FriendlyByteBuf) {
super.processCommit(buf)
activityTickLeft = buf.readVarInt()
}
override fun getComponent() = NNComponent("relay")
}
fun sendQueuedPacket() {
if(queue.isEmpty()) return
val pack = queue.removeFirst()
for(connection in deviceNode.connections) {
// skip unwanted loopback
if(connection in pack.sender.getReachable()) continue
val hopped = pack.hop(pack.sender)
if(connection is ConventionalNetworkDevice) {
connection.sendClassicPacket(hopped)
} else {
Networking.emitMessage(connection, hopped, setOf(deviceNode))
}
}
}
override fun tickDevice(level: Level) {
super.tickDevice(level)
if(level !is ServerLevel) return
if(activityTickLeft > 0) {
activityTickLeft--
deviceNode.markChanged()
}
queue.addAll(justReceived)
justReceived.clear()
val cap = computeRelayCapacity()
while(queue.size > cap) queue.removeLast()
ticksUntilQueue--
if(ticksUntilQueue <= 0) {
ticksUntilQueue = computeRelayInterval()
val toSend = computeRelayBufferSize()
for(i in 0..<toSend) {
sendQueuedPacket()
}
}
deviceNode.markChanged()
}
override fun getMachineBlockPosition() = blockPos!!
override fun getMachineLevel() = level!!
override fun getMachineNode() = deviceNode
override fun getDisplayName() = Component.translatable("block.neocomputers.relay")!!
override fun createMenu(
i: Int,
inventory: Inventory,
player: Player
) = RelayMenu(i, inventory, this)
override fun loadAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
super.loadAdditional(tag, registries)
ContainerHelper.loadAllItems(tag, slots, registries)
}
override fun saveAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
super.saveAdditional(tag, registries)
ContainerHelper.saveAllItems(tag, slots, registries)
}
}
class RelayBlock: DeviceBlock(Properties.of().sound(SoundType.METAL)) {
override fun newBlockEntity(pos: BlockPos, state: BlockState) = RelayEntity(pos, state)
override fun useWithoutItem(
state: BlockState,
level: Level,
pos: BlockPos,
player: Player,
hitResult: BlockHitResult
): InteractionResult {
if(!level.isClientSide) {
val ent = level.getBlockEntity(pos, BlockEntities.RELAY_ENTITY.get()).get()
// Open menu
MenuRegistry.openMenu(player as ServerPlayer, ent)
NodeSynchronizer.registerPlayerScreen(player, ent.deviceNode)
}
return InteractionResult.SUCCESS
}
override fun onRemove(
blockState: BlockState,
level: Level,
blockPos: BlockPos,
blockState2: BlockState,
bl: Boolean
) {
Containers.dropContentsOnDestroy(blockState, blockState2, level, blockPos)
super.onRemove(blockState, level, blockPos, blockState2, bl)
}
}

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

@@ -26,23 +26,19 @@ import org.neoflock.neocomputers.entity.ScreenEntity
import org.neoflock.neocomputers.gui.menu.ScreenMenu import org.neoflock.neocomputers.gui.menu.ScreenMenu
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.max import kotlin.math.max
import org.neoflock.neocomputers.network.NodeSynchronizer
class ScreenBlock() : NodeBlock() { class ScreenBlock() : DeviceBlock() {
companion object { companion object {
val FACING_HORIZ: EnumProperty<Direction> = EnumProperty.create<Direction>("facing_horiz", Direction::class.java) val FACING_HORIZ: EnumProperty<Direction> = EnumProperty.create<Direction>("facing_horiz", Direction::class.java)
val FACING_VERTI: IntegerProperty = IntegerProperty.create("facing_verti", 0, 2) // "Integer" property doesnt accept values below 0, also death to enums, long live magic numbers val FACING_VERTI: IntegerProperty = IntegerProperty.create("facing_verti", 0, 2) // "Integer" property doesnt accept values below 0, also death to enums, long live magic numbers
val ENERGY: Long = 5
} }
init { init {
registerDefaultState(stateDefinition.any().setValue(FACING_HORIZ, Direction.NORTH).setValue(FACING_VERTI, 1)) registerDefaultState(stateDefinition.any().setValue(FACING_HORIZ, Direction.NORTH).setValue(FACING_VERTI, 1))
} }
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity? { override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState) = ScreenEntity(blockPos, blockState)
val scr = ScreenEntity(blockPos, blockState)
scr.initNetworking()
return scr
}
override fun useWithoutItem( override fun useWithoutItem(
blockState: BlockState, blockState: BlockState,
@@ -52,14 +48,9 @@ class ScreenBlock() : NodeBlock() {
blockHitResult: BlockHitResult blockHitResult: BlockHitResult
): InteractionResult { ): InteractionResult {
if(!level.isClientSide) { if(!level.isClientSide) {
val screenState = level.getBlockEntity(blockPos, BlockEntities.SCREEN_ENTITY.get()).get()
if(!screenState.deviceNode.consumeEnergy(ENERGY)) {
player.sendSystemMessage(Component.literal("Not enough power."))
return InteractionResult.SUCCESS
};
val sp = player as ServerPlayer val sp = player as ServerPlayer
val ent = level.getBlockEntity(blockPos, BlockEntities.SCREEN_ENTITY.get()).get() val ent = level.getBlockEntity(blockPos, BlockEntities.SCREEN_ENTITY.get()).get()
NodeSynchronizer.registerPlayerScreen(sp, ent) NodeSynchronizer.registerPlayerScreen(sp, ent.deviceNode)
MenuRegistry.openExtendedMenu(sp, object : ExtendedMenuProvider { MenuRegistry.openExtendedMenu(sp, object : ExtendedMenuProvider {
override fun getDisplayName(): Component = Component.literal("SCREEEEEN!") override fun getDisplayName(): Component = Component.literal("SCREEEEEN!")
override fun createMenu(i: Int, inventory: Inventory, player: Player): AbstractContainerMenu { override fun createMenu(i: Int, inventory: Inventory, player: Player): AbstractContainerMenu {

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.fabricmc.fabric.api.datagen.v1.provider.FabricModelProvider
import net.minecraft.data.models.BlockModelGenerators import net.minecraft.data.models.BlockModelGenerators
import net.minecraft.data.models.ItemModelGenerators 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.block.Blocks
import org.neoflock.neocomputers.item.Items
class ModelGenerator(output: FabricDataOutput) : FabricModelProvider(output) { class ModelGenerator(output: FabricDataOutput) : FabricModelProvider(output) {
override fun generateBlockStateModels(blockStateModelGenerator: BlockModelGenerators) { override fun generateBlockStateModels(blockStateModelGenerator: BlockModelGenerators) {
blockStateModelGenerator.createGenericCube(Blocks.CASE_BLOCK.get()) // blockStateModelGenerator.createGenericCube(Blocks.CASE_BLOCK.get())
} }
override fun generateItemModels(itemModelGenerator: ItemModelGenerators) { override fun generateItemModels(itemModelGenerator: ItemModelGenerators) {
// itemModelGenerator.generateFlatItem(Items.SERVER0.get(), ModelTemplates.FLAT_ITEM)
} }
} }

View File

@@ -0,0 +1,8 @@
package org.neoflock.neocomputers.entity
import net.minecraft.core.BlockPos
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
class AssemblerEntity(pos: BlockPos, state: BlockState) : BlockEntity(BlockEntities.ASSEMBLER_ENTITY.get(), pos, state) {
}

View File

@@ -15,6 +15,7 @@ import org.neoflock.neocomputers.block.CapacitorEntity
import org.neoflock.neocomputers.block.CapacitorEntityTier1 import org.neoflock.neocomputers.block.CapacitorEntityTier1
import org.neoflock.neocomputers.block.CapacitorEntityTier2 import org.neoflock.neocomputers.block.CapacitorEntityTier2
import org.neoflock.neocomputers.block.CapacitorEntityTier3 import org.neoflock.neocomputers.block.CapacitorEntityTier3
import org.neoflock.neocomputers.block.RelayEntity
import org.neoflock.neocomputers.network.PowerManager import org.neoflock.neocomputers.network.PowerManager
// complete fucking bullshit btw // complete fucking bullshit btw
@@ -87,12 +88,36 @@ object BlockEntities {
) )
} }
val RELAY_ENTITY: RegistrySupplier<BlockEntityType<RelayEntity>> = BLOCKENTITIES.register("relay") {
BlockEntityType(
::RelayEntity, setOf(Blocks.RELAY_BLOCK.get()), BullshitFix()
)
}
val ROBOT_ENTITY: RegistrySupplier<BlockEntityType<RobotEntity>> = BLOCKENTITIES.register("robot") {
BlockEntityType(
::RobotEntity, setOf(Blocks.ROBOT_BLOCK.get()), BullshitFix()
)
}
val RACK_ENTITY: RegistrySupplier<BlockEntityType<RackEntity>> = BLOCKENTITIES.register("rack") {
BlockEntityType(
::RackEntity, setOf(Blocks.RACK_BLOCK.get()), BullshitFix()
)
}
val ASSEMBLER_ENTITY: RegistrySupplier<BlockEntityType<AssemblerEntity>> = BLOCKENTITIES.register("assembler") {
BlockEntityType(
::AssemblerEntity, setOf(Blocks.ASSEMBLER_BLOCK.get()), BullshitFix()
)
}
fun registerPowerBlocks() { fun registerPowerBlocks() {
PowerManager.registerPowerBlockEntity(CAPACITOR_ENTITY.get()) PowerManager.registerPowerDevice(CAPACITOR_ENTITY.get())
PowerManager.registerPowerBlockEntity(CAPACITOR2_ENTITY.get()) PowerManager.registerPowerDevice(CAPACITOR2_ENTITY.get())
PowerManager.registerPowerBlockEntity(CAPACITOR3_ENTITY.get()) PowerManager.registerPowerDevice(CAPACITOR3_ENTITY.get())
PowerManager.registerPowerBlockEntity(SOLARGEN_ENTITY.get()) PowerManager.registerPowerDevice(SOLARGEN_ENTITY.get())
PowerManager.registerPowerBlockEntity(COMBUSTGEN_ENTITY.get()) PowerManager.registerPowerDevice(COMBUSTGEN_ENTITY.get())
PowerManager.registerPowerBlockEntity(CASE_ENTITY.get()) PowerManager.registerPowerDevice(CASE_ENTITY.get())
} }
} }

View File

@@ -2,33 +2,46 @@ package org.neoflock.neocomputers.entity
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.world.item.DyeColor
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.entity.BlockEntity import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import org.neoflock.neocomputers.block.CableBlock import org.neoflock.neocomputers.block.CableBlock
import org.neoflock.neocomputers.block.NodeBlockEntity import org.neoflock.neocomputers.block.CableBlock.Companion.COLOR
import org.neoflock.neocomputers.block.CableBlock.Companion.getPropByDirection
import org.neoflock.neocomputers.block.DeviceBlockEntity
import org.neoflock.neocomputers.block.SingleDeviceBlockEntity
import org.neoflock.neocomputers.network.DeviceNode
class CableEntity(pos: BlockPos, state: BlockState) : BlockEntity(BlockEntities.CABLE_ENTITY.get(), pos, state) { class CableEntity(pos: BlockPos, state: BlockState) : SingleDeviceBlockEntity(BlockEntities.CABLE_ENTITY.get(), pos, state) {
override val deviceNode = object : DeviceNode(){}
override fun sendCommitsToClient(level: Level) {
// we have nothing to commit lol
return
}
override fun requestServerState() {
// no state, we don't bother
return
}
override fun getNodeFromSide(directionToRequester: Direction): DeviceNode? {
if(CableBlock.shouldConnect(blockPos, blockPos.relative(directionToRequester), level!!)) {
return deviceNode
}
return null
}
override fun setChanged() { override fun setChanged() {
super.setChanged() super.setChanged()
// val neighbors = getNeighbourEntities()
for (dir in Direction.entries) { for (dir in Direction.entries) {
val ent = level!!.getBlockEntity(blockPos.relative(dir)) val ent = level!!.getBlockEntity(blockPos.relative(dir))
level!!.setBlockAndUpdate(blockPos, blockState.setValue(CableBlock.getPropByDirection(dir), (ent is NodeBlockEntity || ent is CableEntity))) level!!.setBlockAndUpdate(blockPos, blockState.setValue(getPropByDirection(dir), CableBlock.shouldConnect(blockPos, blockPos.relative(dir), level!!)))
if(ent is DeviceBlockEntity) {
ent.connectionsAreDirty = true
}
} }
} }
// fun getNeighbourEntities(): List<BlockEntity> {
// val subpos = listOf(
// blockPos.offset(0, 0, 1),
// blockPos.offset(0, 0, -1),
// blockPos.offset(0, 1, 0),
// blockPos.offset(0, -1, 0),
// blockPos.offset(1, 0, 0),
// blockPos.offset(-1, 0, 0),
// )
//
// return subpos.mapNotNull { pos -> level?.getBlockEntity(pos) }
// }
} }

View File

@@ -11,6 +11,7 @@ import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundSource import net.minecraft.sounds.SoundSource
import net.minecraft.world.Container
import net.minecraft.world.ContainerHelper import net.minecraft.world.ContainerHelper
import net.minecraft.world.MenuProvider import net.minecraft.world.MenuProvider
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
@@ -20,12 +21,11 @@ import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import org.neoflock.neocomputers.NeoComputers import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.block.CaseBlock import org.neoflock.neocomputers.block.CaseBlock
import org.neoflock.neocomputers.block.NodeBlockEntity import org.neoflock.neocomputers.block.SingleDeviceBlockEntity
import org.neoflock.neocomputers.block.NodeSynchronizer
import org.neoflock.neocomputers.block.dirToIdx
import org.neoflock.neocomputers.gui.menu.CaseMenu import org.neoflock.neocomputers.gui.menu.CaseMenu
import org.neoflock.neocomputers.item.ComponentItem import org.neoflock.neocomputers.item.ComponentItem
import org.neoflock.neocomputers.network.DeviceNode import org.neoflock.neocomputers.network.DeviceNode
import org.neoflock.neocomputers.network.NNComponent
import org.neoflock.neocomputers.network.Networking import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.network.PowerRole import org.neoflock.neocomputers.network.PowerRole
import org.neoflock.neocomputers.sounds.ComputerRunningSoundInstance import org.neoflock.neocomputers.sounds.ComputerRunningSoundInstance
@@ -34,8 +34,10 @@ import org.neoflock.neocomputers.utils.GenericContainer
import java.time.Duration import java.time.Duration
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
import org.neoflock.neocomputers.network.NodeSynchronizer
import kotlin.text.ifEmpty
class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEntity(BlockEntities.CASE_ENTITY.get(), blockPos, blockState), MachineEntity, GenericContainer, MenuProvider { class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): SingleDeviceBlockEntity(BlockEntities.CASE_ENTITY.get(), blockPos, blockState), MachineEntity, GenericContainer, MenuProvider {
val stacks: NonNullList<ItemStack> = NonNullList<ItemStack>.withSize(7, ItemStack.EMPTY) val stacks: NonNullList<ItemStack> = NonNullList<ItemStack>.withSize(7, ItemStack.EMPTY)
var isOn = false var isOn = false
@@ -48,45 +50,72 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
override val deviceNode = object : DeviceNode() { override val deviceNode = object : DeviceNode() {
override var powerRole = PowerRole.CONSUMER override var powerRole = PowerRole.CONSUMER
override var energyCapacity: Long = 500 override var energyCapacity: Long = 500
}
override fun encodeDownstreamData(packet: FriendlyByteBuf) { override fun writeFullStateCommit(buf: FriendlyByteBuf) {
super.encodeDownstreamData(packet) super.writeFullStateCommit(buf)
packet.writeBoolean(isOn) buf.writeUUID(address)
packet.writeVarInt(diskActivityTime) buf.writeBoolean(isOn)
packet.writeVarInt(networkActivityTime) buf.writeVarInt(diskActivityTime)
packet.writeUtf(err ?: "") buf.writeVarInt(networkActivityTime)
} buf.writeUtf(err ?: "")
override fun syncWithUpstream(packet: FriendlyByteBuf) {
super.syncWithUpstream(packet)
setRunning(packet.readBoolean())
diskActivityTime = packet.readVarInt()
networkActivityTime = packet.readVarInt()
err = packet.readUtf().ifEmpty { null }
}
override fun processScreenInteraction(player: ServerPlayer, packet: FriendlyByteBuf) {
val c = packet.readByte().toInt()
if(c == 0x01) {
start()
} }
if(c == 0x02) {
stop()
}
}
override fun encodeScreenData(player: ServerPlayer, packet: FriendlyByteBuf) { override fun processCommit(buf: FriendlyByteBuf) {
super.encodeScreenData(player, packet) super.processCommit(buf)
packet.writeBoolean(isOn) Networking.changeNodeAddress(this, buf.readUUID())
packet.writeByteArray((err ?: "").encodeToByteArray()) setRunning(buf.readBoolean())
packet.writeLong(deviceNode.energy) diskActivityTime = buf.readVarInt()
packet.writeLong(deviceNode.energyCapacity) networkActivityTime = buf.readVarInt()
packet.writeLong(getMachineMemoryUsed()) err = buf.readUtf().ifEmpty { null }
packet.writeLong(getMachineMemoryTotal()) }
packet.writeLong(getMachineComponentsUsed())
packet.writeLong(getMachineComponentsTotal()) override fun processScreenInteraction(player: ServerPlayer, buf: FriendlyByteBuf) {
packet.writeUtf(arch) super.processScreenInteraction(player, buf)
val c = buf.readByte().toInt()
if(c == 0x01) {
start()
}
if(c == 0x02) {
stop()
}
}
override fun encodeScreenData(player: ServerPlayer, buf: FriendlyByteBuf) {
super.encodeScreenData(player, buf)
buf.writeBoolean(isOn)
buf.writeByteArray((err ?: "").encodeToByteArray())
buf.writeLong(energy)
buf.writeLong(energyCapacity)
buf.writeLong(getMachineMemoryUsed())
buf.writeLong(getMachineMemoryTotal())
buf.writeLong(getMachineComponentsUsed())
buf.writeLong(getMachineComponentsTotal())
buf.writeUtf(arch)
}
override fun tick() {
super.tick()
if (isRunning()) {
if(diskActivityTime > 0) diskActivityTime--
if(networkActivityTime > 0) networkActivityTime--
if(getMachineArchitectures().isEmpty()) {
crash("@neocomputers.errors.ENOCPU")
} else if(getMachineComponentsUsed() > getMachineComponentsTotal()) {
crash("@neocomputers.errors.E2BIG")
} else if (!consumeEnergy(1)) {
crash("@neocomputers.errors.ENOENJ")
}
}
}
override fun received(message: Networking.Message) {
super.received(message)
if(message is Networking.ClassicPacket) {
NeoComputers.LOGGER.info("machine $address got $message from ${message.sender.address}")
}
}
override fun getComponent() = NNComponent("computer")
} }
val redstoneIn = Array(Direction.entries.size) {0} val redstoneIn = Array(Direction.entries.size) {0}
@@ -95,7 +124,7 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
fun refetchRedstone(dir: Direction) { fun refetchRedstone(dir: Direction) {
val src = blockPos.offset(dir.stepX, dir.stepY, dir.stepZ) val src = blockPos.offset(dir.stepX, dir.stepY, dir.stepZ)
val cur = level?.getSignal(src, dir) ?: 0 val cur = level?.getSignal(src, dir) ?: 0
val idx = dirToIdx(dir) val idx = dir.ordinal
if(redstoneIn[idx] != cur) { if(redstoneIn[idx] != cur) {
onRedstoneSignalChanged(dir, redstoneIn[idx], cur) onRedstoneSignalChanged(dir, redstoneIn[idx], cur)
} }
@@ -118,7 +147,7 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
fun onRedstoneSignalChanged(dir: Direction, oldValue: Int, newValue: Int) { fun onRedstoneSignalChanged(dir: Direction, oldValue: Int, newValue: Int) {
sendMachineEvent(MachineRedstoneEvent(this, dir, oldValue, newValue)) sendMachineEvent(MachineRedstoneEvent(this, dir, oldValue, newValue))
Networking.emitMessage(deviceNode, Networking.ComputerUncheckedSignal(deviceNode, "redstone_changed", arrayOf(deviceNode.address.toString(), dirToIdx(dir), oldValue, newValue))) Networking.emitMessage(deviceNode, Networking.ComputerUncheckedSignal(deviceNode, "redstone_changed", arrayOf(deviceNode.address.toString(), dir.ordinal, oldValue, newValue)))
NeoComputers.LOGGER.info("redstone in direction ${dir.name} changed from $oldValue to $newValue") NeoComputers.LOGGER.info("redstone in direction ${dir.name} changed from $oldValue to $newValue")
if(oldValue == 0) { if(oldValue == 0) {
// Rising edge // Rising edge
@@ -134,6 +163,7 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
fun setRunning(value: Boolean) { fun setRunning(value: Boolean) {
if(isOn == value) return if(isOn == value) return
deviceNode.markChanged()
NeoComputers.LOGGER.info("[${deviceNode.address}] Going from $isOn to $value") NeoComputers.LOGGER.info("[${deviceNode.address}] Going from $isOn to $value")
isOn = value isOn = value
val world = level ?: return val world = level ?: return
@@ -150,14 +180,15 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
} }
// Server-side stuff!! // Server-side stuff!!
sendMachineEvent(MachinePowerEvent(this, isOn)) sendMachineEvent(MachinePowerEvent(this, isOn))
Networking.emitMessage(deviceNode, Networking.ClassicPacket(deviceNode, deviceNode.address.toString(), null, 1, listOf(), 0))
} }
override fun start(): Boolean { override fun start(): Boolean {
if(isOn) return true if(isOn) return true
err = null err = null
val archs = getMachineArchitectures() val architectures = getMachineArchitectures()
// Beep patterns taken from https://github.com/MightyPirates/OpenComputers/blob/571482db88080d56329e8f8cf0db2a90825bf1d7/src/main/scala/li/cil/oc/server/machine/Machine.scala // Beep patterns taken from https://github.com/MightyPirates/OpenComputers/blob/571482db88080d56329e8f8cf0db2a90825bf1d7/src/main/scala/li/cil/oc/server/machine/Machine.scala
if(archs.isEmpty()) { if(architectures.isEmpty()) {
crash("@neocomputers.errors.ENOCPU") crash("@neocomputers.errors.ENOCPU")
beepAsync("-..") beepAsync("-..")
return false return false
@@ -179,9 +210,9 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
beepAsync("-.") beepAsync("-.")
return false return false
} }
if(arch !in archs) { if(arch !in architectures) {
// Just pick one! TODO: consult EEPROM first // Just pick one! TODO: consult EEPROM first
arch = archs.first() arch = architectures.first()
} }
beepAsync(".") beepAsync(".")
setRunning(true) setRunning(true)
@@ -195,10 +226,8 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
} }
override fun crash(error: String): Boolean { override fun crash(error: String): Boolean {
if(isOn) { beepAsync("--")
beepAsync("--") sendMachineEvent(MachineCrashEvent(this, error))
sendMachineEvent(MachineCrashEvent(this, error))
}
setRunning(false) setRunning(false)
err = error err = error
return true return true
@@ -208,12 +237,12 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
override fun getMachineNode() = deviceNode override fun getMachineNode() = deviceNode
override fun getRedstoneInput(direction: Direction): Int = redstoneIn[dirToIdx(direction)] override fun getRedstoneInput(direction: Direction): Int = redstoneIn[direction.ordinal]
override fun getRedstoneOutput(direction: Direction): Int = redstoneOut[dirToIdx(direction)] override fun getRedstoneOutput(direction: Direction): Int = redstoneOut[direction.ordinal]
override fun setRedstoneOutput(direction: Direction, newValue: Int): Int { override fun setRedstoneOutput(direction: Direction, newValue: Int): Int {
val idx = dirToIdx(direction) val idx = direction.ordinal
val old = redstoneOut[idx] val old = redstoneOut[idx]
redstoneOut[idx] = newValue redstoneOut[idx] = newValue
return old return old
@@ -234,7 +263,7 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
override fun getMachineMemoryTotal(): Long = stacks.mapNotNull { (it.item as? ComponentItem)?.getMemoryCapacity(it) }.sum().toLong() override fun getMachineMemoryTotal(): Long = stacks.mapNotNull { (it.item as? ComponentItem)?.getMemoryCapacity(it) }.sum().toLong()
override fun getMachineMemoryUsed(): Long = 0 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 getMachineComponentsTotal(): Long = stacks.mapNotNull { (it.item as? ComponentItem)?.getComponentCapacity(it) }.sum().toLong()
override fun getMachineArchitecture() = arch override fun getMachineArchitecture() = arch
override fun getMachineArchitectures() = stacks.mapNotNull { (it.item as? ComponentItem)?.getArchitecturesProvided(it) }.flatten().toSet() override fun getMachineArchitectures() = stacks.mapNotNull { (it.item as? ComponentItem)?.getArchitecturesProvided(it) }.flatten().toSet()
@@ -251,11 +280,11 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
override fun stillValid(player: Player): Boolean = !this.isRemoved override fun stillValid(player: Player): Boolean = !this.isRemoved
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) { override fun loadAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
super.loadAdditional(compoundTag, provider) super.loadAdditional(tag, registries)
deviceNode.energy = min(deviceNode.energyCapacity, compoundTag.getLong("energy")) deviceNode.energy = min(deviceNode.energyCapacity, tag.getLong("energy"))
//isOn = compoundTag.getBoolean("powerOn") //isOn = compoundTag.getBoolean("powerOn")
ContainerHelper.loadAllItems(compoundTag, getItems(), provider) ContainerHelper.loadAllItems(tag, getItems(), registries)
} }
override fun saveAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) { override fun saveAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
@@ -273,20 +302,6 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
super.setRemoved() super.setRemoved()
} }
override fun tickNode(level: Level) { override fun canPlaceItem(slot: Int, stack: ItemStack): Boolean = false
super.tickNode(level) override fun canTakeItem(target: Container, slot: Int, stack: ItemStack): Boolean = false
if(!level.isClientSide) {
if (isRunning()) {
if(diskActivityTime > 0) diskActivityTime--
if(networkActivityTime > 0) networkActivityTime--
if(getMachineArchitectures().isEmpty()) {
crash("@neocomputers.errors.ENOCPU")
} else if(getMachineComponentsUsed() > getMachineComponentsTotal()) {
crash("@neocomputers.errors.E2BIG")
} else if (!deviceNode.consumeEnergy(1)) {
crash("@neocomputers.errors.ENOENJ")
}
}
}
}
} }

View File

@@ -1,6 +1,7 @@
package org.neoflock.neocomputers.entity package org.neoflock.neocomputers.entity
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.core.HolderLookup import net.minecraft.core.HolderLookup
import net.minecraft.core.NonNullList import net.minecraft.core.NonNullList
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
@@ -15,16 +16,15 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import org.neoflock.neocomputers.block.CombustionGeneratorBlock import org.neoflock.neocomputers.block.CombustionGeneratorBlock
import org.neoflock.neocomputers.block.NodeBlockEntity import org.neoflock.neocomputers.block.SingleDeviceBlockEntity
import org.neoflock.neocomputers.gui.menu.CombustionGeneratorMenu import org.neoflock.neocomputers.gui.menu.CombustionGeneratorMenu
import org.neoflock.neocomputers.network.DeviceNode import org.neoflock.neocomputers.network.DeviceNode
import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.network.PowerRole import org.neoflock.neocomputers.network.PowerRole
import org.neoflock.neocomputers.utils.GenericContainer import org.neoflock.neocomputers.utils.GenericContainer
import org.neoflock.neocomputers.utils.ContainerUtils import org.neoflock.neocomputers.utils.ContainerUtils
import kotlin.math.min import kotlin.math.min
class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) : NodeBlockEntity(BlockEntities.COMBUSTGEN_ENTITY.get(), blockPos, blockState), GenericContainer, MenuProvider { class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) : SingleDeviceBlockEntity(BlockEntities.COMBUSTGEN_ENTITY.get(), blockPos, blockState), GenericContainer, MenuProvider {
val energyPerTick: Long = 50 val energyPerTick: Long = 50
var burningTimeRemaining: Int = 0 var burningTimeRemaining: Int = 0
@@ -32,6 +32,11 @@ class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState)
override val deviceNode = object : DeviceNode() { override val deviceNode = object : DeviceNode() {
override var powerRole = PowerRole.GENERATOR override var powerRole = PowerRole.GENERATOR
override var energyCapacity: Long = 100000 override var energyCapacity: Long = 100000
override fun encodeScreenData(player: ServerPlayer, buf: FriendlyByteBuf) {
buf.writeLong(energy)
buf.writeLong(energyCapacity)
}
} }
val stacks: NonNullList<ItemStack> = NonNullList<ItemStack>.withSize(1, ItemStack.EMPTY) val stacks: NonNullList<ItemStack> = NonNullList<ItemStack>.withSize(1, ItemStack.EMPTY)
@@ -46,8 +51,8 @@ class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState)
return !this.isRemoved return !this.isRemoved
} }
override fun tickNode(level: Level) { override fun tickDevice(level: Level) {
super.tickNode(level) super.tickDevice(level)
// TODO: give us a block state tag for active // TODO: give us a block state tag for active
// keep combusting and shi // keep combusting and shi
@@ -79,11 +84,6 @@ class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState)
level?.setBlockAndUpdate(blockPos, blockState.setValue(CombustionGeneratorBlock.COMBUSTGEN_ACTIVE, burningTimeRemaining > 0)) level?.setBlockAndUpdate(blockPos, blockState.setValue(CombustionGeneratorBlock.COMBUSTGEN_ACTIVE, burningTimeRemaining > 0))
} }
override fun encodeScreenData(player: ServerPlayer, packet: FriendlyByteBuf) {
packet.writeLong(deviceNode.energy)
packet.writeLong(deviceNode.energyCapacity)
}
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) { override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
super.loadAdditional(compoundTag, provider) super.loadAdditional(compoundTag, provider)
deviceNode.energy = min(deviceNode.energyCapacity, compoundTag.getLong("energy")) deviceNode.energy = min(deviceNode.energyCapacity, compoundTag.getLong("energy"))

View File

@@ -4,9 +4,7 @@ import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.phys.Vec3 import net.minecraft.world.phys.Vec3
import org.neoflock.neocomputers.item.ComponentItem
import org.neoflock.neocomputers.network.DeviceNode import org.neoflock.neocomputers.network.DeviceNode
import org.neoflock.neocomputers.network.Networking
import java.time.Duration import java.time.Duration
abstract class MachineEvent { abstract class MachineEvent {
@@ -17,12 +15,16 @@ data class MachineRedstoneEvent(override val machine: MachineEntity, val side: D
data class MachinePowerEvent(override val machine: MachineEntity, val nowRunning: Boolean): MachineEvent() data class MachinePowerEvent(override val machine: MachineEntity, val nowRunning: Boolean): MachineEvent()
data class MachineCrashEvent(override val machine: MachineEntity, val error: String): MachineEvent() data class MachineCrashEvent(override val machine: MachineEntity, val error: String): MachineEvent()
interface MachineEntity { interface ComponentUser {
// Block position of machine, for wireless tech // Block position of machine, for wireless tech
fun getMachineBlockPosition(): BlockPos fun getMachineBlockPosition(): BlockPos
fun getMachinePrecisePosition(): Vec3 = getMachineBlockPosition().center fun getMachinePrecisePosition(): Vec3 = getMachineBlockPosition().center
fun getMachineLevel(): Level fun getMachineLevel(): Level
fun getMachineNode(): DeviceNode
}
interface MachineEntity: ComponentUser {
// Pattern can have dots (.), dashes (-) and spaces ( ). // Pattern can have dots (.), dashes (-) and spaces ( ).
// Each character is duration long, and has a 50ms break. // Each character is duration long, and has a 50ms break.
// For non-short ones, which are typically reserved only for hardware interactions, // For non-short ones, which are typically reserved only for hardware interactions,
@@ -40,8 +42,6 @@ interface MachineEntity {
fun crash(error: String): Boolean fun crash(error: String): Boolean
fun getLastError(): String? fun getLastError(): String?
fun getMachineNode(): DeviceNode
// Some metadata // Some metadata
fun getMachineMemoryTotal(): Long fun getMachineMemoryTotal(): Long
fun getMachineMemoryUsed(): Long fun getMachineMemoryUsed(): Long

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,20 @@
package org.neoflock.neocomputers.entity
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.core.BlockPos
import net.minecraft.network.chat.Component
import net.minecraft.world.Nameable
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity
import net.minecraft.world.level.block.state.BlockState
import org.neoflock.neocomputers.NeoComputers
class RobotEntity(pos: BlockPos, state: BlockState) : BlockEntity(BlockEntities.ROBOT_ENTITY.get(), pos, state,), Nameable {
val body: ModelPart? = null
val name = "Diddyx" //TODO: names
override fun getName(): Component? = Component.literal(name)
init {
NeoComputers.LOGGER.info("yooo")
}
}

View File

@@ -1,79 +1,117 @@
package org.neoflock.neocomputers.entity; package org.neoflock.neocomputers.entity
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.locale.Language
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import org.neoflock.neocomputers.NeoComputers import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.block.NodeBlockEntity import org.neoflock.neocomputers.block.SingleDeviceBlockEntity
import org.neoflock.neocomputers.gui.buffer.BufferRenderer import org.neoflock.neocomputers.gui.buffer.BufferRenderer
import org.neoflock.neocomputers.network.DeviceNode import org.neoflock.neocomputers.network.DeviceNode
import org.neoflock.neocomputers.network.NNComponent
import org.neoflock.neocomputers.network.Networking import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.utils.GPUChar import org.neoflock.neocomputers.utils.GPUChar
import org.neoflock.neocomputers.utils.TextBuffer import org.neoflock.neocomputers.utils.TextBuffer
import kotlin.text.ifEmpty
class ScreenEntity(blockPos: BlockPos, blockState: BlockState) : class ScreenEntity(blockPos: BlockPos, blockState: BlockState) :
NodeBlockEntity(BlockEntities.SCREEN_ENTITY.get(), blockPos, blockState) { SingleDeviceBlockEntity(BlockEntities.SCREEN_ENTITY.get(), blockPos, blockState) {
var lastError: String? = null
var isOn: Boolean = false
override val deviceNode = object : DeviceNode() { override val deviceNode = object : DeviceNode() {
override fun received(message: Networking.Message) { override fun received(message: Networking.Message) {
super.received(message) super.received(message)
if(message is Networking.ComputerEvent) { if(message is Networking.ComputerEvent) {
// return if not directly connected
if(message.sender !in this.connections) return
val mEnv = message.machineEvent val mEnv = message.machineEvent
NeoComputers.LOGGER.info("Got message $mEnv!") NeoComputers.LOGGER.info("Got message $mEnv!")
if(mEnv is MachinePowerEvent) { if(mEnv is MachinePowerEvent) {
if(mEnv.nowRunning) { if(mEnv.nowRunning) {
textBuf.set(0, 0, address.toString()) lastError = null
} else {
textBuf.fill(0, 0, textBuf.width, textBuf.height, GPUChar(' ')) textBuf.fill(0, 0, textBuf.width, textBuf.height, GPUChar(' '))
textBuf.set(0, 0, address.toString())
} }
isOn = mEnv.nowRunning
markChanged()
}
if(mEnv is MachineCrashEvent) {
lastError = mEnv.error
markChanged()
} }
} }
} }
override fun encodeScreenData(player: ServerPlayer, buf: FriendlyByteBuf) {
super.encodeScreenData(player, buf)
textBuf.encodeContents(buf)
}
override fun writeFullStateCommit(buf: FriendlyByteBuf) {
super.writeFullStateCommit(buf)
buf.writeUUID(address)
buf.writeBoolean(isOn)
buf.writeUtf(lastError ?: "")
textBuf.encodeContents(buf)
}
override fun processCommit(buf: FriendlyByteBuf) {
super.processCommit(buf)
if(Networking.changeNodeAddress(this, buf.readUUID())) createScreenTexture()
isOn = buf.readBoolean()
lastError = buf.readUtf().ifEmpty { null }
textBuf.decodeContents(buf)
}
override fun getComponent() = NNComponent("screen")
} }
var bound = "screen/unbound" var bound = "screen/unbound"
val textBuf = TextBuffer(50, 16) 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 encodeDownstreamData(packet: FriendlyByteBuf) { override fun tickDevice(level: Level) {
super.encodeDownstreamData(packet) super.tickDevice(level)
textBuf.encodeContents(packet) cleanRenderer()
} createScreenTexture()
override fun syncWithUpstream(packet: FriendlyByteBuf) {
super.syncWithUpstream(packet)
textBuf.decodeContents(packet)
}
override fun encodeScreenData(player: ServerPlayer, packet: FriendlyByteBuf) {
super.encodeScreenData(player, packet)
textBuf.encodeContents(packet)
}
override fun tickNode(level: Level) {
super.tickNode(level)
cleanrenderer()
createscreenstuffs()
} }
override fun setRemoved() { override fun setRemoved() {
super.setRemoved() super.setRemoved()
bound = "screen/unbound" // ensure no missing texture is displayed bound = "screen/unbound" // ensure no missing texture is displayed
cleanrenderer() cleanRenderer()
} }
private fun createscreenstuffs() { private fun createScreenTexture() {
bound = "screen/"+deviceNode.address.toString().replace("-", "_") bound = "screen/"+deviceNode.address.toString().replace("-", "_")
if (level!!.isClientSide) { if (level!!.isClientSide) {
var renderer = BufferRenderer(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, bound), textBuf) if(lastError == null) {
renderer.drawBuffer() if(!isOn) {
cleanrenderer = { renderer.clean() } textBuf.fill(0, 0, textBuf.width, textBuf.height)
}
val renderer = BufferRenderer(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, bound), textBuf)
renderer.drawBuffer()
cleanRenderer = { renderer.clean() }
} else {
var trueError = lastError!!
if(trueError.startsWith("@")) {
val trans = trueError.substring(1)
val lang = Language.getInstance()
trueError = lang.getOrDefault("neocomputers.computer.errorNoMsg", "Error: ") + lang.getOrDefault(trans)
}
val throwAwayBuf = TextBuffer(50, 16)
val fg = 0xFFFFFF
val bg = 0x2B68A6
throwAwayBuf.fill(0, 0, throwAwayBuf.width, throwAwayBuf.height, GPUChar(' ', fg, bg))
throwAwayBuf.set((throwAwayBuf.width - trueError.length) / 2, throwAwayBuf.height/2, trueError, fg, bg)
val renderer = BufferRenderer(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, bound), throwAwayBuf)
renderer.drawBuffer()
cleanRenderer = { renderer.clean() }
}
} }
} }
} }

View File

@@ -1,25 +1,25 @@
package org.neoflock.neocomputers.entity package org.neoflock.neocomputers.entity
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.core.HolderLookup import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import org.neoflock.neocomputers.block.NodeBlockEntity import org.neoflock.neocomputers.block.SingleDeviceBlockEntity
import org.neoflock.neocomputers.network.DeviceNode import org.neoflock.neocomputers.network.DeviceNode
import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.network.PowerRole import org.neoflock.neocomputers.network.PowerRole
class SolarGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) : NodeBlockEntity(BlockEntities.SOLARGEN_ENTITY.get(), blockPos, blockState) { class SolarGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) : SingleDeviceBlockEntity(BlockEntities.SOLARGEN_ENTITY.get(), blockPos, blockState) {
val energyPerTick: Long = 50 val energyPerTick: Long = 10
override val deviceNode = object : DeviceNode() { override val deviceNode = object : DeviceNode() {
override var powerRole: PowerRole = PowerRole.GENERATOR override var powerRole: PowerRole = PowerRole.GENERATOR
override var energyCapacity: Long = 50000 override var energyCapacity: Long = 50000
} }
override fun tickNode(level: Level) { override fun tickDevice(level: Level) {
super.tickNode(level) super.tickDevice(level)
val l = level val l = level
if(l.isDay) { if(l.isDay) {
deviceNode.giveEnergy(energyPerTick) deviceNode.giveEnergy(energyPerTick)

View File

@@ -0,0 +1,46 @@
package org.neoflock.neocomputers.entity.render
import com.mojang.blaze3d.vertex.DefaultVertexFormat
import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.blaze3d.vertex.VertexFormat
import com.mojang.math.Axis
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.RenderStateShard
import net.minecraft.client.renderer.RenderType
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider
import net.minecraft.resources.ResourceLocation
import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.entity.AssemblerEntity
class AssemblerEntityRenderer(val context: BlockEntityRendererProvider.Context) : BlockEntityRenderer<AssemblerEntity> {
val RENDER_TYPE = {l: ResourceLocation ->
RenderType.create("nc_assembler", DefaultVertexFormat.POSITION_TEX, VertexFormat.Mode.QUADS, RenderType.TRANSIENT_BUFFER_SIZE, RenderType.CompositeState.builder()
.setTextureState(RenderStateShard.TextureStateShard(l, false, false))
.setShaderState(RenderStateShard.ShaderStateShard.POSITION_TEX_SHADER)
.createCompositeState(false))
}
override fun render(blockEntity: AssemblerEntity, partialTick: Float, poseStack: PoseStack, bufferSource: MultiBufferSource, packedLight: Int, packedOverlay: Int) {
var buffer = bufferSource.getBuffer(RENDER_TYPE(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/block/assembler_top_on.png")))
val pose = poseStack.last()
buffer.addVertex(pose, 0f, 17/16f, 1f).setUv(1f, 0f)
buffer.addVertex(pose, 1f, 17/16f, 1f).setUv(1f, 1f)
buffer.addVertex(pose, 1f, 17/16f, 0f).setUv(0f, 1f)
buffer.addVertex(pose, 0f, 17/16f, 0f).setUv(0f, 0f)
// TODO: do assembling texture
buffer = bufferSource.getBuffer(RENDER_TYPE(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/block/assembler_side_on.png")))
poseStack.pushPose()
for (i in 0..3) {
val pose = poseStack.last()
buffer.addVertex(pose, 1.001f, 1f, 0f).setUv(0f, 0f)
buffer.addVertex(pose, 1.001f, 1f, 1f).setUv(1f, 0f)
buffer.addVertex(pose, 1.001f, 0f, 1f).setUv(1f, 1f)
buffer.addVertex(pose, 1.001f, 0f, 0f).setUv(0f, 1f)
poseStack.rotateAround(Axis.YP.rotationDegrees(90f), 0.5f, 0.5f, 0.5f)
}
poseStack.popPose()
}
}

View File

@@ -5,12 +5,14 @@ import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.blaze3d.vertex.VertexConsumer import com.mojang.blaze3d.vertex.VertexConsumer
import com.mojang.blaze3d.vertex.VertexFormat import com.mojang.blaze3d.vertex.VertexFormat
import com.mojang.math.Axis import com.mojang.math.Axis
import net.minecraft.client.renderer.LightTexture
import net.minecraft.client.renderer.MultiBufferSource import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.RenderStateShard import net.minecraft.client.renderer.RenderStateShard
import net.minecraft.client.renderer.RenderType import net.minecraft.client.renderer.RenderType
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer import net.minecraft.client.renderer.blockentity.BlockEntityRenderer
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider
import net.minecraft.core.Direction import net.minecraft.core.Direction
import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.block.CaseBlock import org.neoflock.neocomputers.block.CaseBlock
import org.neoflock.neocomputers.entity.CaseBlockEntity import org.neoflock.neocomputers.entity.CaseBlockEntity
@@ -23,9 +25,10 @@ class CaseEntityRenderer(private val context: BlockEntityRendererProvider.Contex
val BLINKTIME: Long = 10 // in ticks 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() RenderType.TRANSIENT_BUFFER_SIZE, RenderType.CompositeState.builder()
.setShaderState(RenderStateShard.POSITION_COLOR_SHADER) .setShaderState(RenderStateShard.POSITION_COLOR_LIGHTMAP_SHADER)
.setLightmapState(RenderStateShard.LightmapStateShard.LIGHTMAP)
.createCompositeState(false)) .createCompositeState(false))
override fun render(ent: CaseBlockEntity, partialTick: Float, mat: PoseStack, bufferSource: MultiBufferSource, packedLight: Int, packedOverlay: Int) { 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) if (ent.isOn) drawLED(buffer, mat.last(), 3F)
else if (ent.getLastError() != null) { // if else hell else if (ent.getLastError() != null) { // if else hell
if ((ent.level!!.dayTime/BLINKTIME) % 2 == 1.toLong()) drawLED(buffer, mat.last(), 3F, RED) 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, packedLight)
} else drawLED(buffer, mat.last(), 3F, OFF) } else drawLED(buffer, mat.last(), 3F, OFF, packedLight)
mat.translate(6/16F, 0F, 0F) 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() mat.popPose()
} }
private fun drawLED(buffer: VertexConsumer, mat: PoseStack.Pose, width: Float, color: Int = GREEN) { 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) buffer.addVertex(mat, width/16F, 0F, 0F).setColor(color).setLight(light)
buffer.addVertex(mat, width/16F, 1/16F, 0F).setColor(color) buffer.addVertex(mat, width/16F, 1/16F, 0F).setColor(color).setLight(light)
buffer.addVertex(mat, 0F, 1/16F, 0F).setColor(color) buffer.addVertex(mat, 0F, 1/16F, 0F).setColor(color).setLight(light)
buffer.addVertex(mat, 0F, 0F, 0F).setColor(color) buffer.addVertex(mat, 0F, 0F, 0F).setColor(color).setLight(light)
} }
private fun handleDirection(facing: Direction, mat: PoseStack) { private fun handleDirection(facing: Direction, mat: PoseStack) {

View File

@@ -0,0 +1,15 @@
package org.neoflock.neocomputers.entity.render
import net.minecraft.client.renderer.blockentity.BlockEntityRenderers
import org.neoflock.neocomputers.entity.BlockEntities
object EntityRenderers {
fun registerBlockEntityRenderers() {
BlockEntityRenderers.register(BlockEntities.SCREEN_ENTITY.get(), ::ScreenEntityRenderer); // TODO: put this in common
BlockEntityRenderers.register(BlockEntities.CASE_ENTITY.get(), ::CaseEntityRenderer);
BlockEntityRenderers.register(BlockEntities.RELAY_ENTITY.get(), ::RelayEntityRenderer);
BlockEntityRenderers.register(BlockEntities.ROBOT_ENTITY.get(), ::RobotEntityRenderer);
BlockEntityRenderers.register(BlockEntities.RACK_ENTITY.get(), ::RackEntityRenderer);
BlockEntityRenderers.register(BlockEntities.ASSEMBLER_ENTITY.get(), ::AssemblerEntityRenderer)
}
}

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,129 @@
package org.neoflock.neocomputers.entity.render
import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.DefaultVertexFormat
import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.blaze3d.vertex.VertexConsumer
import com.mojang.blaze3d.vertex.VertexFormat
import com.mojang.math.Axis
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.Font
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.client.renderer.GameRenderer
import net.minecraft.client.renderer.ItemBlockRenderTypes
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.RenderStateShard
import net.minecraft.client.renderer.RenderType
import net.minecraft.client.renderer.RenderType.CompositeState
import net.minecraft.client.renderer.block.ModelBlockRenderer
import net.minecraft.client.renderer.block.model.BakedQuad
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider
import net.minecraft.client.renderer.blockentity.ChestRenderer
import net.minecraft.client.renderer.entity.EntityRenderer
import net.minecraft.client.renderer.entity.LivingEntityRenderer
import net.minecraft.client.renderer.texture.OverlayTexture
import net.minecraft.client.renderer.texture.TextureAtlas
import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.client.resources.model.BakedModel
import net.minecraft.client.resources.model.Material
import net.minecraft.client.resources.model.ModelResourceLocation
import net.minecraft.client.resources.model.ModelState
import net.minecraft.core.Direction
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import net.minecraft.util.RandomSource
import net.minecraft.world.item.DyeColor
import net.minecraft.world.level.block.entity.ChestBlockEntity
import net.minecraft.world.phys.Vec3
import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.block.model.RobotModel
import org.neoflock.neocomputers.entity.RobotEntity
import kotlin.math.sin
class RobotEntityRenderer(val context: BlockEntityRendererProvider.Context) : BlockEntityRenderer<RobotEntity> {
val atlas: (Material) -> TextureAtlasSprite = { m ->
Minecraft.getInstance().getTextureAtlas(m.atlasLocation()).apply(m.texture())
}
val loc: ResourceLocation = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "robot")
var model: BakedModel? = Minecraft.getInstance().modelManager.getModel(ModelResourceLocation.inventory(loc))
val renderer: ModelBlockRenderer = ModelBlockRenderer(Minecraft.getInstance().blockColors) // so ass
val STREAK_RENDER_TYPE = RenderType.create("nc_robot_streak", DefaultVertexFormat.POSITION_TEX_COLOR, VertexFormat.Mode.QUADS, RenderType.TRANSIENT_BUFFER_SIZE,
CompositeState.builder()
.setShaderState(RenderStateShard.ShaderStateShard { GameRenderer.getPositionTexColorShader() })
.setTransparencyState(RenderStateShard.ADDITIVE_TRANSPARENCY)
.setCullState(RenderStateShard.CullStateShard.NO_CULL)
.setTextureState(RenderStateShard.TextureStateShard(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/block/robot.png"), false, false))
.createCompositeState(false))
override fun render(ent: RobotEntity, partialTick: Float, poseStack: PoseStack, bufferSource: MultiBufferSource, packedLight: Int, packedOverlay: Int) {
poseStack.pushPose()
// poseStack.translate(0f, sin(ent.level!!.dayTime.toFloat()/20F)*0.02F, 0f)
val modelbuffer = bufferSource.getBuffer(RenderType.entitySolid(TextureAtlas.LOCATION_BLOCKS))
val colorbuffer = bufferSource.getBuffer(STREAK_RENDER_TYPE)
val col = DyeColor.LIGHT_GRAY.fireworkColor
val red = ((col and 0xFF0000) shr 8*2) / 255f
val green = ((col and 0xFF00) shr 8) / 255f
val blue = ((col and 0xFF)) / 255f
renderer.renderModel(poseStack.last(), modelbuffer, ent.blockState, model!!, red, green, blue, packedLight, packedOverlay)
renderLight(poseStack, colorbuffer, (ent.level!!.dayTime%16).toInt())
// TODO: crafting table and chest little models
// EntityRenderer
renderTag(ent, Component.literal(ent.name), poseStack, bufferSource, packedLight, partialTick)
poseStack.popPose()
}
// offset is 0-15
fun renderLight(poseStack: PoseStack, buffer: VertexConsumer, offset: Int) {
poseStack.pushPose()
val u1 = 0.5f
val v1 = 0.5f + offset*1/32f
val u2 = 1F
val v2 = 17/32f + offset*1/32f
for (i in 0..3) {
poseStack.rotateAround(Axis.YP.rotationDegrees(90f), 0.5f, 0.5f, 0.5f)
buffer.addVertex(poseStack.last(),0.1f+2/16f, 7/16f, 0.9f-2/16f).setColor(1f, 0f, 0f, 1f).setUv(u2, v2)
buffer.addVertex(poseStack.last(),0.1f+2/16f, 9/16f, 0.9f-2/16f).setColor(1f, 0f, 0f, 1f).setUv(u2, v1)
buffer.addVertex(poseStack.last(),0.1f+2/16f, 9/16f, 0.1f+2/16f).setColor(1f, 0f, 0f, 1f).setUv(u1, v1)
buffer.addVertex(poseStack.last(),0.1f+2/16f, 7/16f, 0.1f+2/16f).setColor(1f, 0f, 0f, 1f).setUv(u1, v2)
}
poseStack.popPose()
}
fun renderTag(ent: RobotEntity, name: Component, stack: PoseStack, source: MultiBufferSource, light: Int, ptick: Float) {
val d = Minecraft.getInstance().cameraEntity!!.distanceToSqr(ent.blockPos.center)
if (d > 4096.0) return
val vec = Vec3(0.5, 20 / 16.0, 0.5)
stack.pushPose()
stack.translate(vec.x, vec.y, vec.z)
stack.mulPose(context.entityRenderer.cameraOrientation())
stack.scale(0.025F, -0.025F, 0.025F)
val opacity = Minecraft.getInstance().options.getBackgroundOpacity(0.25F)
val alpha: Int = (opacity * 255.0f).toInt() shl 24
// val alpha = 255
val halfwidth = (-context.font.width(name)) / 2;
// RenderSystem.enableDepthTest()
// RenderSystem.enableBlend()
// RenderSystem.depthMask(true)
context.font.drawInBatch(name, halfwidth.toFloat(), 2f, 0xFFFFFF, false, stack.last().pose(), source, Font.DisplayMode.SEE_THROUGH, alpha, light)
(source as MultiBufferSource.BufferSource).endBatch()
stack.popPose()
}
}

View File

@@ -27,6 +27,7 @@ class ScreenEntityRenderer(val context: BlockEntityRendererProvider.Context?) :
.createCompositeState(false)) .createCompositeState(false))
} }
override fun render(entity: ScreenEntity, partialTick: Float, mat: PoseStack, bufferSource: MultiBufferSource, packedLight: Int, packedOverlay: Int) { override fun render(entity: ScreenEntity, partialTick: Float, mat: PoseStack, bufferSource: MultiBufferSource, packedLight: Int, packedOverlay: Int) {
if(!entity.isOn && entity.lastError == null) return
val facing = entity.blockState.getValue(ScreenBlock.FACING_HORIZ) val facing = entity.blockState.getValue(ScreenBlock.FACING_HORIZ)
val vert = entity.blockState.getValue(ScreenBlock.FACING_VERTI)-1 val vert = entity.blockState.getValue(ScreenBlock.FACING_VERTI)-1

View File

@@ -0,0 +1,29 @@
package org.neoflock.neocomputers.gui.menu
import net.fabricmc.fabric.mixin.item.client.HeldItemRendererMixin
import net.minecraft.client.gui.MapRenderer
import net.minecraft.client.renderer.entity.ItemRenderer
import net.minecraft.world.Container
import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.item.ItemStack
import org.neoflock.neocomputers.block.Blocks
import org.neoflock.neocomputers.gui.widget.DynamicSlot
import org.neoflock.neocomputers.utils.GenericContainer
import org.neoflock.neocomputers.utils.GenericContainerMenu
class CaseSlot(container: Container, index: Int, x: Int, y: Int) : DynamicSlot(container, index, x, y) {
val caseItems = listOf(Blocks.CASE_BLOCK.get().asItem())
override fun mayPlace(stack: ItemStack): Boolean = stack.item in caseItems
}
class AssemblerMenu : GenericContainerMenu {
constructor(id: Int, inv: Inventory) : this(id, inv, SimpleContainer(1))
constructor(id: Int, inv: Inventory, container: Container) : super(Menus.ASSEMBLER_MENU.get(), id, container) {
this.addSlot(CaseSlot(container, 0, 12, 12))
this.addInventoryHotbar(inv, 8, 84)
}
}

View File

@@ -10,21 +10,30 @@ import net.minecraft.world.flag.FeatureFlags
import net.minecraft.world.inventory.MenuType import net.minecraft.world.inventory.MenuType
import org.neoflock.neocomputers.NeoComputers import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.gui.menu.ScreenMenu import org.neoflock.neocomputers.gui.menu.ScreenMenu
import org.neoflock.neocomputers.gui.screen.AssemblerScreen
import org.neoflock.neocomputers.gui.screen.CaseScreen import org.neoflock.neocomputers.gui.screen.CaseScreen
import org.neoflock.neocomputers.gui.screen.CombustionGeneratorScreen 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 import org.neoflock.neocomputers.gui.screen.ScreenScreen
object Menus { object Menus {
val MENUS: DeferredRegister<MenuType<*>> = DeferredRegister.create(NeoComputers.MODID, Registries.MENU) val MENUS: DeferredRegister<MenuType<*>> = DeferredRegister.create(NeoComputers.MODID, Registries.MENU)
// val SCREEN_MENU: RegistrySupplier<MenuType<ScreenMenu>> = MENUS.register("screen_menu") { MenuType(::ScreenMenu, FeatureFlagSet.of()) }
val SCREEN_MENU: RegistrySupplier<MenuType<ScreenMenu>> = MENUS.register("screen_menu") { MenuRegistry.ofExtended<ScreenMenu>(::ScreenMenu) } val SCREEN_MENU: RegistrySupplier<MenuType<ScreenMenu>> = MENUS.register("screen_menu") { MenuRegistry.ofExtended<ScreenMenu>(::ScreenMenu) }
val COMBUSTGEN_MENU: RegistrySupplier<MenuType<CombustionGeneratorMenu>> = MENUS.register("combustgen_menu") { MenuType(::CombustionGeneratorMenu, FeatureFlagSet.of() ) } val 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 CASE_MENU: RegistrySupplier<MenuType<CaseMenu>> = MENUS.register("case_menu") { MenuType(::CaseMenu, FeatureFlagSet.of() )}
val RELAY_MENU: RegistrySupplier<MenuType<RelayMenu>> = MENUS.register("relay_menu") { MenuType(::RelayMenu, FeatureFlagSet.of() )}
val RACK_MENU: RegistrySupplier<MenuType<RackMenu>> = MENUS.register("rack_menu") { MenuRegistry.ofExtended(::RackMenu) }
val ASSEMBLER_MENU: RegistrySupplier<MenuType<AssemblerMenu>> = MENUS.register("assembler_menu") { MenuType(::AssemblerMenu, FeatureFlagSet.of() )}
// val RACK_MENU: RegistrySupplier<MenuType<RackMenu>> = MENUS.register("rack_menu") { MenuType(::RackMenu, FeatureFlagSet.of() )}
fun registerScreens() { fun registerScreens() {
MenuScreens.register(Menus.COMBUSTGEN_MENU.get()) { m: CombustionGeneratorMenu, u, comp ->CombustionGeneratorScreen(m,u,comp)} MenuScreens.register(Menus.COMBUSTGEN_MENU.get()) { m: CombustionGeneratorMenu, u, comp ->CombustionGeneratorScreen(m,u,comp)}
MenuScreens.register(Menus.SCREEN_MENU.get(), ::ScreenScreen) MenuScreens.register(Menus.SCREEN_MENU.get(), ::ScreenScreen)
MenuScreens.register(Menus.CASE_MENU.get(), ::CaseScreen) MenuScreens.register(Menus.CASE_MENU.get(), ::CaseScreen)
MenuScreens.register(Menus.RELAY_MENU.get(), ::RelayScreen)
MenuScreens.register(Menus.RACK_MENU.get(), ::RackScreen)
MenuScreens.register(Menus.ASSEMBLER_MENU.get(), ::AssemblerScreen)
} }
} }

View File

@@ -0,0 +1,193 @@
package org.neoflock.neocomputers.gui.menu
import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.BufferUploader
import com.mojang.blaze3d.vertex.DefaultVertexFormat
import com.mojang.blaze3d.vertex.Tesselator
import com.mojang.blaze3d.vertex.VertexConsumer
import com.mojang.blaze3d.vertex.VertexFormat
import io.netty.buffer.Unpooled
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.events.GuiEventListener
import net.minecraft.client.renderer.GameRenderer
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.RenderStateShard
import net.minecraft.client.renderer.RenderType
import net.minecraft.client.resources.sounds.SimpleSoundInstance
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.sounds.SoundEvents
import net.minecraft.world.Container
import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.entity.RackEntity
import org.neoflock.neocomputers.gui.widget.ComponentRoles
import org.neoflock.neocomputers.gui.widget.DynamicSlot
import org.neoflock.neocomputers.item.ComponentItem
import org.neoflock.neocomputers.utils.GenericContainerMenu
class RackSlot(container: Container, slot: Int, x: Int, y: Int) : DynamicSlot(container, slot, x, y), GuiEventListener {
// i hate that i made this, my regret is immeasurable
// i genuinely cant help myself
val MAIN_COLOURS = listOf(0xff8382d8.toInt(), 0xff75bdc1.toInt(), 0xffc8ca5f.toInt(), 0xffdb7d75.toInt(), 0xff7ec95f.toInt())
val DARK_COLOURS = listOf(0xff6a6ab0.toInt(), 0xff60999d.toInt(), 0xffa2a44e.toInt(), 0xffb36660.toInt(), 0xff67a34e.toInt())
val LIGHT_COLOURS = listOf(0xffdcdcf0.toInt(), 0xffdcdcf0.toInt(), 0xffececd4.toInt(), 0xfff0dbd9.toInt(), 0xffdbecd4.toInt())
val secondaries = 2 // TODO: make this actually change depending on how many network cards
// todo: kotlin getters and setters
fun getSelected(i: Int): Int = (container as RackEntity).conns[containerSlot*4+i]
fun setSelected(i: Int, v: Int) { (container as RackEntity).conns[containerSlot*4+i] = v }
override fun draw(graphics: GuiGraphics, mouseX: Int, mouseY: Int) {
super.draw(graphics, mouseX, mouseY)
if (!hasItem()) { drawQuad(graphics, ComponentRoles.getTextureFor("rack"), x, y, 16, 16, 0f, 0f, 15f, 15f); return; }
for (i in 0..secondaries) {
if (getSelected(i) > -1) drawConnection(graphics, getSelected(i), i-1)
}
drawEndpoints(graphics, mouseX, mouseY, secondaries)
}
override fun mayPlace(stack: ItemStack): Boolean {
if (stack.item !is ComponentItem) return false
return (stack.item as ComponentItem).getComponentRoles(stack).contains(ComponentRoles.RACK_MOUNTABLE)
}
override fun onTake(player: Player, stack: ItemStack) {
super.onTake(player, stack)
setSelected(0, -1)
setSelected(1, -1)
setSelected(2, -1)
setSelected(3, -1)
(container as RackEntity).setChanged()
}
fun drawConnection(guiGraphics: GuiGraphics, side: Int, sec: Int = -1) {
val bufferSource = guiGraphics.bufferSource()
val buffer = bufferSource.getBuffer(RenderType.gui())
if (sec == -1) {
drawColor(guiGraphics, buffer, 18, 1, DARK_COLOURS[side], 6 + (11 * side))
drawColor(guiGraphics, buffer, 18, 2, MAIN_COLOURS[side], 6 + (11 * side))
drawColor(guiGraphics, buffer, 18, 3, LIGHT_COLOURS[side], 6 + (11 * side))
} else {
drawColor(guiGraphics, buffer, 18, 6+(4*sec), MAIN_COLOURS[side], 6+(11*side))
drawColor(guiGraphics, buffer, 18, 7+(4*sec), 0xff8f8f90.toInt(), 6+(11*side))
}
}
fun drawEndpoints(guiGraphics: GuiGraphics, mx: Int, my: Int, sec: Int =0) {
val bufferSource = guiGraphics.bufferSource()
val buffer = bufferSource.getBuffer(RenderType.gui())
// main slot endpoint
drawColor(guiGraphics, buffer, 17, 1, 0xff888888.toInt())
drawColor(guiGraphics, buffer, 17, 3, 0xffffffff.toInt())
// main cable endpoints
for (i in 0..4) {
drawColor(guiGraphics, buffer, 24+(11*i), 1, 0xff333333.toInt(), 1, 3)
drawColor(guiGraphics, buffer, 25+(11*i), 1, MAIN_COLOURS[i], 3, 3)
drawColor(guiGraphics, buffer, 28+(11*i), 1, 0xffffffff.toInt(), 1, 3)
// highlight
if (mx >= x+25+(11*i) && mx <= x+27+(11*i) && my >= y+1 && my <= y+3) {
drawColor(guiGraphics, buffer, 25+(11*i), 1, 0x80FFFFFF.toInt(), 3, 3)
}
}
// secondary endpoints
for (i in 0..<sec) {
// slot
drawColor(guiGraphics, buffer, 17, 6+(4*i), 0xffffffff.toInt())
drawColor(guiGraphics, buffer, 17, 7+(4*i), 0xff888888.toInt())
// cable
for (j in 0..4) {
drawColor(guiGraphics, buffer, 24+(11*j), 6+(4*i), 0xff333333.toInt(), 1, 2)
drawColor(guiGraphics, buffer, 25+(11*j), 6+(4*i), MAIN_COLOURS[j], 3, 2)
drawColor(guiGraphics, buffer, 28+(11*j), 6+(4*i), 0xffffffff.toInt(), 1, 2)
// highlight
if (mx >= x+25+(11*j) && mx <= x+27+(11*j) && my >= y+6+(4*i) && my <= y+8+(4*i)) {
drawColor(guiGraphics, buffer, 25+(11*j), 6+(4*i), 0x80FFFFFF.toInt(), 3, 2)
}
}
}
}
fun encode(buf: FriendlyByteBuf) { // client -> server
buf.writeInt(containerSlot)
buf.writeInt(getSelected(0))
buf.writeInt(getSelected(1))
buf.writeInt(getSelected(2))
buf.writeInt(getSelected(3))
}
// TODO: replace with graphics.fill (cant be assed atm)
fun drawColor(guiGraphics: GuiGraphics, buffer: VertexConsumer, _x:Int, _y: Int, col: Int, width: Int=1, height: Int=1) {
val pose = guiGraphics.pose().last()
// x+_x+1 is one im not proud of
buffer.addVertex(pose, x+_x+width.toFloat(), y+_y+height.toFloat(), 2f).setColor(col)
buffer.addVertex(pose, x+_x+width.toFloat(), y+_y.toFloat(), 2f).setColor(col)
buffer.addVertex(pose, x+_x.toFloat(), y+_y.toFloat(), 2f).setColor(col)
buffer.addVertex(pose, x+_x.toFloat(), y+_y+height.toFloat(), 2f).setColor(col)
}
fun clickynoise() {
val handler = Minecraft.getInstance().soundManager
handler.play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F));
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
for (i in 0..4) { // main line
if (mouseX >= x+25+(11*i) && mouseX <= x+28+(11*i) && mouseY >= y+1 && mouseY <= y+4 && button == 0) {
setSelected(0, if (getSelected(0) != i) i else -1)
(container as RackEntity).setChanged()
clickynoise()
return true
}
}
for (i in 0..<secondaries) { // secondary lines
for (j in 0..4) {
if (mouseX >= x+25+(11*j) && mouseX <= x+28+(11*j) && mouseY >= y+6+(4*i) && mouseY <= y+8+(4*i) && button == 0) {
setSelected(i+1, if (getSelected(i+1) != j) j else -1)
(container as RackEntity).setChanged()
clickynoise()
return true
}
}
}
return super.mouseClicked(mouseX, mouseY, button)
}
override fun setFocused(focused: Boolean) {
}
override fun isFocused(): Boolean {
return false
}
}
class RackMenu : GenericContainerMenu {
constructor(i: Int, inv: Inventory, buf: FriendlyByteBuf) : this(i, inv, (inv.player.level().getBlockEntity(buf.readBlockPos()) as RackEntity))
constructor(i: Int, inv: Inventory, container: Container) : super(Menus.RACK_MENU.get(), i, container) {
for(i in 0..3) {
val slot = RackSlot(container, i, 20, 23+i*20)
this.addSlot(slot)
}
this.addInventorySlots(inv, 8, 128)
}
}

View File

@@ -0,0 +1,85 @@
package org.neoflock.neocomputers.gui.menu
import com.mojang.blaze3d.systems.RenderSystem
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.renderer.GameRenderer
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.Container
import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.block.RelayEntity
import org.neoflock.neocomputers.gui.widget.ComponentRoles
import org.neoflock.neocomputers.gui.widget.DynamicSlot
import org.neoflock.neocomputers.item.ComponentItem
import org.neoflock.neocomputers.item.RelayUpgrade
import org.neoflock.neocomputers.utils.GenericContainerMenu
class RelaySlot(container: Container, slot: Int, x: Int, y: Int, val role: String, val relay: RelayEntity?) : DynamicSlot(container, slot, x, y) {
override fun mayPlace(stack: ItemStack): Boolean {
if(stack.isEmpty) return true
val upgrade = stack.item as? RelayUpgrade ?: return false
if(containerSlot == RelayEntity.CARD) {
return upgrade.isRelayCompatibleCard(stack)
}
if(containerSlot == RelayEntity.CPU) {
return upgrade.getRelayInterval(stack) != null
}
if(containerSlot == RelayEntity.MEM) {
return upgrade.getRelayBufferSize(stack) != null
}
if(containerSlot == RelayEntity.STORAGE) {
return upgrade.getRelayQueueSize(stack) != null
}
return false
}
override fun set(stack: ItemStack) {
super.set(stack)
val item = stack.item
if(item is ComponentItem) {
item.whenComponentPlaced(stack, relay, role)
}
}
override fun onTake(player: Player, stack: ItemStack) {
super.onTake(player, stack)
val item = stack.item
if(item is ComponentItem) {
item.whenComponentTaken(stack, relay, role)
}
}
override fun getMaxStackSize() = 1
override fun getMaxStackSize(stack: ItemStack) = 1
override fun draw(graphics: GuiGraphics, mouseX: Int, mouseY: Int) {
super.draw(graphics, mouseX, mouseY)
if(!hasItem()) {
drawQuad(graphics, ComponentRoles.getTextureFor(role), x-1, y-1, 18, 18, 0f, 0f, 15f, 15f)
}
}
}
class RelayMenu : GenericContainerMenu {
constructor(i: Int, inv: Inventory) : this(i, inv, SimpleContainer(RelayEntity.SLOT_COUNT))
constructor(i: Int, inv: Inventory, container: Container) : super(Menus.RELAY_MENU.get(), i, container) {
val relay = container as? RelayEntity
val relayMenuWidth = 176
val itemX = 152
val itemRowDist = 16
val itemSpacing = 20
this.addSlot(RelaySlot(container, RelayEntity.CARD, relayMenuWidth+4, itemRowDist, ComponentRoles.NETWORK, relay))
this.addSlot(RelaySlot(container, RelayEntity.CPU, itemX, itemRowDist, ComponentRoles.COMPUTE, relay))
this.addSlot(RelaySlot(container, RelayEntity.MEM, itemX, itemRowDist+itemSpacing, ComponentRoles.MEMORY, relay))
this.addSlot(RelaySlot(container, RelayEntity.STORAGE, itemX, itemRowDist+itemSpacing*2, ComponentRoles.STORAGE, relay))
this.addInventorySlots(inv, 8, 84)
}
}

View File

@@ -13,7 +13,7 @@ import java.io.File
import kotlin.experimental.and import kotlin.experimental.and
import kotlin.experimental.xor import kotlin.experimental.xor
class BufferRenderer(private var id: ResourceLocation, private var buffer: TextBuffer) { // TODO: NN buffer class BufferRenderer(private var id: ResourceLocation, var buffer: TextBuffer) { // TODO: NN buffer
val CHARW = 8 val CHARW = 8
val CHARH = 16 val CHARH = 16
@@ -26,15 +26,11 @@ class BufferRenderer(private var id: ResourceLocation, private var buffer: TextB
Minecraft.getInstance().textureManager.register(this.id, tex) Minecraft.getInstance().textureManager.register(this.id, tex)
} }
fun dump(path: String) { fun toRGBA(color: Int): Int {
image.writeToFile(File(path)) // Minecaft lies, its AGBR
NeoComputers.LOGGER.info("DUMPED!!!") return java.lang.Integer.reverseBytes((color.toLong() * 256 + 0xFF).toInt())
} }
// fun toRGBA(color: Int): Int {
// return color.shl(8).or(0xFF)
// }
fun drawGlyph(x: Int, y: Int, c: Char, fg: Int) { fun drawGlyph(x: Int, y: Int, c: Char, fg: Int) {
var glyph: ArrayList<Byte> = FontProvider.map[c]!! var glyph: ArrayList<Byte> = FontProvider.map[c]!!
@@ -42,7 +38,7 @@ class BufferRenderer(private var id: ResourceLocation, private var buffer: TextB
for (i in 0..<CHARW) { for (i in 0..<CHARW) {
// var pixel = ((glyph[j] and ((1 shl (CHARW - i - 1)).toByte())).toInt()) ushr (CHARW - i - 1) // retardation // var pixel = ((glyph[j] and ((1 shl (CHARW - i - 1)).toByte())).toInt()) ushr (CHARW - i - 1) // retardation
var pixel = (glyph[j] and (0b10000000 ushr i).toByte()).toInt() var pixel = (glyph[j] and (0b10000000 ushr i).toByte()).toInt()
if (pixel > 0) image.setPixelRGBA(x+i, y+j, 0xFF000000.toInt()+fg) if (pixel > 0) image.setPixelRGBA(x+i, y+j, toRGBA(fg))
} }
} }
} }
@@ -53,7 +49,7 @@ class BufferRenderer(private var id: ResourceLocation, private var buffer: TextB
var char: GPUChar = buffer.get(i, j) var char: GPUChar = buffer.get(i, j)
var x = i*CHARW var x = i*CHARW
var y = j*CHARH var y = j*CHARH
image.fillRect(x, y, CHARW, CHARH, (0xFF000000+char.bg).toInt()) image.fillRect(x, y, CHARW, CHARH, toRGBA(char.bg))
if (char.c != ' ' && char.c != '\u0000') drawGlyph(x, y, char.c, char.fg) if (char.c != ' ' && char.c != '\u0000') drawGlyph(x, y, char.c, char.fg)
} }
} }

View File

@@ -0,0 +1,39 @@
package org.neoflock.neocomputers.gui.screen
import io.netty.buffer.Unpooled
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.player.Inventory
import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.gui.menu.AssemblerMenu
import org.neoflock.neocomputers.gui.menu.CaseMenu
import org.neoflock.neocomputers.gui.widget.ButtonSprites
import org.neoflock.neocomputers.gui.widget.ImagerButton
import org.neoflock.neocomputers.network.NodeSynchronizer
import org.neoflock.neocomputers.utils.GenericContainerScreen
class AssemblerScreen : GenericContainerScreen<AssemblerMenu> {
private var btn: ImagerButton? = null
private val PCB: ResourceLocation = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/gui/computer.png")
private val BTN: ResourceLocation = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/gui/button_power.png")
constructor(abstractContainerMenu: AssemblerMenu, inventory: Inventory, component: Component) : super(abstractContainerMenu, inventory, component) {
btn = ImagerButton(
8, 104,
18, 18,
ButtonSprites(BTN, 18, 18, 36, 36)
) {
// val buf = FriendlyByteBuf(Unpooled.buffer())
// buf.writeByte(if(isOn) 0x02 else 0x01)
// NodeSynchronizer.sendScreenInteraction(buf)
}
addWidget(btn!!)
}
override fun renderbg(guiGraphics: GuiGraphics, f: Float, i: Int, j: Int) {
guiGraphics.blit(PCB, 0, 0, 0, 0, this.imageWidth, this.imageHeight) // WE'RE FREE
}
}

View File

@@ -11,7 +11,7 @@ import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.inventory.tooltip.TooltipComponent import net.minecraft.world.inventory.tooltip.TooltipComponent
import net.minecraft.world.phys.Vec3 import net.minecraft.world.phys.Vec3
import org.neoflock.neocomputers.NeoComputers import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.block.NodeSynchronizer import org.neoflock.neocomputers.network.NodeSynchronizer
import org.neoflock.neocomputers.gui.menu.CaseMenu import org.neoflock.neocomputers.gui.menu.CaseMenu
import org.neoflock.neocomputers.gui.widget.ButtonSprites import org.neoflock.neocomputers.gui.widget.ButtonSprites
import org.neoflock.neocomputers.gui.widget.ImagerButton import org.neoflock.neocomputers.gui.widget.ImagerButton
@@ -26,6 +26,7 @@ class CaseScreen : GenericContainerScreen<CaseMenu> {
private var btn: ImagerButton? = null private var btn: ImagerButton? = null
override fun shouldCenterTitle(): Boolean = false override fun shouldCenterTitle(): Boolean = false
// override fun findMenuTexture(): ResourceLocation = BG
var isOn = false var isOn = false
var lastError: String? = null var lastError: String? = null
@@ -70,14 +71,14 @@ class CaseScreen : GenericContainerScreen<CaseMenu> {
if(hasShiftDown()) { if(hasShiftDown()) {
msgs.addLast(Component.translatable("neocomputers.computer.energy", energy, maxEnergy).withStyle(if(energy < maxEnergy/5) ChatFormatting.RED else ChatFormatting.WHITE)) msgs.addLast(Component.translatable("neocomputers.computer.energy", energy, maxEnergy).withStyle(if(energy < maxEnergy/5) ChatFormatting.RED else ChatFormatting.WHITE))
msgs.addLast(Component.translatable("neocomputers.computer.memory", Formatting.formatMemory(memory), Formatting.formatMemory(maxMemory))) msgs.addLast(Component.translatable("neocomputers.computer.memory", Formatting.formatMemory(memory), Formatting.formatMemory(maxMemory)))
msgs.addLast(Component.translatable("neocomputers.computer.components", components, maxEnergy).withStyle(if(components <= maxComponents) ChatFormatting.WHITE else ChatFormatting.RED)) msgs.addLast(Component.translatable("neocomputers.computer.components", components, maxComponents).withStyle(if(components <= maxComponents) ChatFormatting.WHITE else ChatFormatting.RED))
} }
return msgs return msgs
} }
constructor(abstractContainerMenu: CaseMenu, inventory: Inventory, component: Component) : super(abstractContainerMenu, inventory, component) { constructor(abstractContainerMenu: CaseMenu, inventory: Inventory, component: Component) : super(abstractContainerMenu, inventory, component) {
btn = ImagerButton( btn = ImagerButton(
15, 15, 71, 33,
18, 18, 18, 18,
ButtonSprites(BTN, 18, 18, 36, 36) ButtonSprites(BTN, 18, 18, 36, 36)
) { ) {
@@ -85,17 +86,11 @@ class CaseScreen : GenericContainerScreen<CaseMenu> {
buf.writeByte(if(isOn) 0x02 else 0x01) buf.writeByte(if(isOn) 0x02 else 0x01)
NodeSynchronizer.sendScreenInteraction(buf) 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 addWidget(btn!!)
btn!!.y = relY+33 }
btn!!.render(guiGraphics, i, j, f) // minecraft SUCKSSS override fun renderbg(guiGraphics: GuiGraphics, f: Float, i: Int, j: Int) {
guiGraphics.blit(PCB, relX, relY, 0, 0, this.imageWidth, this.imageHeight) 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) { 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

@@ -0,0 +1,51 @@
package org.neoflock.neocomputers.gui.screen
import net.minecraft.ChatFormatting
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.Style
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.item.DyeColor
import org.neoflock.neocomputers.gui.menu.RelayMenu
import org.neoflock.neocomputers.utils.GenericContainerScreen
import kotlin.math.max
import kotlin.math.min
class RelayScreen(abstractContainerMenu: RelayMenu, inventory: Inventory, component: Component): GenericContainerScreen<RelayMenu>(abstractContainerMenu, inventory, component) {
var interval: Int = 5
var bufferSize: Int = 1
var queueSize: Int = 20
var inQueue: Int = 0
override fun shouldCenterTitle(): Boolean = false
override fun processScreenStatePacket(buf: FriendlyByteBuf) {
super.processScreenStatePacket(buf)
interval = buf.readVarInt()
bufferSize = buf.readVarInt()
queueSize = buf.readVarInt()
inQueue = buf.readVarInt()
}
override fun render(graphics: GuiGraphics, mouseX: Int, mouseY: Int, something: Float) {
super.render(graphics, mouseX, mouseY, something)
val textX = imageX + 12
val dataX = imageX + 100
val textSpacing = 20
val textY = imageY + 20
val clr = ChatFormatting.DARK_GRAY.color!!
graphics.drawString(this.font, "Cycle rate", textX, textY, clr, false)
graphics.drawString(this.font, "Packets / cycle", textX, textY + textSpacing, clr, false)
graphics.drawString(this.font, "Queue Size", textX, textY + textSpacing*2, clr, false)
val hz = if(interval == 0) 20 else 20 / interval
val buffered = min(inQueue, bufferSize)
val queued = max(inQueue - bufferSize, 0)
graphics.drawString(this.font, "$hz Hz", dataX, textY, clr, false)
graphics.drawString(this.font, "$buffered / $bufferSize", dataX, textY + textSpacing, clr, false)
graphics.drawString(this.font, "$queued / $queueSize", dataX, textY + textSpacing * 2, clr, false)
}
}

View File

@@ -24,6 +24,8 @@ class ScreenScreen : GenericContainerScreen<ScreenMenu>{
var textBuf = TextBuffer(0, 0) var textBuf = TextBuffer(0, 0)
override fun shouldCenterTitle(): Boolean = false
override fun processScreenStatePacket(buf: FriendlyByteBuf) { override fun processScreenStatePacket(buf: FriendlyByteBuf) {
super.processScreenStatePacket(buf) super.processScreenStatePacket(buf)
textBuf.decodeContents(buf) textBuf.decodeContents(buf)
@@ -44,6 +46,8 @@ class ScreenScreen : GenericContainerScreen<ScreenMenu>{
} }
} }
override fun renderLabels(guiGraphics: GuiGraphics, mouseX: Int, mouseY: Int) { }
// override fun onClose() { // override fun onClose() {
// super.onClose() // super.onClose()
// renderer. // renderer.

View File

@@ -6,11 +6,9 @@ import net.minecraft.client.renderer.GameRenderer
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.world.Container import net.minecraft.world.Container
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.ItemLike
import org.neoflock.neocomputers.NeoComputers import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.entity.MachineEntity import org.neoflock.neocomputers.entity.ComponentUser
import org.neoflock.neocomputers.item.ComponentItem import org.neoflock.neocomputers.item.ComponentItem
// Sort of a mis-nomer, does not need to be associated with components specifically // Sort of a mis-nomer, does not need to be associated with components specifically
@@ -85,14 +83,11 @@ data class ComponentSlotRequirement(val tier: Int, val role: String) {
// Tier 0 allows ALL tiers, making it completely untiered. // Tier 0 allows ALL tiers, making it completely untiered.
// Role determines what the role is. // Role determines what the role is.
class ComponentSlot(container: Container, slot: Int, x: Int, y: Int, val machine: MachineEntity?, val requirement: ComponentSlotRequirement): DynamicSlot(container, slot, x, y) { class ComponentSlot(container: Container, slot: Int, x: Int, y: Int, val machine: ComponentUser?, var requirement: ComponentSlotRequirement): DynamicSlot(container, slot, x, y) {
override fun draw(graphics: GuiGraphics, relX: Int, relY: Int, mouseX: Int, mouseY: Int) { override fun draw(graphics: GuiGraphics, mouseX: Int, mouseY: Int) {
super.draw(graphics, relX, relY, mouseX, mouseY) super.draw(graphics, mouseX, mouseY)
if(!hasItem()) { if(!hasItem()) {
RenderSystem.enableBlend() drawQuad(graphics, ComponentRoles.getTextureFor(requirement.role), x - 1, y - 1, 18, 18, 0F, 0F, 15F, 15F)
RenderSystem.setShaderTexture(0, ComponentRoles.getTextureFor(requirement.role))
RenderSystem.setShader { GameRenderer.getPositionTexShader() }
drawQuad(relX + x - 1, relY + y - 1, 18, 18, 0F, 0F, 15F, 15F)
if (requirement.tier > 0) { if (requirement.tier > 0) {
RenderSystem.setShaderTexture( RenderSystem.setShaderTexture(
0, 0,
@@ -101,10 +96,11 @@ class ComponentSlot(container: Container, slot: Int, x: Int, y: Int, val machine
"textures/gui/slots/tier${requirement.tier - 1}.png" "textures/gui/slots/tier${requirement.tier - 1}.png"
) )
) )
RenderSystem.setShader { GameRenderer.getPositionTexShader() } val tex = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/gui/slots/tier${requirement.tier - 1}.png")
drawQuad(relX + x - 1, relY + y - 1, 18, 18, 0F, 0F, 15F, 15F) // RenderSystem.setShader { GameRenderer.getPositionTexShader() }
drawQuad(graphics, tex, x - 1, y - 1, 18, 18, 0F, 0F, 15F, 15F)
} }
RenderSystem.disableBlend() // RenderSystem.disableBlend()
} }
} }

View File

@@ -5,41 +5,43 @@ import com.mojang.blaze3d.vertex.BufferBuilder
import com.mojang.blaze3d.vertex.BufferUploader import com.mojang.blaze3d.vertex.BufferUploader
import com.mojang.blaze3d.vertex.DefaultVertexFormat import com.mojang.blaze3d.vertex.DefaultVertexFormat
import com.mojang.blaze3d.vertex.Tesselator import com.mojang.blaze3d.vertex.Tesselator
import com.mojang.blaze3d.vertex.VertexConsumer
import com.mojang.blaze3d.vertex.VertexFormat import com.mojang.blaze3d.vertex.VertexFormat
import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.renderer.GameRenderer 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.client.renderer.RenderType
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.world.Container import net.minecraft.world.Container
import net.minecraft.world.inventory.Slot import net.minecraft.world.inventory.Slot
import org.neoflock.neocomputers.NeoComputers import org.neoflock.neocomputers.NeoComputers
open class DynamicSlot(container: Container, slot: Int, x: Int, y: Int) : Slot(container, slot, x, y) { open class DynamicSlot(container: Container, slot: Int, x: Int, y: Int, var active: Boolean = true) : Slot(container, slot, x, y) {
val BACKGROUND: ResourceLocation = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/gui/slots/slot.png") val BACKGROUND: ResourceLocation = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/gui/slots/slot.png")
val RENDER_TYPE = { r: ResourceLocation ->
open fun draw(graphics: GuiGraphics, relX: Int, relY: Int, mouseX: Int, mouseY: Int) { RenderType.create("nc_gui_slot", DefaultVertexFormat.POSITION_TEX, VertexFormat.Mode.QUADS, RenderType.TRANSIENT_BUFFER_SIZE, RenderType.CompositeState.builder()
RenderSystem.enableBlend() // background .setShaderState(ShaderStateShard.POSITION_TEX_SHADER)
RenderSystem.setShaderTexture(0, BACKGROUND) .setTextureState(RenderStateShard.TextureStateShard(r, false, false))
RenderSystem.setShader { GameRenderer.getPositionTexShader() } .setTransparencyState(RenderStateShard.TransparencyStateShard.TRANSLUCENT_TRANSPARENCY)
drawQuad(relX+x-1, relY+y-1, 18, 18, 0F, 0F, 15F, 15F) .createCompositeState(false))
RenderSystem.disableBlend()
} }
fun drawQuad(x: Int, y: Int, width: Int, height: Int, u1: Float, v1: Float, u2: Float, v2: Float) { open fun draw(graphics: GuiGraphics, mouseX: Int, mouseY: Int) {
var t: Tesselator = Tesselator.getInstance() drawQuad(graphics, BACKGROUND, x-1, y-1, 18, 18, 0F, 0F, 15F, 15F)
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()!!)
} }
// private fun renderSlotHighlight(guiGraphics: GuiGraphics, x: Int, y: Int, k: Int) { // im not sure but i tihnk i copied this from mc source code fun drawQuad(guiGraphics: GuiGraphics, tex: ResourceLocation, x: Int, y: Int, width: Int, height: Int, u1: Float, v1: Float, u2: Float, v2: Float) {
// guiGraphics.fillGradient(RenderType.guiOverlay(), x, y, x + 16, y + 16, -2130706433, -2130706433, k); val pose = guiGraphics.pose().last()
// } val builder = guiGraphics.bufferSource().getBuffer(RENDER_TYPE(tex))
builder.addVertex(pose, x.toFloat(), (y+height).toFloat(), 1f).setUv(u1/15F, v2/15F)
builder.addVertex(pose, (x+width).toFloat(), (y+height).toFloat(), 1f).setUv(u2/15F, v2/15F)
builder.addVertex(pose, (x+width).toFloat(), y.toFloat(), 1f).setUv(u2/15F, v1/15F)
builder.addVertex(pose, x.toFloat(), y.toFloat(), 1f).setUv(u1/15F,v1/15F)
}
override fun isActive() = active
} }

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

@@ -2,9 +2,8 @@ package org.neoflock.neocomputers.item
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import org.neoflock.neocomputers.entity.MachineEntity import org.neoflock.neocomputers.entity.ComponentUser
import org.neoflock.neocomputers.gui.widget.ComponentRoles import org.neoflock.neocomputers.gui.widget.ComponentRoles
import org.neoflock.neocomputers.network.Networking
open class CBUSItem(val tier: Int, val maxComponents: Int): Item(Item.Properties()), ComponentItem { open class CBUSItem(val tier: Int, val maxComponents: Int): Item(Item.Properties()), ComponentItem {
override fun getComponentRoles(itemStack: ItemStack) = setOf(ComponentRoles.BUS) override fun getComponentRoles(itemStack: ItemStack) = setOf(ComponentRoles.BUS)
@@ -13,7 +12,7 @@ open class CBUSItem(val tier: Int, val maxComponents: Int): Item(Item.Properties
override fun getComponentCapacity(itemStack: ItemStack) = maxComponents override fun getComponentCapacity(itemStack: ItemStack) = maxComponents
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
} }
class CBUS0: CBUSItem(1, 8) class CBUS0: CBUSItem(1, 8)
class CBUS1: CBUSItem(2, 12) class CBUS1: CBUSItem(2, 12)

View File

@@ -2,11 +2,10 @@ package org.neoflock.neocomputers.item
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import org.neoflock.neocomputers.entity.MachineEntity import org.neoflock.neocomputers.entity.ComponentUser
import org.neoflock.neocomputers.gui.widget.ComponentRoles import org.neoflock.neocomputers.gui.widget.ComponentRoles
import org.neoflock.neocomputers.network.Networking
open class CPUItem(val tier: Int, val maxComponents: Int): Item(Item.Properties()), ComponentItem { open class CPUItem(val tier: Int, val maxComponents: Int): Item(Item.Properties()), RelayUpgrade {
override fun getComponentRoles(itemStack: ItemStack): Set<String> = setOf(ComponentRoles.COMPUTE) override fun getComponentRoles(itemStack: ItemStack): Set<String> = setOf(ComponentRoles.COMPUTE)
override fun getComponentTier(itemStack: ItemStack): Int = tier override fun getComponentTier(itemStack: ItemStack): Int = tier
@@ -15,7 +14,9 @@ open class CPUItem(val tier: Int, val maxComponents: Int): Item(Item.Properties(
override fun getArchitecturesProvided(itemStack: ItemStack): Set<String> = setOf("Lua 5.3") override fun getArchitecturesProvided(itemStack: ItemStack): Set<String> = setOf("Lua 5.3")
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
override fun getRelayInterval(itemStack: ItemStack) = 4 / tier
} }
class CPU0: CPUItem(1, 8) class CPU0: CPUItem(1, 8)

View File

@@ -1,6 +1,7 @@
package org.neoflock.neocomputers.item package org.neoflock.neocomputers.item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import org.neoflock.neocomputers.entity.ComponentUser
import org.neoflock.neocomputers.entity.MachineEntity import org.neoflock.neocomputers.entity.MachineEntity
import org.neoflock.neocomputers.entity.MachineEvent import org.neoflock.neocomputers.entity.MachineEvent
import org.neoflock.neocomputers.network.DeviceNode import org.neoflock.neocomputers.network.DeviceNode
@@ -18,7 +19,7 @@ interface ComponentItem {
fun getArchitecturesProvided(itemStack: ItemStack): Set<String> = setOf() fun getArchitecturesProvided(itemStack: ItemStack): Set<String> = setOf()
// Component placed, node must now exist // Component placed, node must now exist
fun whenComponentPlaced(itemStack: ItemStack, machine: MachineEntity?, newRole: String) { fun whenComponentPlaced(itemStack: ItemStack, machine: ComponentUser?, newRole: String) {
val oldNode = getComponentNode(itemStack) val oldNode = getComponentNode(itemStack)
if(oldNode != null) Networking.removeNode(oldNode) // did a mod forget to call whenComponentTaken? if(oldNode != null) Networking.removeNode(oldNode) // did a mod forget to call whenComponentTaken?
val node = toComponentNode(itemStack, machine) ?: return val node = toComponentNode(itemStack, machine) ?: return
@@ -27,14 +28,14 @@ interface ComponentItem {
} }
// Component taken, and thus removed // Component taken, and thus removed
fun whenComponentTaken(itemStack: ItemStack, machine: MachineEntity?, previousRole: String) { fun whenComponentTaken(itemStack: ItemStack, machine: ComponentUser?, previousRole: String) {
val node = getComponentNode(itemStack) ?: return val node = getComponentNode(itemStack) ?: return
// removing disconnects // removing disconnects
Networking.removeNode(node) Networking.removeNode(node)
} }
// To node, if applicable. Meant to create the node, but not add it, as it will use the itemStack's address to find it again // To node, if applicable. Meant to create the node, but not add it, as it will use the itemStack's address to find it again
fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?): DeviceNode? fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?): DeviceNode?
// Gets the node associated to an item, if it exists // Gets the node associated to an item, if it exists
fun getComponentNode(itemStack: ItemStack): DeviceNode? { fun getComponentNode(itemStack: ItemStack): DeviceNode? {
@@ -52,3 +53,11 @@ interface ComponentItem {
fun onMachineEvent(itemStack: ItemStack, machine: MachineEntity, event: MachineEvent) {} fun onMachineEvent(itemStack: ItemStack, machine: MachineEntity, event: MachineEvent) {}
} }
// A special ComponentItem which specifies upgrades specific to the relay
interface RelayUpgrade: ComponentItem {
fun getRelayInterval(itemStack: ItemStack): Int? = null
fun getRelayBufferSize(itemStack: ItemStack): Int? = null
fun getRelayQueueSize(itemStack: ItemStack): Int? = null
fun isRelayCompatibleCard(itemStack: ItemStack): Boolean = false
}

View File

@@ -4,9 +4,8 @@ import net.minecraft.network.chat.Component
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag import net.minecraft.world.item.TooltipFlag
import org.neoflock.neocomputers.entity.MachineEntity import org.neoflock.neocomputers.entity.ComponentUser
import org.neoflock.neocomputers.gui.widget.ComponentRoles import org.neoflock.neocomputers.gui.widget.ComponentRoles
import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.utils.Formatting import org.neoflock.neocomputers.utils.Formatting
// Note: We'll prob want to replace them with NN component configs later on // Note: We'll prob want to replace them with NN component configs later on
@@ -16,13 +15,13 @@ open class DataCard(val tier: Int, val limit: Long): Item(Properties()), Compone
override fun getComponentTier(itemStack: ItemStack): Int = tier override fun getComponentTier(itemStack: ItemStack): Int = tier
override fun whenComponentPlaced(itemStack: ItemStack, machine: MachineEntity?, newRole: String) { override fun whenComponentPlaced(itemStack: ItemStack, machine: ComponentUser?, newRole: String) {
if(machine != null) ensureHasAddress(itemStack) if(machine != null) ensureHasAddress(itemStack)
super.whenComponentPlaced(itemStack, machine, newRole) super.whenComponentPlaced(itemStack, machine, newRole)
} }
// TODO: Modem Component // TODO: Modem Component
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
override fun appendHoverText( override fun appendHoverText(
itemStack: ItemStack, itemStack: ItemStack,

View File

@@ -4,9 +4,8 @@ import net.minecraft.network.chat.Component
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag import net.minecraft.world.item.TooltipFlag
import org.neoflock.neocomputers.entity.MachineEntity import org.neoflock.neocomputers.entity.ComponentUser
import org.neoflock.neocomputers.gui.widget.ComponentRoles import org.neoflock.neocomputers.gui.widget.ComponentRoles
import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.utils.Formatting import org.neoflock.neocomputers.utils.Formatting
import java.nio.ByteBuffer import java.nio.ByteBuffer
@@ -27,12 +26,12 @@ open class EEPROMItem(val tier: Int, val codeCapacity: Int, val dataCapacity: In
override fun getComponentCapacity(itemStack: ItemStack): Int = 0 override fun getComponentCapacity(itemStack: ItemStack): Int = 0
override fun whenComponentPlaced(itemStack: ItemStack, machine: MachineEntity?, newRole: String) { override fun whenComponentPlaced(itemStack: ItemStack, machine: ComponentUser?, newRole: String) {
if(machine != null) ensureHasAddress(itemStack) if(machine != null) ensureHasAddress(itemStack)
super.whenComponentPlaced(itemStack, machine, newRole) super.whenComponentPlaced(itemStack, machine, newRole)
} }
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
override fun appendHoverText( override fun appendHoverText(
itemStack: ItemStack, itemStack: ItemStack,

View File

@@ -4,9 +4,8 @@ import net.minecraft.network.chat.Component
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag import net.minecraft.world.item.TooltipFlag
import org.neoflock.neocomputers.entity.MachineEntity import org.neoflock.neocomputers.entity.ComponentUser
import org.neoflock.neocomputers.gui.widget.ComponentRoles import org.neoflock.neocomputers.gui.widget.ComponentRoles
import org.neoflock.neocomputers.network.Networking
// Note: We'll prob want to replace them with NN component configs later on // Note: We'll prob want to replace them with NN component configs later on
@@ -15,13 +14,13 @@ open class GPUCard(val tier: Int, val vram: Long): Item(Properties()), Component
override fun getComponentTier(itemStack: ItemStack): Int = tier override fun getComponentTier(itemStack: ItemStack): Int = tier
override fun whenComponentPlaced(itemStack: ItemStack, machine: MachineEntity?, newRole: String) { override fun whenComponentPlaced(itemStack: ItemStack, machine: ComponentUser?, newRole: String) {
if(machine != null) ensureHasAddress(itemStack) if(machine != null) ensureHasAddress(itemStack)
super.whenComponentPlaced(itemStack, machine, newRole) super.whenComponentPlaced(itemStack, machine, newRole)
} }
// TODO: GPU Component // TODO: GPU Component
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
override fun appendHoverText( override fun appendHoverText(
itemStack: ItemStack, itemStack: ItemStack,

View File

@@ -4,17 +4,15 @@ import net.minecraft.network.chat.Component
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag import net.minecraft.world.item.TooltipFlag
import org.neoflock.neocomputers.entity.MachineEntity import org.neoflock.neocomputers.entity.ComponentUser
import org.neoflock.neocomputers.gui.widget.ComponentRoles import org.neoflock.neocomputers.gui.widget.ComponentRoles
import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.utils.Formatting import org.neoflock.neocomputers.utils.Formatting
import java.util.UUID
fun getDiskProperties(): Item.Properties = Item.Properties() fun getDiskProperties(): Item.Properties = Item.Properties()
.component(DataComponents.LABEL, "") .component(DataComponents.LABEL, "")
.component(DataComponents.READONLY, false) .component(DataComponents.READONLY, false)
open class HardDiskItem(val tier: Int, val capacity: Long): Item(getDiskProperties()), ComponentItem { open class HardDiskItem(val tier: Int, val capacity: Long, val relayQueueSize: Int): Item(getDiskProperties()), RelayUpgrade {
override fun getComponentRoles(itemStack: ItemStack): Set<String> = setOf(ComponentRoles.STORAGE) override fun getComponentRoles(itemStack: ItemStack): Set<String> = setOf(ComponentRoles.STORAGE)
override fun getComponentTier(itemStack: ItemStack): Int = tier override fun getComponentTier(itemStack: ItemStack): Int = tier
@@ -23,12 +21,12 @@ open class HardDiskItem(val tier: Int, val capacity: Long): Item(getDiskProperti
override fun getComponentCapacity(itemStack: ItemStack): Int = 0 override fun getComponentCapacity(itemStack: ItemStack): Int = 0
override fun whenComponentPlaced(itemStack: ItemStack, machine: MachineEntity?, newRole: String) { override fun whenComponentPlaced(itemStack: ItemStack, machine: ComponentUser?, newRole: String) {
if(machine != null) ensureHasAddress(itemStack) if(machine != null) ensureHasAddress(itemStack)
super.whenComponentPlaced(itemStack, machine, newRole) super.whenComponentPlaced(itemStack, machine, newRole)
} }
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
override fun appendHoverText( override fun appendHoverText(
itemStack: ItemStack, itemStack: ItemStack,
@@ -56,8 +54,10 @@ open class HardDiskItem(val tier: Int, val capacity: Long): Item(getDiskProperti
} }
return super.getName(itemStack) return super.getName(itemStack)
} }
override fun getRelayQueueSize(itemStack: ItemStack) = relayQueueSize
} }
class HardDisk0: HardDiskItem(1, 1 shl 20) class HardDisk0: HardDiskItem(1, 1 shl 20, 30)
class HardDisk1: HardDiskItem(2, 2 shl 20) class HardDisk1: HardDiskItem(2, 2 shl 20, 40)
class HardDisk2: HardDiskItem(3, 4 shl 20) class HardDisk2: HardDiskItem(3, 4 shl 20, 50)

View File

@@ -4,23 +4,21 @@ import net.minecraft.network.chat.Component
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag import net.minecraft.world.item.TooltipFlag
import org.neoflock.neocomputers.entity.MachineEntity import org.neoflock.neocomputers.entity.ComponentUser
import org.neoflock.neocomputers.gui.widget.ComponentRoles import org.neoflock.neocomputers.gui.widget.ComponentRoles
import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.utils.Formatting
class InternetCard: Item(Item.Properties()), ComponentItem { class InternetCard: Item(Item.Properties()), ComponentItem {
override fun getComponentRoles(itemStack: ItemStack): Set<String> = setOf(ComponentRoles.CARD, ComponentRoles.INET) override fun getComponentRoles(itemStack: ItemStack): Set<String> = setOf(ComponentRoles.CARD, ComponentRoles.INET)
override fun getComponentTier(itemStack: ItemStack): Int = 1 override fun getComponentTier(itemStack: ItemStack): Int = 2
override fun whenComponentPlaced(itemStack: ItemStack, machine: MachineEntity?, newRole: String) { override fun whenComponentPlaced(itemStack: ItemStack, machine: ComponentUser?, newRole: String) {
if(machine != null) ensureHasAddress(itemStack) if(machine != null) ensureHasAddress(itemStack)
super.whenComponentPlaced(itemStack, machine, newRole) super.whenComponentPlaced(itemStack, machine, newRole)
} }
// TODO: Internet Component // TODO: Internet Component
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
override fun appendHoverText( override fun appendHoverText(
itemStack: ItemStack, itemStack: ItemStack,

View File

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

View File

@@ -4,13 +4,11 @@ import net.minecraft.network.chat.Component
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag import net.minecraft.world.item.TooltipFlag
import org.neoflock.neocomputers.entity.MachineEntity import org.neoflock.neocomputers.entity.ComponentUser
import org.neoflock.neocomputers.gui.widget.ComponentRoles import org.neoflock.neocomputers.gui.widget.ComponentRoles
import org.neoflock.neocomputers.network.DeviceNode
import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.utils.Formatting import org.neoflock.neocomputers.utils.Formatting
open class MemoryItem(val tier: Int, val capacity: Int): Item(Item.Properties().`arch$tab`(Tabs.TAB)), ComponentItem { open class MemoryItem(val tier: Int, val capacity: Int, val relayBuf: Int): Item(Item.Properties().`arch$tab`(Tabs.TAB)), RelayUpgrade {
override fun getComponentRoles(itemStack: ItemStack) = setOf(ComponentRoles.MEMORY) override fun getComponentRoles(itemStack: ItemStack) = setOf(ComponentRoles.MEMORY)
override fun getComponentTier(itemStack: ItemStack): Int = tier override fun getComponentTier(itemStack: ItemStack): Int = tier
@@ -20,7 +18,7 @@ open class MemoryItem(val tier: Int, val capacity: Int): Item(Item.Properties().
override fun getComponentCapacity(itemStack: ItemStack): Int = 0 override fun getComponentCapacity(itemStack: ItemStack): Int = 0
// no node for memory // no node for memory
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
override fun appendHoverText( override fun appendHoverText(
itemStack: ItemStack, itemStack: ItemStack,
@@ -33,11 +31,13 @@ open class MemoryItem(val tier: Int, val capacity: Int): Item(Item.Properties().
} }
super.appendHoverText(itemStack, tooltipContext, list, tooltipFlag) super.appendHoverText(itemStack, tooltipContext, list, tooltipFlag)
} }
override fun getRelayBufferSize(itemStack: ItemStack) = relayBuf
} }
class MemoryTier1(): MemoryItem(1, 192 shl 10) class MemoryTier1(): MemoryItem(1, 192 shl 10, 2)
class MemoryTier1_5(): MemoryItem(1, 256 shl 10) class MemoryTier1_5(): MemoryItem(1, 256 shl 10, 3)
class MemoryTier2(): MemoryItem(2, 384 shl 10) class MemoryTier2(): MemoryItem(2, 384 shl 10, 4)
class MemoryTier2_5(): MemoryItem(2, 512 shl 10) class MemoryTier2_5(): MemoryItem(2, 512 shl 10, 5)
class MemoryTier3(): MemoryItem(3, 768 shl 10) class MemoryTier3(): MemoryItem(3, 768 shl 10, 6)
class MemoryTier3_5(): MemoryItem(3, 1 shl 20) class MemoryTier3_5(): MemoryItem(3, 1 shl 20, 7)

View File

@@ -4,22 +4,21 @@ import net.minecraft.network.chat.Component
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag import net.minecraft.world.item.TooltipFlag
import org.neoflock.neocomputers.entity.MachineEntity import org.neoflock.neocomputers.entity.ComponentUser
import org.neoflock.neocomputers.gui.widget.ComponentRoles import org.neoflock.neocomputers.gui.widget.ComponentRoles
import org.neoflock.neocomputers.network.Networking
open class NetworkCard(val tier: Int, val maxRange: Int, val isWired: Boolean): Item(Properties()), ComponentItem { open class NetworkCard(val tier: Int, val maxRange: Int, val isWired: Boolean): Item(Properties()), ComponentItem {
override fun getComponentRoles(itemStack: ItemStack): Set<String> = setOf(ComponentRoles.CARD, ComponentRoles.NETWORK) override fun getComponentRoles(itemStack: ItemStack): Set<String> = setOf(ComponentRoles.CARD, ComponentRoles.NETWORK)
override fun getComponentTier(itemStack: ItemStack): Int = tier override fun getComponentTier(itemStack: ItemStack): Int = tier
override fun whenComponentPlaced(itemStack: ItemStack, machine: MachineEntity?, newRole: String) { override fun whenComponentPlaced(itemStack: ItemStack, machine: ComponentUser?, newRole: String) {
if(machine != null) ensureHasAddress(itemStack) if(machine != null) ensureHasAddress(itemStack)
super.whenComponentPlaced(itemStack, machine, newRole) super.whenComponentPlaced(itemStack, machine, newRole)
} }
// TODO: Modem Component // TODO: Modem Component
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
override fun appendHoverText( override fun appendHoverText(
itemStack: ItemStack, itemStack: ItemStack,

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

@@ -4,9 +4,8 @@ import net.minecraft.network.chat.Component
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag import net.minecraft.world.item.TooltipFlag
import org.neoflock.neocomputers.entity.MachineEntity import org.neoflock.neocomputers.entity.ComponentUser
import org.neoflock.neocomputers.gui.widget.ComponentRoles import org.neoflock.neocomputers.gui.widget.ComponentRoles
import org.neoflock.neocomputers.network.Networking
// Note: We'll prob want to replace them with NN component configs later on // Note: We'll prob want to replace them with NN component configs later on
@@ -15,13 +14,13 @@ open class RedstoneCard(val tier: Int): Item(Properties()), ComponentItem {
override fun getComponentTier(itemStack: ItemStack): Int = tier override fun getComponentTier(itemStack: ItemStack): Int = tier
override fun whenComponentPlaced(itemStack: ItemStack, machine: MachineEntity?, newRole: String) { override fun whenComponentPlaced(itemStack: ItemStack, machine: ComponentUser?, newRole: String) {
if(machine != null) ensureHasAddress(itemStack) if(machine != null) ensureHasAddress(itemStack)
super.whenComponentPlaced(itemStack, machine, newRole) super.whenComponentPlaced(itemStack, machine, newRole)
} }
// TODO: Redstone Component // TODO: Redstone Component
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
override fun appendHoverText( override fun appendHoverText(
itemStack: ItemStack, itemStack: ItemStack,

View File

@@ -0,0 +1,27 @@
package org.neoflock.neocomputers.item
import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.entity.ItemRenderer
import net.minecraft.client.renderer.item.ItemProperties
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import org.neoflock.neocomputers.entity.ComponentUser
import org.neoflock.neocomputers.gui.widget.ComponentRoles
import org.neoflock.neocomputers.network.DeviceNode
class ServerItem() : Item(Properties()), ComponentItem, RackItem {
override fun getComponentRoles(itemStack: ItemStack): Set<String> = setOf(ComponentRoles.RACK_MOUNTABLE)
override fun getComponentTier(itemStack: ItemStack): Int = 0
override fun toComponentNode(
itemStack: ItemStack,
machine: ComponentUser?
): DeviceNode? {
return null // TODO: atom machine item plz
}
override fun render_lights(source: MultiBufferSource, stack: PoseStack, light: Int) {
}
}

View File

@@ -23,38 +23,9 @@ object Tabs {
ItemStack(Items.MEM0.get()) ItemStack(Items.MEM0.get())
} }
builder.displayItems { parameters, output -> builder.displayItems { parameters, output ->
// TODO: get rid of arch$tab and this shi and replace with loop over items registry Items.ITEMS.forEach {
output.accept(ItemStack(Items.CPU0.get())) output.accept(ItemStack(it.get()))
output.accept(ItemStack(Items.CPU1.get())) }
output.accept(ItemStack(Items.CPU2.get()))
output.accept(ItemStack(Items.CBUS0.get()))
output.accept(ItemStack(Items.CBUS1.get()))
output.accept(ItemStack(Items.CBUS2.get()))
output.accept(ItemStack(Items.CBUS_CREATIVE.get()))
output.accept(ItemStack(Items.DATA0.get()))
output.accept(ItemStack(Items.DATA1.get()))
output.accept(ItemStack(Items.DATA2.get()))
output.accept(ItemStack(Items.GPU0.get()))
output.accept(ItemStack(Items.GPU1.get()))
output.accept(ItemStack(Items.GPU2.get()))
output.accept(ItemStack(Items.HDD0.get()))
output.accept(ItemStack(Items.HDD1.get()))
output.accept(ItemStack(Items.HDD2.get()))
output.accept(ItemStack(Items.INET.get()))
output.accept(ItemStack(Items.TUNNEL.get()))
output.accept(ItemStack(Items.LAN.get()))
output.accept(ItemStack(Items.WLAN0.get()))
output.accept(ItemStack(Items.WLAN1.get()))
output.accept(ItemStack(Items.REDIO0.get()))
output.accept(ItemStack(Items.REDIO1.get()))
output.accept(ItemStack(Items.EE0.get()))
// Criminal black magic to put LuaBIOS EEPROM in the tabs // Criminal black magic to put LuaBIOS EEPROM in the tabs
do { do {

View File

@@ -4,9 +4,8 @@ import net.minecraft.network.chat.Component
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag import net.minecraft.world.item.TooltipFlag
import org.neoflock.neocomputers.entity.MachineEntity import org.neoflock.neocomputers.entity.ComponentUser
import org.neoflock.neocomputers.gui.widget.ComponentRoles import org.neoflock.neocomputers.gui.widget.ComponentRoles
import org.neoflock.neocomputers.network.Networking
class TunnelCard: Item(Properties().component(DataComponents.TUNNEL_CHANNEL, "creative")), ComponentItem { class TunnelCard: Item(Properties().component(DataComponents.TUNNEL_CHANNEL, "creative")), ComponentItem {
// yes, we're counting TUNNEL as a conventional networking card // yes, we're counting TUNNEL as a conventional networking card
@@ -14,13 +13,13 @@ class TunnelCard: Item(Properties().component(DataComponents.TUNNEL_CHANNEL, "cr
override fun getComponentTier(itemStack: ItemStack): Int = 3 override fun getComponentTier(itemStack: ItemStack): Int = 3
override fun whenComponentPlaced(itemStack: ItemStack, machine: MachineEntity?, newRole: String) { override fun whenComponentPlaced(itemStack: ItemStack, machine: ComponentUser?, newRole: String) {
if(machine != null) ensureHasAddress(itemStack) if(machine != null) ensureHasAddress(itemStack)
super.whenComponentPlaced(itemStack, machine, newRole) super.whenComponentPlaced(itemStack, machine, newRole)
} }
// TODO: Tunnel Component // TODO: Tunnel Component
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null override fun toComponentNode(itemStack: ItemStack, machine: ComponentUser?) = null
override fun appendHoverText( override fun appendHoverText(
itemStack: ItemStack, itemStack: ItemStack,

View File

@@ -1,7 +1,9 @@
package org.neoflock.neocomputers.network package org.neoflock.neocomputers.network
import net.minecraft.core.BlockPos
import net.minecraft.network.FriendlyByteBuf 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.NeoComputers
import org.neoflock.neocomputers.network.Networking.Message import org.neoflock.neocomputers.network.Networking.Message
import org.neoflock.neocomputers.network.Networking.Visibility import org.neoflock.neocomputers.network.Networking.Visibility
@@ -9,6 +11,9 @@ import org.neoflock.neocomputers.network.Networking.maxHopCount
import java.util.UUID import java.util.UUID
import kotlin.math.min import kotlin.math.min
// tmp class until JNI bindings work
data class NNComponent(val type: String)
open class DeviceNode(_address: UUID? = null) { open class DeviceNode(_address: UUID? = null) {
val connections = HashSet<DeviceNode>() val connections = HashSet<DeviceNode>()
private var reachableCache: Set<DeviceNode>? = null private var reachableCache: Set<DeviceNode>? = null
@@ -145,77 +150,84 @@ open class DeviceNode(_address: UUID? = null) {
fun getReachable(): Set<DeviceNode> { fun getReachable(): Set<DeviceNode> {
if(reachableCache == null) { if(reachableCache == null) {
reachableCache = computeReachable(); reachableCache = computeReachable()
} }
return reachableCache!!; return reachableCache!!
} }
open fun invalidateReachableCache() { open fun invalidateReachableCache() {
reachableCache = null 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> { fun computeReachable(): Set<DeviceNode> {
if(reachability == Visibility.NONE) { if(reachability == Visibility.NONE) {
return setOf(); return setOf()
} }
if(reachability == Visibility.DIRECT) { if(reachability == Visibility.SOME) {
return connections.minus(this); return getPreferredFew()
} }
if(reachability == Visibility.NETWORK) { if(reachability == Visibility.NETWORK) {
// absolute cinema // absolute cinema
val working = HashSet<DeviceNode>(); val working = HashSet<DeviceNode>()
val pending = mutableListOf(this); val pending = mutableListOf(this)
var iterCount = 0; var iterCount = 0
while(iterCount < maxHopCount && pending.isNotEmpty()) { while(iterCount < maxHopCount && pending.isNotEmpty()) {
iterCount++; iterCount++
val subnode = pending.removeFirst() val subnode = pending.removeFirst()
if(subnode in working) continue if(subnode in working) continue
working.add(subnode) working.add(subnode)
if(subnode.reachability == Visibility.NETWORK) { if(subnode.reachability == Visibility.NETWORK) {
pending.addAll(subnode.connections) pending.addAll(subnode.connections)
} else if(subnode.reachability == Visibility.DIRECT) { } else if(subnode.reachability == Visibility.SOME) {
working.addAll(subnode.connections) pending.addAll(subnode.getPreferredFew())
} }
} }
// cannot send to itself! // cannot send to itself!
working.remove(this); working.remove(this)
return working; return working
} }
throw NotImplementedError("visibility not implemented"); throw NotImplementedError("visibility not implemented")
} }
fun connectTo(other: DeviceNode) { fun connectTo(other: DeviceNode) {
this.directConnectTo(other); this.directConnectTo(other)
other.directConnectTo(this); other.directConnectTo(this)
} }
fun disconnectFrom(other: DeviceNode) { fun disconnectFrom(other: DeviceNode) {
this.directDisconnectFrom(other); this.directDisconnectFrom(other)
other.directDisconnectFrom(this); other.directDisconnectFrom(this)
} }
fun directConnectTo(other: DeviceNode) { fun directConnectTo(other: DeviceNode) {
if(other == this) return; if(other == this) return
if(other in connections) return; if(other in connections) return
connections.add(other); connections.add(other)
this.onConnect(other); this.onConnect(other)
invalidateReachableCache()
} }
fun directDisconnectFrom(other: DeviceNode) { fun directDisconnectFrom(other: DeviceNode) {
if(other !in connections) return; if(other !in connections) return
connections.remove(other); connections.remove(other)
this.onDisconnect(other); this.onDisconnect(other)
invalidateReachableCache()
} }
// Network synchronization with the NodeSynchronizer // Network synchronization with the NodeSynchronizer
// TODO: process shi // TODO: process shi
var outOfSync = true var outOfSync = false
fun markChanged() { fun markChanged() {
outOfSync = true outOfSync = true
} }
open fun encodeScreenData(buf: FriendlyByteBuf) {} open fun encodeScreenData(player: ServerPlayer, buf: FriendlyByteBuf) {}
open fun processScreenInteraction(player: ServerPlayer, buf: FriendlyByteBuf) {}
// Meant to write the entire state as a single commit // Meant to write the entire state as a single commit
// for clients which say they have no fucking idea what the server is storing // for clients which say they have no fucking idea what the server is storing
@@ -223,13 +235,22 @@ open class DeviceNode(_address: UUID? = null) {
// client-side, meant to bring state forward // client-side, meant to bring state forward
open fun processCommit(buf: FriendlyByteBuf) {} open fun processCommit(buf: FriendlyByteBuf) {}
open fun getComponent(): NNComponent? = null
}
// Used by the relay
// If the ComponentItem in the card slot
interface ConventionalNetworkDevice {
fun sendClassicPacket(packet: Networking.ClassicPacket)
} }
abstract class WirelessEndpoint(address: UUID?) : DeviceNode(address) { abstract class WirelessEndpoint(address: UUID?) : DeviceNode(address) {
abstract fun getRange(): Double abstract fun getEndpointRange(): Double
abstract fun getDimension(): Int abstract fun getEndpointDimension(): Int
abstract fun getPosition(): BlockPos abstract fun getEndpointLevel(): Level
abstract fun getEndpointPosition(): Vec3
// separate from process for simplicity // separate from process for simplicity
abstract fun receiveWireless(message: Message, emitter: WirelessEndpoint) abstract fun receiveWireless(message: Message, emitter: WirelessEndpoint)
} }

View File

@@ -1,6 +1,7 @@
package org.neoflock.neocomputers.network package org.neoflock.neocomputers.network
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.world.level.Level
import org.neoflock.neocomputers.entity.MachineEvent import org.neoflock.neocomputers.entity.MachineEvent
import java.util.UUID import java.util.UUID
import kotlin.math.min import kotlin.math.min
@@ -27,8 +28,8 @@ object Networking {
enum class Visibility { enum class Visibility {
// only it can see itself // only it can see itself
NONE, NONE,
// can only see its direct connections // some, as determined by getPreferredFew()
DIRECT, SOME,
// Can see everything network-wide // Can see everything network-wide
NETWORK, NETWORK,
} }
@@ -36,8 +37,9 @@ object Networking {
abstract class Message(val sender: DeviceNode) 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
fun hop() = ClassicPacket(sender, src, dst, port, data, hopCount + 1); class ClassicPacket(sender: DeviceNode, val src: String, val dst: String?, val port: Int, val data: List<Any>, val hopCount: Int) : Message(sender) {
fun hop(sender: DeviceNode) = ClassicPacket(sender, src, dst, port, data, hopCount + 1);
} }
// for plugins and shi // for plugins and shi
@@ -50,30 +52,26 @@ object Networking {
// node may differ from message.sender in the case of relays, // node may differ from message.sender in the case of relays,
// as they might have DIRECT reachability but // as they might have DIRECT reachability but
fun emitMessage(deviceNode: DeviceNode, message: Message) { fun emitMessage(deviceNode: DeviceNode, message: Message, exclude: Set<DeviceNode> = setOf()) {
deviceNode.getReachable().forEach { it.received(message) } 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 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) { fun emitWirelessMessage(starter: WirelessEndpoint, range: Double, message: Message) {
val startPos = starter.getPosition(); val startPos = starter.getEndpointPosition()
val startDim = starter.getDimension(); val startDim = starter.getEndpointDimension()
val range = starter.getRange(); val level = starter.getEndpointLevel()
wirelessNodes.get().forEach { wirelessNodes.get().forEach {
if(it.getDimension() != startDim) return; if(it.getEndpointDimension() != startDim) return
val pos = it.getPosition(); val pos = it.getEndpointPosition()
val d = distanceBetween(startPos, pos); val d = startPos.distanceTo(pos)
var trueRange = min(it.getRange(), range); var trueRange = min(it.getEndpointRange(), range)
trueRange = min(trueRange, computeRangeAllowedByHardness(startPos, pos)); trueRange = min(trueRange, computeRangeAllowedByHardness(level, BlockPos.containing(startPos), BlockPos.containing(pos)))
if(d > trueRange) return; if(d > trueRange) return
it.receiveWireless(message, starter); it.receiveWireless(message, starter)
} }
} }
@@ -85,12 +83,14 @@ object Networking {
fun getNode(address: UUID): DeviceNode? = allNodes.get()[address] fun getNode(address: UUID): DeviceNode? = allNodes.get()[address]
// TODO: use setter, more convenient // TODO: use setter, more convenient
fun changeNodeAddress(deviceNode: DeviceNode, address: UUID) { fun changeNodeAddress(deviceNode: DeviceNode, address: UUID): Boolean {
if(deviceNode.address.equals(address)) return if(deviceNode.address.equals(address)) return false
if(deviceNode.address !in allNodes.get()) return if(deviceNode.address !in allNodes.get()) return false
if(address in allNodes.get()) return false
allNodes.get().remove(deviceNode.address) allNodes.get().remove(deviceNode.address)
deviceNode.address = address deviceNode.address = address
allNodes.get()[address] = deviceNode allNodes.get()[address] = deviceNode
return true
} }
fun addNode(deviceNode: DeviceNode) { fun addNode(deviceNode: DeviceNode) {
@@ -103,12 +103,17 @@ object Networking {
allNodes.get().forEach { it.value.onNodeAdded(deviceNode) } allNodes.get().forEach { it.value.onNodeAdded(deviceNode) }
} }
fun addNodes(vararg deviceNodes: DeviceNode) { fun addNodes(deviceNodes: Iterable<DeviceNode>) {
deviceNodes.forEach { addNode(it) } deviceNodes.forEach { addNode(it) }
} }
fun addNodes(vararg deviceNodes: DeviceNode) {
addNodes(deviceNodes.asIterable())
}
fun removeNode(deviceNode: DeviceNode) { fun removeNode(deviceNode: DeviceNode) {
if(deviceNode.address !in allNodes.get()) return if(deviceNode.address !in allNodes.get()) return
NodeSynchronizer.nodeErased(deviceNode)
allNodes.get().forEach { it.value.onNodeRemoved(deviceNode) } allNodes.get().forEach { it.value.onNodeRemoved(deviceNode) }
// toList() in order to copy it // toList() in order to copy it
deviceNode.connections.toList().forEach { deviceNode.connections.toList().forEach {
@@ -121,10 +126,14 @@ object Networking {
} }
} }
fun removeNodes(vararg deviceNodes: DeviceNode) { fun removeNodes(deviceNodes: Iterable<DeviceNode>) {
deviceNodes.forEach { removeNode(it) } deviceNodes.forEach { removeNode(it) }
} }
fun removeNodes(vararg deviceNodes: DeviceNode) {
removeNodes(deviceNodes.asIterable())
}
val channels = ThreadLocal.withInitial { HashMap<String, MutableSet<DeviceNode>>() } val channels = ThreadLocal.withInitial { HashMap<String, MutableSet<DeviceNode>>() }
fun addToChannel(channel: String, deviceNode: DeviceNode) { fun addToChannel(channel: String, deviceNode: DeviceNode) {

View File

@@ -0,0 +1,171 @@
package org.neoflock.neocomputers.network
import dev.architectury.networking.NetworkManager
import io.netty.buffer.Unpooled
import net.minecraft.core.BlockPos
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.network.codec.StreamCodec
import net.minecraft.network.protocol.common.custom.CustomPacketPayload
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.level.Level
import org.neoflock.neocomputers.NeoComputers
import java.time.Duration
object NodeSynchronizer {
val MAX_STATE_DISTANCE_ALLOWED = 128
class DeviceBlockStatePayload(var blockPos: BlockPos, var buffers: List<FriendlyByteBuf>): CustomPacketPayload {
companion object {
val BLOCKDEV_SYNC_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "blockdev_sync")
val TYPE = CustomPacketPayload.Type<DeviceBlockStatePayload>(BLOCKDEV_SYNC_ID)
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, DeviceBlockStatePayload> {
override fun decode(buf: RegistryFriendlyByteBuf): DeviceBlockStatePayload {
val blockPos = buf.readBlockPos()
val bufferCount = buf.readVarInt()
val buffers = List(bufferCount) {
val bytes = buf.readByteArray()
val rawBuf = Unpooled.buffer(bytes.size)
rawBuf.writeBytes(bytes)
FriendlyByteBuf(rawBuf)
}
return DeviceBlockStatePayload(blockPos, buffers)
}
override fun encode(buf: RegistryFriendlyByteBuf, payload: DeviceBlockStatePayload) {
buf.writeBlockPos(payload.blockPos)
buf.writeVarInt(payload.buffers.size)
payload.buffers.forEach {
buf.writeByteArray(it.array())
}
}
}
}
override fun type() = TYPE
}
class DeviceBlockStateRequest(var blockPos: BlockPos): CustomPacketPayload {
companion object {
val BLOCKDEV_REQ_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "blockdev_statereq")
val TYPE = CustomPacketPayload.Type<DeviceBlockStateRequest>(BLOCKDEV_REQ_ID)
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, DeviceBlockStateRequest> {
override fun decode(buf: RegistryFriendlyByteBuf): DeviceBlockStateRequest {
val blockPos = buf.readBlockPos()
return DeviceBlockStateRequest(blockPos)
}
override fun encode(buf: RegistryFriendlyByteBuf, payload: DeviceBlockStateRequest) {
buf.writeBlockPos(payload.blockPos)
}
}
}
override fun type() = TYPE
}
class ScreenPayload(var buffer: FriendlyByteBuf): CustomPacketPayload {
companion object {
val SCREEN_SYNC_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "screen_sync")
val TYPE = CustomPacketPayload.Type<ScreenPayload>(SCREEN_SYNC_ID)
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, ScreenPayload> {
override fun decode(buf: RegistryFriendlyByteBuf): ScreenPayload {
val buffer = FriendlyByteBuf(buf.copy(buf.readerIndex(), buf.readableBytes()))
return ScreenPayload(buffer)
}
override fun encode(buf: RegistryFriendlyByteBuf, payload: ScreenPayload) {
buf.writeBytes(payload.buffer)
}
}
}
override fun type() = TYPE
}
class ScreenDataPayload(var buffer: FriendlyByteBuf): CustomPacketPayload {
companion object {
val SCREEN_DATA_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "screen_data")
val TYPE = CustomPacketPayload.Type<ScreenDataPayload>(SCREEN_DATA_ID)
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, ScreenDataPayload> {
override fun decode(buf: RegistryFriendlyByteBuf): ScreenDataPayload {
val buffer = FriendlyByteBuf(buf.copy(buf.readerIndex(), buf.readableBytes()))
return ScreenDataPayload(buffer)
}
override fun encode(buf: RegistryFriendlyByteBuf, payload: ScreenDataPayload) {
buf.writeBytes(payload.buffer)
}
}
}
override fun type() = TYPE
}
class BeepDataPayload(val pos: BlockPos, val pattern: String, val freq: Int, val duration: Duration, val volume: Double): CustomPacketPayload {
companion object {
val BEEP_DATA_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "beep_data")
val TYPE = CustomPacketPayload.Type<BeepDataPayload>(BEEP_DATA_ID)
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, BeepDataPayload> {
override fun decode(buf: RegistryFriendlyByteBuf): BeepDataPayload {
val pos = buf.readBlockPos()
val pattern = buf.readUtf()
val freq = buf.readVarInt()
val duration = buf.readVarLong()
val volume = buf.readDouble()
return BeepDataPayload(pos, pattern, freq, Duration.ofMillis(duration), volume)
}
override fun encode(buf: RegistryFriendlyByteBuf, payload: BeepDataPayload) {
buf.writeBlockPos(payload.pos)
buf.writeUtf(payload.pattern)
buf.writeVarInt(payload.freq)
buf.writeVarLong(payload.duration.toMillis())
buf.writeDouble(payload.volume)
}
}
}
override fun type() = TYPE
}
val screenMap = HashMap<ServerPlayer, DeviceNode>()
fun playerScreenClosed(player: ServerPlayer) {
screenMap.remove(player)
}
fun registerPlayerScreen(player: ServerPlayer, devNode: DeviceNode) {
screenMap[player] = devNode
}
fun nodeErased(node: DeviceNode) {
var player: ServerPlayer? = null
for((p, n) in screenMap) {
if(n == node) player = p
}
if(player != null) screenMap.remove(player)
}
fun syncScreens() {
for((player, ent) in screenMap) {
val buf = FriendlyByteBuf(Unpooled.buffer())
ent.encodeScreenData(player, buf)
NetworkManager.sendToPlayer(player, ScreenPayload(buf))
}
}
fun sendScreenInteraction(friendlyByteBuf: FriendlyByteBuf) {
NetworkManager.sendToServer(ScreenDataPayload(friendlyByteBuf))
}
fun emitBeep(level: Level, beepDataPayload: BeepDataPayload) {
if(level is ServerLevel) {
level.players().forEach {
NetworkManager.sendToPlayer(it, beepDataPayload)
}
}
}
}

View File

@@ -1,42 +1,46 @@
package org.neoflock.neocomputers.network package org.neoflock.neocomputers.network
import net.minecraft.world.level.block.entity.BlockEntityType import net.minecraft.world.level.block.entity.BlockEntityType
import org.neoflock.neocomputers.block.DeviceBlockEntity
//? if fabric { //? if fabric {
import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext /*import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext
import org.neoflock.neocomputers.block.NodeBlockEntity import net.minecraft.core.Direction
import team.reborn.energy.api.EnergyStorage; import team.reborn.energy.api.EnergyStorage;
//?} *///?}
// our soul purpose is to fuse bullshit power APIs together // our soul purpose is to fuse bullshit power APIs together
// the NodeBlockEntity and Node given us a way to get power from a block, we just // the NodeBlockEntity and Node given us a way to get power from a block, we just
// need to tell mods how to do it as well // need to tell mods how to do it as well
object PowerManager { object PowerManager {
fun<T: NodeBlockEntity> registerPowerBlockEntity(blockEntityType: BlockEntityType<T>) { fun<T: DeviceBlockEntity> registerPowerDevice(blockEntityType: BlockEntityType<T>) {
//? if fabric { //? if fabric {
EnergyStorage.SIDED.registerForBlockEntity({ /*EnergyStorage.SIDED.registerForBlockEntity({
entity, dir -> object : EnergyStorage { // TODO: as this is currently written, if the node instance changes and the mod cached the conversion, we're boned. Consider fixing it.
override fun getAmount() = entity.deviceNode.energy entity, dir ->
override fun getCapacity() = entity.deviceNode.energyCapacity val node = entity.getNodeFromSide(dir ?: Direction.UP)
override fun supportsExtraction() = entity.deviceNode.powerRole != PowerRole.CONSUMER && entity.deviceNode.energyCapacity > 0 if(node == null) null else object : EnergyStorage {
override fun supportsInsertion() = entity.deviceNode.powerRole != PowerRole.GENERATOR override fun getAmount() = node.energy
override fun extract(maxAmount: Long, transaction: TransactionContext?): Long { override fun getCapacity() = node.energyCapacity
if(entity.deviceNode.powerRole == PowerRole.CONSUMER) return 0 override fun supportsExtraction() = node.powerRole != PowerRole.CONSUMER && node.energyCapacity > 0
val taken = entity.deviceNode.withdrawEnergy(maxAmount) override fun supportsInsertion() = node.powerRole != PowerRole.GENERATOR
transaction?.addCloseCallback { override fun extract(maxAmount: Long, transaction: TransactionContext?): Long {
ctx, res -> if(res.wasAborted() || !res.wasCommitted()) entity.deviceNode.giveEnergy(taken) if(node.powerRole == PowerRole.CONSUMER) return 0
val taken = node.withdrawEnergy(maxAmount)
transaction?.addCloseCallback {
ctx, res -> if(res.wasAborted() || !res.wasCommitted()) node.giveEnergy(taken)
}
return taken
} }
return taken override fun insert(maxAmount: Long, transaction: TransactionContext?): Long {
} if(node.powerRole == PowerRole.GENERATOR) return 0
override fun insert(maxAmount: Long, transaction: TransactionContext?): Long { val given = node.giveEnergy(maxAmount)
if(entity.deviceNode.powerRole == PowerRole.GENERATOR) return 0 transaction?.addCloseCallback { ctx, res ->
val given = entity.deviceNode.giveEnergy(maxAmount) if (res.wasAborted() || !res.wasCommitted()) node.withdrawEnergy(given)
transaction?.addCloseCallback { ctx, res -> }
if (res.wasAborted() || !res.wasCommitted()) entity.deviceNode.withdrawEnergy(given) return given
} }
return given
} }
}
}, blockEntityType); }, blockEntityType);
//?} *///?}
} }
} }

View File

@@ -1,9 +1,16 @@
package org.neoflock.neocomputers.utils package org.neoflock.neocomputers.utils
// based off the ImplementedContainer of https://docs.fabricmc.net/develop/blocks/block-containers // 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 dev.architectury.registry.menu.MenuRegistry
import net.minecraft.client.gui.GuiGraphics 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.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.world.Container;
import net.minecraft.core.NonNullList; import net.minecraft.core.NonNullList;
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
@@ -68,7 +75,7 @@ abstract class GenericContainerMenu(menuType: MenuType<*>, id: Int, var containe
// Based off the code in ChestMenu // Based off the code in ChestMenu
for (i in 0..2) { for (i in 0..2) {
for (j in 0..8) { 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 val imageY: Int
get() = (height - imageHeight) / 2 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() { override fun init() {
super.init() super.init()
@@ -138,24 +154,50 @@ abstract class GenericContainerScreen<T: GenericContainerMenu>(menu: T, inventor
val menuTex = findMenuTexture() val menuTex = findMenuTexture()
val cx = (width - imageWidth) / 2 val cx = (width - imageWidth) / 2
val cy = (height - imageHeight) / 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) { for (slot in menu.slots) {
if (slot is DynamicSlot) { if (slot is DynamicSlot) {
// NeoComputers.LOGGER.info("slot") slot.draw(guiGraphics, i-cx, j-cy)
slot.draw(guiGraphics, cx, cy, i, j)
} }
} }
guiGraphics.pose().popPose()
} }
open fun renderCustomOverlay(graphics: GuiGraphics, mouseX: Int, mouseY: Int, blend: Float) { open fun renderbg(guiGraphics: GuiGraphics, partialTick: Float, mouseX: Int, mouseY: Int) {}
} open fun renderCustomOverlay(graphics: GuiGraphics, mouseX: Int, mouseY: Int, blend: Float) { }
override fun render(graphics: GuiGraphics, mouseX: Int, mouseY: Int, something: Float) { override fun render(graphics: GuiGraphics, mouseX: Int, mouseY: Int, something: Float) {
super.render(graphics, mouseX, mouseY, something) 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) 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

@@ -1,14 +1,73 @@
package org.neoflock.neocomputers.utils package org.neoflock.neocomputers.utils
import com.mojang.blaze3d.platform.NativeImage
import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.texture.DynamicTexture
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.util.ResourceLocationPattern
import org.neoflock.neocomputers.gui.widget.DynamicSlot
import kotlin.experimental.and
import kotlin.math.min import kotlin.math.min
data class GPUChar(val c: Char, val fg: Int =0xFFFFFF, val bg: Int = 0) // all is bgr data class GPUChar(val c: Char, val fg: Int =0xFFFFFF, val bg: Int = 0) // all is bgr
// TODO: wrapper over NN buffer // TODO: wrapper over NN buffer
class TextBuffer(var width: Int, var height: Int) { class TextBuffer(var width: Int, var height: Int) {
// val CHARW = 8
// val CHARH = 16
//
// val texwidth: Int
// get() = width*CHARW
//
// val texheight: Int
// get() = height*CHARH
//
// var image = NativeImage(texwidth, texheight, true)
// var tex = DynamicTexture(image)
val blank = GPUChar(' ') val blank = GPUChar(' ')
var buf = Array(width*height) { blank } var buf = Array(width*height) { blank }
// init {
// Minecraft.getInstance().textureManager.register(this.id, tex)
// }
// fun toRGBA(color: Int): Int {
// // Minecaft lies, its AGBR
// return java.lang.Integer.reverseBytes((color.toLong() * 256 + 0xFF).toInt())
// }
//
// fun drawGlyph(x: Int, y: Int, c: Char, fg: Int) {
// var glyph: ArrayList<Byte> = FontProvider.map[c]!!
//
// for (j in 0..<CHARH) {
// for (i in 0..<CHARW) {
// // var pixel = ((glyph[j] and ((1 shl (CHARW - i - 1)).toByte())).toInt()) ushr (CHARW - i - 1) // retardation
// var pixel = (glyph[j] and (0b10000000 ushr i).toByte()).toInt()
// if (pixel > 0) image.setPixelRGBA(x+i, y+j, toRGBA(fg))
// }
// }
// }
//
// fun drawBuffer() {
// for (i in 0..<width) {
// for (j in 0..<height) {
// var char: GPUChar = buf[j*height+i]
// var x = i*CHARW
// var y = j*CHARH
// image.fillRect(x, y, CHARW, CHARH, toRGBA(char.bg))
// if (char.c != ' ' && char.c != '\u0000') drawGlyph(x, y, char.c, char.fg)
// }
// }
// tex.upload()
// }
//
// fun clean() {
// Minecraft.getInstance().textureManager.release(this.id)
// image.close()
// tex.close()
// }
fun encodeContents(buf: FriendlyByteBuf) { fun encodeContents(buf: FriendlyByteBuf) {
// 0x01 means set fg, 0x02 means set bg, // 0x01 means set fg, 0x02 means set bg,
@@ -75,16 +134,19 @@ class TextBuffer(var width: Int, var height: Int) {
fun inBounds(x: Int, y: Int) = x >= 0 && y >= 0 && x < width && y < height fun inBounds(x: Int, y: Int) = x >= 0 && y >= 0 && x < width && y < height
fun get(x: Int, y: Int) = if(inBounds(x, y)) buf[x+y*width] else blank fun get(x: Int, y: Int) = if(inBounds(x, y)) buf[x+y*width] else blank
fun set(x: Int, y: Int, pixel: GPUChar) { fun _set(x: Int, y: Int, pixel: GPUChar) {
if(!inBounds(x, y)) return if(!inBounds(x, y)) return
buf[x+y*width] = pixel buf[x+y*width] = pixel
// image.fillRect(x, y, CHARW, CHARH, toRGBA(pixel.bg))
// if (pixel.c != ' ' && pixel.c != '\u0000') drawGlyph(x, y, pixel.c, pixel.fg)
} }
fun set(x: Int, y: Int, text: String, fg: Int = 0xFFFFFF, bg: Int = 0x000000, vertical: Boolean = false) { fun set(x: Int, y: Int, text: String, fg: Int = 0xFFFFFF, bg: Int = 0x000000, vertical: Boolean = false) {
for ((i, c) in text.toCharArray().withIndex()) { for ((i, c) in text.toCharArray().withIndex()) {
val cx = if(vertical) x else x + i val cx = if(vertical) x else x + i
val cy = if(vertical) y + i else y val cy = if(vertical) y + i else y
set(cx, cy, GPUChar(c, fg, bg)) _set(cx, cy, GPUChar(c, fg, bg))
} }
// tex.upload()
} }
fun fill(x: Int, y: Int, w: Int, h: Int, pixel: GPUChar = blank) { fun fill(x: Int, y: Int, w: Int, h: Int, pixel: GPUChar = blank) {
// turn it into values we can fw // turn it into values we can fw
@@ -92,8 +154,9 @@ class TextBuffer(var width: Int, var height: Int) {
val fh = min(h, height) val fh = min(h, height)
for(py in y..<y+fh) { for(py in y..<y+fh) {
for (px in x..<x + fw) { for (px in x..<x + fw) {
set(px, py, pixel) _set(px, py, pixel)
} }
} }
// tex.upload()
} }
} }

View File

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

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

@@ -10,6 +10,9 @@
"block.neocomputers.capacitor": "Small Capacitor", "block.neocomputers.capacitor": "Small Capacitor",
"block.neocomputers.capacitor2": "Medium Capacitor", "block.neocomputers.capacitor2": "Medium Capacitor",
"block.neocomputers.capacitor3": "Large Capacitor", "block.neocomputers.capacitor3": "Large Capacitor",
"block.neocomputers.case": "Case (Untiered)",
"block.neocomputers.cable": "Cable",
"block.neocomputers.relay": "Relay",
"item.neocomputers.eeprom0": "EEPROM (Tier 1)", "item.neocomputers.eeprom0": "EEPROM (Tier 1)",
"item.neocomputers.cpu0": "CPU (Tier 1)", "item.neocomputers.cpu0": "CPU (Tier 1)",
"item.neocomputers.cpu1": "CPU (Tier 2)", "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

@@ -11,6 +11,9 @@
"block.neocomputers.capacitor": "Condensator Electric Mic", "block.neocomputers.capacitor": "Condensator Electric Mic",
"block.neocomputers.capacitor2": "Condensator Electric Mediu", "block.neocomputers.capacitor2": "Condensator Electric Mediu",
"block.neocomputers.capacitor3": "Condensator Electric Mare", "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.eeprom0": "Memorie Programabilă Electronic (Grad 1)",
"item.neocomputers.cpu0": "Procesor Central (Grad 1)", "item.neocomputers.cpu0": "Procesor Central (Grad 1)",
"item.neocomputers.cpu1": "Procesor Central (Grad 2)", "item.neocomputers.cpu1": "Procesor Central (Grad 2)",

View File

@@ -0,0 +1,44 @@
{
"parent": "block/block",
"textures": {
"bottom": "neocomputers:block/generic_top",
"top": "neocomputers:block/assembler_top",
"side": "neocomputers:block/assembler_side",
"particle": "neocomputers:block/generic_top"
},
"elements": [
{ "from": [ 0, 0, 0 ],
"to": [ 16, 7, 16 ],
"faces": {
"up": { "uv": [ 0, 0, 16, 16 ], "texture": "#top" },
"down": { "uv": [ 0, 0, 16, 16 ], "texture": "#bottom" },
"north": { "uv": [ 0, 0, 16, 7 ], "texture": "#side" },
"south": { "uv": [ 0, 0, 16, 7 ], "texture": "#side" },
"west": { "uv": [ 0, 0, 16, 7 ], "texture": "#side" },
"east": { "uv": [ 0, 0, 16, 7 ], "texture": "#side" }
}
},
{ "from": [ 2, 7, 2 ],
"to": [ 14, 9, 14 ],
"faces": {
"up": { "uv": [ 2, 2, 14, 14 ], "texture": "#top" },
"down": { "uv": [ 2, 2, 14, 14 ], "texture": "#bottom" },
"north": { "uv": [ 2, 7, 14, 9 ], "texture": "#side" },
"south": { "uv": [ 2, 7, 14, 9 ], "texture": "#side" },
"west": { "uv": [ 2, 7, 14, 9 ], "texture": "#side" },
"east": { "uv": [ 2, 7, 14, 9 ], "texture": "#side" }
}
},
{ "from": [ 0, 9, 0 ],
"to": [ 16, 16, 16 ],
"faces": {
"up": { "uv": [ 0, 0, 16, 16 ], "texture": "#top" },
"down": { "uv": [ 0, 0, 16, 16 ], "texture": "#bottom" },
"north": { "uv": [ 0, 9, 16, 16 ], "texture": "#side" },
"south": { "uv": [ 0, 9, 16, 16 ], "texture": "#side" },
"west": { "uv": [ 0, 9, 16, 16 ], "texture": "#side" },
"east": { "uv": [ 0, 9, 16, 16 ], "texture": "#side" }
}
}
]
}

View File

@@ -2,7 +2,8 @@
"parent": "minecraft:block/block", "parent": "minecraft:block/block",
"render_type": "minecraft:solid", "render_type": "minecraft:solid",
"textures": { "textures": {
"cap": "neocomputers:block/cable_cap" "cap": "neocomputers:block/cable_cap",
"particle": "neocomputers:block/cable_cap"
}, },
"elements": [ "elements": [
{ {

View File

@@ -2,7 +2,8 @@
"parent": "minecraft:block/block", "parent": "minecraft:block/block",
"render_type": "minecraft:solid", "render_type": "minecraft:solid",
"textures": { "textures": {
"cap": "neocomputers:block/cable_cap" "cap": "neocomputers:block/cable_cap",
"particle": "neocomputers:block/cable_cap"
}, },
"elements": [ "elements": [
{ {

View File

@@ -2,19 +2,20 @@
"parent": "minecraft:block/block", "parent": "minecraft:block/block",
"render_type": "minecraft:solid", "render_type": "minecraft:solid",
"textures": { "textures": {
"cap": "neocomputers:block/cable_body" "body": "neocomputers:block/cable_body",
"particle": "neocomputers:block/cable_cap"
}, },
"elements": [ "elements": [
{ {
"from": [6, 6, 6], "from": [6, 6, 6],
"to": [10, 10, 10], "to": [10, 10, 10],
"faces": { "faces": {
"north": { "uv": [6,6,10,10], "texture": "#cap" }, "north": { "uv": [6,6,10,10], "texture": "#body", "tintindex": 0 },
"east": { "uv": [6,6,10,10], "texture": "#cap" }, "east": { "uv": [6,6,10,10], "texture": "#body", "tintindex": 0 },
"west": { "uv": [6,6,10,10], "texture": "#cap" }, "west": { "uv": [6,6,10,10], "texture": "#body", "tintindex": 0 },
"south": { "uv": [6,6,10,10], "texture": "#cap" }, "south": { "uv": [6,6,10,10], "texture": "#body", "tintindex": 0 },
"up": { "uv": [0,0, 5, 5], "texture": "#cap" }, "up": { "uv": [0,0, 5, 5], "texture": "#body", "tintindex": 0 },
"down": { "uv": [0,0, 5, 5], "texture": "#cap" } "down": { "uv": [0,0, 5, 5], "texture": "#body", "tintindex": 0 }
} }
} }
] ]

View File

@@ -3,18 +3,19 @@
"render_type": "minecraft:solid", "render_type": "minecraft:solid",
"textures": { "textures": {
"cap": "neocomputers:block/cable_cap", "cap": "neocomputers:block/cable_cap",
"body": "neocomputers:block/cable_body" "body": "neocomputers:block/cable_body",
"particle": "neocomputers:block/cable_cap"
}, },
"elements": [ "elements": [
{ {
"from": [6, 6, 10], "from": [6, 6, 10],
"to": [10, 10, 16], "to": [10, 10, 16],
"faces": { "faces": {
"east": { "uv": [4,4,11,11], "texture": "#body" }, "east": { "uv": [4,4,11,11], "texture": "#body", "tintindex": 0 },
"west": { "uv": [4,4,11,11], "texture": "#body" }, "west": { "uv": [4,4,11,11], "texture": "#body", "tintindex": 0 },
"up": { "uv": [4,4,11,11], "texture": "#body" }, "up": { "uv": [4,4,11,11], "texture": "#body", "tintindex": 0 },
"down": { "uv": [4,4,11,11], "texture": "#body" }, "down": { "uv": [4,4,11,11], "texture": "#body", "tintindex": 0 },
"south": { "uv": [6, 6, 10, 10], "texture": "#cap"} "south": { "uv": [6, 6, 10, 10], "texture": "#cap", "tintindex": 0}
} }
} }
] ]

View File

@@ -3,24 +3,25 @@
"render_type": "minecraft:solid", "render_type": "minecraft:solid",
"textures": { "textures": {
"cap": "neocomputers:block/cable_cap", "cap": "neocomputers:block/cable_cap",
"body": "neocomputers:block/cable_body" "body": "neocomputers:block/cable_body",
"particle": "neocomputers:block/cable_cap"
}, },
"elements": [ "elements": [
{ {
"from": [6, -2, 6], "from": [6, 1, 6],
"to": [10, 18, 10], "to": [10, 15, 10],
"faces": { "faces": {
"east": { "uv": [0,0,5,16], "texture": "#body" }, "east": { "uv": [0,0,5,16], "texture": "#body", "tintindex": 0 },
"west": { "uv": [0,0,5,16], "texture": "#body" }, "west": { "uv": [0,0,5,16], "texture": "#body", "tintindex": 0 },
"north": { "uv": [0,0,5,16], "texture": "#body" }, "north": { "uv": [0,0,5,16], "texture": "#body", "tintindex": 0 },
"south": { "uv": [0,0,5,16], "texture": "#body" }, "south": { "uv": [0,0,5,16], "texture": "#body", "tintindex": 0 },
"up": { "uv": [0,0,5,16], "texture": "#body" }, "up": { "uv": [0,0,5,16], "texture": "#body", "tintindex": 0 },
"down": { "uv": [0,0,5,16], "texture": "#body" } "down": { "uv": [0,0,5,16], "texture": "#body", "tintindex": 0 }
} }
}, },
{ {
"from": [4, -3, 4], "from": [4, 0, 4],
"to": [12, -2, 12], "to": [12, 1, 12],
"faces": { "faces": {
"east": { "uv": [0,0,4,4], "texture": "#cap" }, "east": { "uv": [0,0,4,4], "texture": "#cap" },
"west": { "uv": [0,0,4,4], "texture": "#cap" }, "west": { "uv": [0,0,4,4], "texture": "#cap" },
@@ -30,8 +31,8 @@
} }
}, },
{ {
"from": [4, 18, 4], "from": [4, 15, 4],
"to": [12, 19, 12], "to": [12, 16, 12],
"faces": { "faces": {
"east": { "uv": [0,0,4,4], "texture": "#cap" }, "east": { "uv": [0,0,4,4], "texture": "#cap" },
"west": { "uv": [0,0,4,4], "texture": "#cap" }, "west": { "uv": [0,0,4,4], "texture": "#cap" },

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

Some files were not shown because too many files have changed in this diff Show More