Jump to content

AnZaNaMa

Forge Modder
  • Posts

    161
  • Joined

  • Last visited

Posts posted by AnZaNaMa

  1. Not sure if this is the right thread, so move it if I'm in the wrong place.

     

    I'm working on updating an old mod to 1.15.2, which runs a RESTful HTTP server alongside the game server that allows outside services to query information.

     

    Originally, I had implemented this using Netty, because it is already included in any Minecraft game. However, I was unable to figure out how to get an HTTPS server running, and honestly Netty is too low-level for this project. It required like 10 different classes just to get a basic HTTP server running.

     

    I've been looking into different libraries, and it seems like the Spring framework is something that would help me implement a RESTful API without having to re-invent the wheel 20 times first. However, I have no idea if it would even be possible to set up a mod with Spring, or how I would distribute it. Spring has tutorials on its site for setting it up with Gradle, but the sections of the build.gradle it's having me modify don't even exist in the ForgeGradle build.gradle

     

    Can anyone help me figure out how to set this up, or suggest a different networking library that has easy HTTP/HTTPS server support?

  2. Oh wow I'm stupid. Yeah, originally I was just using the normal block class. Guess I forgot to change it after I made my custom block class. I've changed it to TradeTerminalBlock and that's solved my problems. However, I still have a couple of questions.

     

    First off, it seems like the game is somehow saving my blockstate's properties when I quit the world, but I haven't written anything to translate the blockstate into nbt or metadata or anything. How is this information saved, since getStateFromMeta and getMetaFromState no longer exist? If I were to create my own custom BlockState property, would it also auto-magically be saved, or do I need to implement something to accomplish that? Also, do i need to manually send packets to the client when a blockstate changes, or is that handled by the game automatically?

     

    One more thing: Who's in charge of maintaining the Forge ReadTheDocs? I'd be willing to help contribute to update them if needed, since they're so out of date, but I don't know a ton.

  3. I checked out the Loom, because it uses HorizontalBlock

     

    Loom BlockState:

    {
        "variants": {
            "facing=north": { "model": "block/loom" },
            "facing=south": { "model": "block/loom", "y": 180 },
            "facing=west":  { "model": "block/loom", "y": 270 },
            "facing=east":  { "model": "block/loom", "y": 90 }
        }
    }

     

    Loom Model:

    {
        "parent": "block/orientable",
        "textures": {
            "top": "block/loom_top",
            "bottom": "block/loom_bottom",
            "front": "block/loom_front",
            "side": "block/loom_side"
        }
    }

     

    As you can see, my blockstate is almost exactly the same as what's used in Vanilla, but for some reason, minecraft still isn't recognizing the BlockState property.

     

    Do I need to register my block to tell the game it uses that property somehow? I've implemented fillStateContainer, getStateForPlacement, and I set the default state in my constructor.

  4. Hello, I'm having some troubles getting simple BlockStates to work in 1.15.2 (forge 31.1.1). Currently, I'm trying to get a simple rotatable block. Originally, I tried using the official Forge ReadTheDocs, but I've noticed that the Forge documentation is SEVERAL MAJOR VERSIONS out of date. The readthedocs says that the documentation is for 1.15.x, but most of the information in there is clearly out of date. All of the references it makes use the old naming scheme, and it often tells you to use methods that no longer exist.

     

    I was following the instructions on the docs, but that tutorial says you have to implement getMetaFromState and getStateFromMeta, which are methods that don't exist in this version. I found Cabidoo's 1.15.2 example mod repository, so I've been trying to follow what they've done there with their ModFurnaceBlock.

     

    For some reason when the game loads, I get errors saying that 'facing' is an unknown blockstate property, even though it's one of the built-in ones.

     

    [22:48:40] [Server-Worker-2/WARN] [minecraft/ModelBakery]: Exception loading blockstate definition: 'smartshops:blockstates/trade_terminal.json' in resourcepack: 'Mod Resources' for variant: 'facing=south': Unknown blockstate property: 'facing'
    [22:48:40] [Server-Worker-2/WARN] [minecraft/ModelBakery]: Exception loading blockstate definition: 'smartshops:blockstates/trade_terminal.json' in resourcepack: 'Mod Resources' for variant: 'facing=east': Unknown blockstate property: 'facing'
    [22:48:40] [Server-Worker-2/WARN] [minecraft/ModelBakery]: Exception loading blockstate definition: 'smartshops:blockstates/trade_terminal.json' in resourcepack: 'Mod Resources' for variant: 'facing=north': Unknown blockstate property: 'facing'
    [22:48:40] [Server-Worker-2/WARN] [minecraft/ModelBakery]: Exception loading blockstate definition: 'smartshops:blockstates/trade_terminal.json' in resourcepack: 'Mod Resources' for variant: 'facing=west': Unknown blockstate property: 'facing'
    [22:48:40] [Server-Worker-2/WARN] [minecraft/ModelBakery]: Exception loading blockstate definition: 'smartshops:blockstates/trade_terminal.json' missing model for variant: 'smartshops:trade_terminal#'

     

    I'm assuming the last message is only a problem because the BlockState variants failed to load properly. Also, the texture shows up as a full cube with the purple and black missing texture in game.

     

    Here are the relevant files to my problem: TradeTerminalBlock, trade_terminal.json (blockstate file), trade_terminal.json (model file).

     

    Also, is there an updated version of the documentation anywhere, or even just a set of update notes, telling what's changed since whenever the last time the docs were updated was?

  5. Hello! I've noticed that newer versions of Forge like to dump out the entire registry when the game loads, which makes it annoying to try and read through the console while testing mods in my development environment. Is there a way to disable this registry dump, while still keeping the log level at DEBUG?

  6. I managed to figure it out. I had my @EventBusSubscriber wrong (had to subscribe to the client-specific bus for the FMLCommonSetupEvent). Because of that, the event handler wasn't firing, so the instance of the capability was never being injected with a value, so it was still null when I tried to use it.

     

    @Draco18s also, you were right. I was just passing an instance of my ILifeForce, when I needed to pass it a supplier. I ended up using a lambda supplier:

    @SubscribeEvent
    public static void onCommonSetupEvent(FMLCommonSetupEvent event) {
        CapabilityManager.INSTANCE.register(ILifeForce.class, new LifeForceStorage(), () -> new LifeForce());
    }

     

    • Like 1
  7. FIrst off, the file contents you gave for your model file for example_item.json look like a localization file. For regular rendering of an item, your src\main\resources\assets\fm\models\item\example_item.json would look something like this:

     

    {
      "parent": "item/generated",
      "textures": {
        "layer0": "modid:item/example_item"
      }
    }

     

    That "modid:item/example_item" is a resource location for the texture that will be used to draw layer0, which is the only layer in this case. Essentially, the "modid:item/example_item" refers to the texture for your item. With the way that resource locations work, your actual texture for the item should be located at src\main\resources\assets\fm\textures\item\example_item.png, rather than in the models folder.

     

    Also, I think you'll want to put that localization information in the file: src\main\resources\assets\fm\lang\en_us.json

     

    Edit: I feel like I should explain more.

    The "resources\assets\modid\models" folder contains files that describe the way an object in the game should look. Unless you're using more complicated rendering techniques, these files are in the form of .json files (which is part of a system that resulted from the changes made in 1.8). These models make references to the textures that will be used to draw items/blocks. The textures themselves (.png images) will be searched for in the "resources\assets\modid\textures" folder.

     

    You can find more information on models in the Forge Docs.

  8. Hello, I'm working on implementing a capability for living entities for a mod I'm working on and I've run into some trouble. I believe I've gotten most of it right, from what I've gathered from other threads here.

     

    The trouble I'm running into is when the AttachCapabilitiesEvent<Entity> I'm hooking into fires. When that event fires, I'm calling event.addCapability(), and the game crashes while it's attempting to create the new instance of my capability provider (ICapabilitySerializable), throwing a null pointer exception.

     

    Here, you can see my event listener for the AttachCapabilitiesEvent<Entity>, as well as the registration for my capability:

    @SubscribeEvent
    public static void onCommonSetup(FMLCommonSetupEvent event) {
        CapabilityManager.INSTANCE.register(ILifeForce.class, new LifeForceStorage(), LifeForce::new);
    }
    
    @SubscribeEvent
    public static void onAttachCapabilities(AttachCapabilitiesEvent<Entity> event) {
        if(event.getObject() instanceof LivingEntity) {
            event.addCapability(new ResourceLocation(LifePower.MODID, "lifeforce"), new LifeForceProvider());
            event.getObject().getCapability(LifeForceProvider.LIFE_FORCE_CAP).ifPresent((capability) -> {
                capability.set(Math.round(((LivingEntity) event.getObject()).getHealth()));
            });
        }
    }

     

    Here's the gist of the crash report:

    Description: Ticking memory connection
    
    java.lang.NullPointerException: Ticking memory connection
    	at com.networkoverflow.lifepower.content.capabilities.LifeForceProvider.<init>(LifeForceProvider.java:14) ~[classes/:?] {pl:capability_inject_definalize:A}
    	at com.networkoverflow.lifepower.content.capabilities.CapabilityHandler.onAttachCapabilities(CapabilityHandler.java:25) ~[classes/:?] {}
    	at net.minecraftforge.eventbus.ASMEventHandler_0_CapabilityHandler_onAttachCapabilities_AttachCapabilitiesEvent.invoke(.dynamic) ~[?:?] {}

    (Full Crash Report)

     

    Here is my LifeForceProvider.java (with line 14, the crash line, marked):

    package com.networkoverflow.lifepower.content.capabilities;
    
    import net.minecraft.nbt.INBT;
    import net.minecraft.util.Direction;
    import net.minecraftforge.common.capabilities.Capability;
    import net.minecraftforge.common.capabilities.CapabilityInject;
    import net.minecraftforge.common.capabilities.ICapabilitySerializable;
    import net.minecraftforge.common.util.LazyOptional;
    
    public class LifeForceProvider implements ICapabilitySerializable<INBT> {
        @CapabilityInject(ILifeForce.class)
        public static final Capability<ILifeForce> LIFE_FORCE_CAP = null;
    
        private LazyOptional<ILifeForce> instance = LazyOptional.of(LIFE_FORCE_CAP::getDefaultInstance); //THIS IS WHAT CRASHES <-----
    
        @Override
        public <T> LazyOptional<T> getCapability(Capability<T> capability, Direction direction) {
            return capability == LIFE_FORCE_CAP ? instance.cast() : LazyOptional.empty();
        }
    
        @Override
        public INBT serializeNBT() {
            return LIFE_FORCE_CAP.getStorage().writeNBT(LIFE_FORCE_CAP, this.instance.orElseThrow(() -> new IllegalArgumentException("LazyOptional must not be empty!")), null);
        }
    
        @Override
        public void deserializeNBT(INBT nbt) {
            LIFE_FORCE_CAP.getStorage().readNBT(LIFE_FORCE_CAP, this.instance.orElseThrow(() -> new IllegalArgumentException("LazyOptional must not be empty!")), null, nbt);
        }
    }

     

    So, as you can see, the LazyOptional.of() that I'm calling is raising a NullPointerException, which I think refers to LIFE_FORCE_CAP being null. However, I thought that because that variable has the @CapabilityInject annotation, its null value would be replaced with whatever forge generates.

     

    One reason I could think of for this happening is if I'm hooking into the wrong place to register my capability. In this thread, @Animefan8888 mentioned that the call to CapabilityManager.INSTANCE.register() should happen in the FMLCommonSetupEvent. Is this the wrong place to register my capability, or am I doing something else wrong?

     

    All code related to this capability

  9. Hello, I'm working on a mod that communicates information about the minecraft server to outside sources. One of the ways I'm trying to accomplish this is by hooking into certain events and sending out an HTTP post request with a json payload to a user-defined endpoint. I'm using Netty to accomplish this, since it's already used by minecraft. For some reason, though, my HttpClient won't send the messages through. I have print statements before and after message sending and it gets to the first message, but never gets to the second one. I realize this is more of a question about Netty than forge but the Netty community doesn't seem to be very active and I haven't gotten a response yet. I'm hoping that someone here will  be able to help me with this issue.

     

    Below, you can find my code:

    package com.anzanama.statusapi.http.client;
    
    import io.netty.bootstrap.Bootstrap;
    import io.netty.channel.*;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioSocketChannel;
    import io.netty.handler.codec.http.*;
    import io.netty.util.CharsetUtil;
    
    public class HttpClient {
        private String uri;
        private int port;
        private String payload;
    
        public HttpClient(String uri, int port, String payload) {
            this.uri = uri;
            this.port = port;
            this.payload = payload;
        }
    
        public void run() throws Exception {
            EventLoopGroup workerGroup = new NioEventLoopGroup();
    
            try {
                Bootstrap b = new Bootstrap();
                b.group(workerGroup);
                b.channel(NioSocketChannel.class);
                //b.option(ChannelOption.SO_KEEPALIVE, true);
                b.handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new HttpClientCodec());
                        ch.pipeline().addLast(new HttpObjectAggregator(1048576));
                        ch.pipeline().addLast(new HttpClientHandler());
                        ch.pipeline().addLast(new HttpRequestEncoder());
                    }
                });
    
                HttpRequest request = HttpRequester.createRequest(this.uri, this.payload);
                request.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json");
                System.out.println("Sending message!");
                Channel f = b.connect(uri, port).channel();
                f.writeAndFlush(request);
                f.closeFuture().sync();
                System.out.println("Message was sent!");
            } finally {
                workerGroup.shutdownGracefully();
            }
        }
    }
    package com.anzanama.statusapi.http.client;
    
    import io.netty.handler.codec.http.*;
    
    import static io.netty.buffer.Unpooled.copiedBuffer;
    
    public class HttpRequester {
        public static FullHttpRequest createRequest(String uri, String payload) {
            return createRequest(uri, payload.getBytes());
        }
    
        public static FullHttpRequest createRequest(String uri, byte[] payload) {
            return createRequest(uri, payload, HttpVersion.HTTP_1_1);
        }
    
        public static FullHttpRequest createRequest(String uri, byte[] payload, final HttpVersion version) {
            if (0 < payload.length)
            {
                FullHttpRequest request = new DefaultFullHttpRequest(version, HttpMethod.POST, uri, copiedBuffer(payload));
                request.headers().set(HttpHeaderNames.CONTENT_LENGTH, payload.length);
                return request;
            }
            else
            {
                return new DefaultFullHttpRequest(version, HttpMethod.POST, uri);
            }
        }
    }

     

  10. I discovered that either minecraft or forge is already keeping a record of tick times, so I'll just use this instead to avoid having a tick handler that bogs down the server. For anyone in the future, who's interested in this, look in net.minecraftforge.server.command.CommandTps to see how the forge TPS command calculates it.

  11. Hello, I'm attempting to monitor the average tick time of a forge server in my mod. Currently, I'm using an event handler that subscibes to TickEvent.ServerTickEvent to record System.currentTimeMillis each tick and then when someone asks for the TPS, I average out the differences between times in the array to find the mean tick time in milliseconds and divide 1000 by that to get the TPS. However, the numbers I come up with are always much larger than those produced by the 'forge tps' command (i.e. 0.3ms vs 10ms).

     

    I'm fairly certain my math is correct, which means there must be a problem with the way I am recording data each tick. Is there a better way for me to accomplish this? Below is my code:

     

    @SubscribeEvent
    public static void onTick(TickEvent.ServerTickEvent event) {
    	StatusAPI.data.tick();
    }
    
    public static JsonObject tps() {
      long[] tickList = StatusAPI.data.getTickList();
      long totalMillis = 0;
      int endIndex = tickList[tickList.length-1] != 0 ? tickList.length : StatusAPI.data.getTickListIndex();
      for(int i=0; i < endIndex - 1; i++) {
        long diff = tickList[i+1] - tickList[i];
        totalMillis += diff;
      }
      float averageMillis = (float)totalMillis / (float)endIndex;
      float ticksPerSecond = 1000F / averageMillis;
      JsonObject data = new JsonObject();
      DecimalFormat df = new DecimalFormat("0.00");
      data.addProperty("ticksPerSecond", df.format(ticksPerSecond));
      data.addProperty("averageTickTime", df.format(averageMillis));
      return data;
    }

     

  12. I have a command that teleports a player to another player and in that, I make a check to see if the player is in the same dimension as the other one, and if not, I call EntityPlayer::changeDimension();

    This seems to teleport the player fine, but it causes a weird desync with the client. The mod is server side only, as it's only a commands mod and I don't want to make my players have to download anything additional. The client acts like it doesn't know it moved to a new dimension. It sees everything in the new dimension fine, but other players can't see the one who teleported and the client has to relog into the server to be able to see items they dropped. I assume I need to send the client some sort of update packet, but I can't find anything in EntityPlayer for updating beside the EntityPlayer::sendPlayerAbilities() which wouldn't do what I want.

     

    Any tips?

  13. Hi, I'm not extremely familiar with the new registry system that has been introduced in 1.12. I'm attempting to figure out how I can get an instance of an Item from its registry name (i.e. "minecraft:torch")

     

    It looks like in 1.7.10, you could call GameData.findItem(modid, name) however, I haven't been able to find anything from newer versions. I would think it's a part of the registry system, but I'm not sure how it would be done.

  14. Yeah I understand this, but I was just wondering if it was possible cause I've seen plugins claiming they do it - I've already got it working fine on the main thread, but I'm just thinking if it's possible it'd be nice in the case that there are a LOT of entities I need to clear. However, from what I've found in testing it doesn't seem like the amount of time it takes to run is really going to matter. Seems to run just fine.

  15. Hi all, I'm working on a little mod akin to the ClearLagg plugin that will automatically clear out entities from time to time. I have seen a couple plugins boasting that they do this on a separate thread to reduce lag, but I'm wondering how this would be possible. It seems like it'd be subject to some hella race conditions.

  16. So I've been looking through resource packs a lot recently and I've come across an idea. I think it would be really cool to allow people to make a resource pack that makes use of the OreDictionary - for example, you define a model for oreCopper and every block that is registered as oreCopper uses that model.

  17. Hello, I'm working on porting a mod and I've noticed that MinecraftServer.getServer().getConfigurationManager() no longer exists. I have found looking around that I can use FMLCommonHandler.instance().getServer() will give an instance of MinecraftServer, but the server doesn't have a getConfigurationManager(). In 1.7.10, this could be used via ConfigurationManager#func_152596_g() to check if a player is operator. How can I accomplish this in 1.10.2?

  18. Actually, I think I may have managed to figure it out. Here's what I'm doing in getQuads() to access the TileEntity:

    @Override
        public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand) {
            if(side != null) {
                return Collections.EMPTY_LIST;
            }
            IExtendedBlockState extState = (IExtendedBlockState)state; 
            TileEntityBase  tile = (TileEntityBase)extState.getValue(UnlistedProperty.BLOCK_ACCESS).getTileEntity(extState.getValue(UnlistedProperty.POS));
        }

     

    Are you using the UnlistedPropertyGeneric.WORLD and UnlistedPropertyGeneric.TILE elsewhere, or am I missing something? Do I need to map these properties to the block somewhere else so that I can actually access them without error here?

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.