Jump to content

PenWallet

Members
  • Posts

    15
  • Joined

  • Last visited

Everything posted by PenWallet

  1. A bit of bump, I'm still stuck trying to draw this () to every player's inventory. I did it by overriding minecraft's inventory texture, but as I was told, this is not a good idea, but I don't know what method to use or in which event of GuiScreenEvent to do so.
  2. Most likely, you have tried to register twice the same item, in this case, "pulchrit"
  3. Well I'm stupid, not sure why I didn't look for a getGuiLeft method, and there it was. That solved my recipe book moving all over the place. Yup, that worked, I did this: //Event to add the string to the screen @OnlyIn(Dist.CLIENT) @SubscribeEvent public void guiScreenEvent(GuiScreenEvent.DrawScreenEvent.Post event) { if(!(event.getGui() instanceof InventoryScreen)) return; InventoryScreen screen = (InventoryScreen)event.getGui(); screen.getMinecraft().fontRenderer.drawString(CurrencyCapability.getAmountFromPlayer(Minecraft.getInstance().player)+"g", screen.getGuiLeft() + 110, screen.height / 2 - 13, 0xffae00); } (The very same InventoryScreen does use raw additions so I'll guess that's doable?) And for the thing you said, about drawing the portion, do you know the method which I would have to use or how I'd do it? Do I need a .png with just that part of the background?
  4. So, I want to do 3 things in my custom inventory: - Changing the background to this one, which adds a space for the currency - Move the book icon to the top right corner, above the crafting result slot, so that it doesn't interfere with the currency slot - Adding a text to said currency slot. From that stuff, I have achieved: - Tried to change background with code: private static final ResourceLocation CUSTOM_INVENTORY = new ResourceLocation(Constants.MODID, "textures/gui/container/custominventory.png"); @OnlyIn(Dist.CLIENT) @SubscribeEvent public void guiBackground(GuiScreenEvent.BackgroundDrawnEvent event) { if(!(event.getGui() instanceof InventoryScreen)) return; InventoryScreen screen = (InventoryScreen)event.getGui(); screen.getMinecraft().getTextureManager().bindTexture(CUSTOM_INVENTORY); } It didn't work, so I replaced minecraft's texture with mine in my mod's assets, and it does work, but I'm guessing that's not the way to do it. - I managed to move the crafting recipe book like this: @OnlyIn(Dist.CLIENT) @SubscribeEvent public void guiScreenEvent(GuiScreenEvent.DrawScreenEvent.Post event) { if(!(event.getGui() instanceof InventoryScreen)) return; InventoryScreen screen = (InventoryScreen)event.getGui(); int guiLeft = (screen.width - screen.getXSize()) / 2; for(Object object : screen.children()) { if(object instanceof RecipeBookGui) { guiLeft = ((RecipeBookGui)object).updateScreenPosition(screen.width < 379, guiLeft + 290, screen.height / 2 - 79); } else if(object instanceof ImageButton) { ((ImageButton)object).setPosition(guiLeft + 290, screen.height / 2 - 79); } } } And it does move it, but only if it's fullscreen, if it isn't fullscreen, it goes somewhere else, like this: - The string over the currency slot I have no idea how to implement. When I used CustomInventoryScreen, I did it like this: protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) { //This draws the currency at the right place. THIS is where I would need that information, but I don't know how to get it this.font.drawString(money+"g", this.guiLeft + 110, this.height / 2 - 13, 0xffae00); } But now that I'm using events like @diesieben07 said, I don't even know how to add it A main problem, I think, is that most stuff from InventoryScreen and its super class are protected or private, so I have very little stuff to touch. I don't know, I feel quite lost right now, any help is highly appreaciated, thanks
  5. And how would I go about giving the player the information when he first joins? Right now, when he first joins, it shows 0 on the player's inventory GUI because Minecraft.getInstance().player doesn't have the information yet. When I update the information, I did what you told me and send the packet, and then it does show correctly on the GUI, but I don't know exactly where I would first update that information. Also, aside from that I understand I can only ask for the information (that is, sending the C2SCurrencyPacket) from the client, so I should first check if world.isRemote, right?
  6. Hello, I'm quite new to modding, really sorry if making beginners' mistakes. So, I have a capability for each PlayerEntity, which is just an integer acting as a currency. To do this, I copied the InventoryScreen code to change the GUI's texture to my own (which adds in a place for the currency) and to show a text with said amount of currency. The problem comes getting the information from the user's capability. Since it's server-only information, I need to make packet networking, so I did, but I have no idea how to rely that information to my CustomInventoryScreen. Since I think I can't show Mojang's proprietary code, I'll only show what I changed from InventoryScreen: CustomInventoryScreen @OnlyIn(Dist.CLIENT) public class CustomInventoryScreen extends DisplayEffectsScreen<PlayerContainer> implements IRecipeShownListener { private static final ResourceLocation CUSTOM_INVENTORY_TEXTURE = new ResourceLocation(Constants.MODID, "textures/gui/container/custominventory.png"); /** * Draws the background layer of this container (behind the items). */ protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) { //Call to get the server to send the user's currency information MyMod.CHANNEL.sendToServer(new C2SCurrencyPacket()); //This changes the background to mine (with the place for the currency added to the texture) this.minecraft.getTextureManager().bindTexture(CUSTOM_INVENTORY_TEXTURE); //This draws the currency at the right place. THIS is where I would need that information, but I don't know how to get it this.font.drawString("10002g", this.guiLeft + 110, this.height / 2 - 13, 0xffae00); } } C2SCurrencyPacket public class C2SCurrencyPacket { public C2SCurrencyPacket() { } public static void handle(final C2SCurrencyPacket msg, Supplier<NetworkEvent.Context> ctx) { ctx.get().enqueueWork(() -> { ServerPlayerEntity sender = ctx.get().getSender(); ICurrency currency = sender.getCapability(CurrencyCapability.CURRENCY_CAPABILITY).orElseThrow(IllegalStateException::new); //I send the currency amount information to the client with another packet MyMod.CHANNEL.send(PacketDistributor.ALL.noArg(), new S2CCurrencyPacket(currency.getAmount())); //Just testing if the currency is accurate by showing a message to the user, and it is sender.sendMessage(new StringTextComponent("Money: "+currency.getAmount()), ChatType.SYSTEM); }); ctx.get().setPacketHandled(true); } public static void encode(final C2SCurrencyPacket msg, final PacketBuffer packetBuffer) { } public static C2SCurrencyPacket decode(final PacketBuffer packetBuffer) { return new C2SCurrencyPacket(); } } S2CCurrencyPacket public class S2CCurrencyPacket { private int amount; public S2CCurrencyPacket(int amount) { this.amount = amount; } public static void handle(final S2CCurrencyPacket msg, Supplier<NetworkEvent.Context> ctx) { ctx.get().enqueueWork(() -> { // Here I would need to give the currency information to the menu, but I don't know how }); ctx.get().setPacketHandled(true); } public static void encode(final S2CCurrencyPacket msg, final PacketBuffer packetBuffer) { packetBuffer.writeInt(msg.amount); } public static S2CCurrencyPacket decode(final PacketBuffer packetBuffer) { return new S2CCurrencyPacket(packetBuffer.readInt()); } } Here's how I attach my CustomInventoryScreen to the game: @Mod(Constants.MODID) public class MyMod { @SubscribeEvent public void changeInventoryGUI(GuiOpenEvent event) { if(event.getGui() instanceof InventoryScreen) event.setGui(new CustomInventoryScreen(Minecraft.getInstance().player)); } } So, to sum it up, my problem is that I don't know how to access my CustomInventoryScreen instance to show the information or if that's the way I should do it. I don't know if what I have done is correct or if I'm killing bunnies with every line of code I type. Please help me out and thank you for your time EDIT: I managed to solve my problem by changing the CustomInventoryScreen to this @OnlyIn(Dist.CLIENT) public class CustomInventoryScreen extends DisplayEffectsScreen<PlayerContainer> implements IRecipeShownListener { private static final ResourceLocation CUSTOM_INVENTORY_TEXTURE = new ResourceLocation(Constants.MODID, "textures/gui/container/custominventory.png"); private int money = 0; public CustomInventoryScreen(PlayerEntity player) { //Call to get the server to send the user's currency information StardewMod.CHANNEL.sendToServer(new C2SCurrencyPacket()); } //Sets the variable to the right amount of money public void setMoney(int amount) { this.money = amount; } /** * Draws the background layer of this container (behind the items). */ protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) { //Call to get the server to send the user's currency information MyMod.CHANNEL.sendToServer(new C2SCurrencyPacket()); //This changes the background to mine (with the place for the currency added to the texture) this.minecraft.getTextureManager().bindTexture(CUSTOM_INVENTORY_TEXTURE); //This draws the currency at the right place. THIS is where I would need that information, but I don't know how to get it this.font.drawString(money+"g", this.guiLeft + 110, this.height / 2 - 13, 0xffae00); } } And the S2CCurrencyPacket to this: public class S2CCurrencyPacket { private int amount; public S2CCurrencyPacket(int amount) { this.amount = amount; } public static void handle(final S2CCurrencyPacket msg, Supplier<NetworkEvent.Context> ctx) { ctx.get().enqueueWork(() -> { ServerPlayerEntity sender = ctx.get().getSender(); // the client that sent this packet //Set the amount in the screen ((CustomInventoryScreen)Minecraft.getInstance().currentScreen).setMoney(msg.amount); }); ctx.get().setPacketHandled(true); } public static void encode(final S2CCurrencyPacket msg, final PacketBuffer packetBuffer) { packetBuffer.writeInt(msg.amount); } public static S2CCurrencyPacket decode(final PacketBuffer packetBuffer) { return new S2CCurrencyPacket(packetBuffer.readInt()); } } This does indeed solve my problem, but I don't know why it smells like stinky code. Am I on the right here or is this just a shitty way to do it?
  7. Alright, thank you very much for your help. I'll try later on the day to do the showing on the inventory, but for now that's all I needed, thanks a lot again.
  8. So, if I wanted to (which is what I want to do) show the current amount on the inventory. That's the client, so I would have to do synchronization, right?
  9. Damn, that worked like a charm, and it also reduced the amount of lines, thanks a lot. One last thing. If the mod were to be used in multiplayer, would I have synchronization problems? I read that on https://mcforge.readthedocs.io/en/1.15.x/datastorage/capabilities/#synchronizing-data-with-clients, but I'm unsure if that still applies, or if it won't be a problem at all
  10. Right now I'm just testing so that if I right click on the item, it shows the current amount, then prints out a message to the user. It works, but it looks like an awful lot of code to get the information. Would this be the way to access its information? Is there a better way? public class CopperIngot extends Item { public CopperIngot() { super(new Item.Properties().group(Constants.SMITEMGROUP)); setRegistryName(Constants.MODID, Constants.COPPERINGOT); } @Override public ActionResult<ItemStack> onItemRightClick(World worldIn, PlayerEntity playerIn, Hand handIn) { if(!worldIn.isRemote) playerIn.getCapability(CurrencyCapability.CURRENCY_CAPABILITY).ifPresent(new NonNullConsumer<ICurrency>() { @Override public void accept(@Nonnull ICurrency iCurrency) { playerIn.sendStatusMessage(new StringTextComponent("Currency: "+iCurrency.getAmount()), false); iCurrency.addOrSubtractAmount(1); } }); return super.onItemRightClick(worldIn, playerIn, handIn); } }
  11. First of all, I'm quite new to modding, so I'm sorry if I'm doing many beginners' errors. Hello, I've been reading some stuff about capabilities, but most stuff I find is from 1.12 and it appears to be outdated. I think. I want to implement sort of a currency, so that each player would have its own amount registered to it. What I have so far is this: ICurrency.java public interface ICurrency { public int getAmount(); public void setAmount(int amount); public void addOrSubtractAmount(int amount); } Currency.java public class Currency implements ICurrency { private int amount = 0; @Override public int getAmount() { return this.amount; } @Override public void setAmount(int amount) { this.amount = amount; if(this.amount < 0) this.amount = 0; } @Override public void addOrSubtractAmount(int amount) { this.amount += amount; if(this.amount < 0) this.amount = 0; } } CurrencyStorage.java public class CurrencyStorage implements Capability.IStorage<ICurrency> { @Nullable @Override public INBT writeNBT(Capability<ICurrency> capability, ICurrency instance, Direction side) { return IntNBT.func_229692_a_(instance.getAmount()); } @Override public void readNBT(Capability<ICurrency> capability, ICurrency instance, Direction side, INBT nbt) { if (!(instance instanceof Currency)) throw new IllegalArgumentException("Can not deserialize to an instance that isn't the default implementation"); instance.setAmount(((IntNBT)nbt).getInt()); } } CurrencyCapability.java public class CurrencyCapability implements ICapabilitySerializable<IntNBT> { @CapabilityInject(ICurrency.class) public static final Capability<ICurrency> CURRENCY_CAPABILITY = null; private LazyOptional<ICurrency> instance = LazyOptional.of(CURRENCY_CAPABILITY::getDefaultInstance); public static void register() { CapabilityManager.INSTANCE.register(ICurrency.class, new CurrencyStorage(), Currency::new); } @Nonnull @Override public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) { return CURRENCY_CAPABILITY.orEmpty(cap, instance);; } @Override public IntNBT serializeNBT() { return (IntNBT) CURRENCY_CAPABILITY.getStorage().writeNBT(CURRENCY_CAPABILITY, instance.orElseThrow(() -> new IllegalArgumentException("LazyOptional cannot be empty!")), null);; } @Override public void deserializeNBT(IntNBT nbt) { CURRENCY_CAPABILITY.getStorage().readNBT(CURRENCY_CAPABILITY, instance.orElseThrow(() -> new IllegalArgumentException("LazyOptional cannot be empty!")), null, nbt); } } Where I'm registering the capability @Mod(Constants.MODID) public class Mod { public Mod() { FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup); //More events and stuff... } @SubscribeEvent public void attachCapabilitiesEntity(final AttachCapabilitiesEvent<Entity> event) { if(event.getObject() instanceof PlayerEntity) event.addCapability(new ResourceLocation(Constants.MODID, Constants.CURRENCY), new CurrencyCapability()); } private void setup(final FMLCommonSetupEvent event) { //Register the Currency capability CurrencyCapability.register(); } //More events and stuff... } My problems lie on various places: 1. CurrencyCapability throws errors: .orEmpty, and CURRENCY_CAPABILITY.getStorage() say "Method invocation 'orEmpty' will produce 'NullPointerException' " and can't use it 2. I'm not sure if I'm registering it correctly 3. I don't know, once I'm able to register it correctly, how to get the info (the currency amount, that it) from the player Thank you for your time
  12. Hello, I'm quite noob at making mods, so any help will be appreciated. I want to know how to make flowers spawn in the world, thanks.
  13. Thanks for that, that was definitely a step in the right direction, but now I'm stuck on how to make it move towards the player. I used moveToBlockPosAndAngles() but what it does is teleporting the bat to the player. Any idea on how I would make it move towards me, like a Zombie would (but flying)?
  14. From what you said I understand I will have to copy the original code from BatEntity and change that condition, but how would I check it doesn't have an attack target? Sorry for being such a noob
  15. Hi, I'm working on a mod for 1.15.2. I want this custom Bat entity (IridiumBat) to attack the player on sight. Instead, it's only attacking the player if it's really close. It looks as if the bat is actually trying to get closer to me, but it's like fighting its instruction of flying randomly. I've looked around BatEntity looking for a clue as to what's causing it, but I wouldn't really know what to change. I assigned the ZombieAttackModifiedGoal to the IridiumBat, which is just a modified version of ZombieAttackGoal (made it accept IridiumBat in the constructor parameters and deleted the raiseArms parameters). Because ZombieAttackGoal extends from MeleeAttackGoal, which doesn't accept AmbientEntity in its constructor parameters, I needed to make a MeleeAttackModifiedGoal to accept it as well, which is what ZombieAttackModifiedGoal extends now. IridiumBat.java: public class IridiumBat extends BatEntity { @SuppressWarnings("unchecked") public IridiumBat(EntityType<? extends BatEntity> type, World worldIn) { super((EntityType<? extends BatEntity>) EntitiesList.IRIDIUM_BAT, worldIn); } @Override protected void registerAttributes() { super.registerAttributes(); this.getAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(15.0f); this.getAttributes().registerAttribute(SharedMonsterAttributes.ATTACK_DAMAGE); this.getAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(1.0f); this.getAttribute(SharedMonsterAttributes.FOLLOW_RANGE).setBaseValue(35.0f); } @Override protected void registerGoals() { this.goalSelector.addGoal(8, new LookRandomlyGoal(this)); this.goalSelector.addGoal(8, new LookAtGoal(this, PlayerEntity.class, 8.0F)); this.goalSelector.addGoal(0, new ZombieAttackModifiedGoal(this, 1.0D, true)); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, PlayerEntity.class, false)); } } ZombieAttackedModifiedGoal.java: public class ZombieAttackModifiedGoal extends MeleeAttackModifiedGoal { private final IridiumBat bat; public ZombieAttackModifiedGoal(IridiumBat bat, double speed, boolean useLongMemory) { super(bat, speed, useLongMemory); this.bat = bat; } /** * Execute a one shot task or start executing a continuous task */ public void startExecuting() { super.startExecuting(); } /** * Reset the task's internal state. Called when this task is interrupted by another one */ public void resetTask() { super.resetTask(); this.bat.setAggroed(false); } /** * Keep ticking a continuous task that has already been started */ public void tick() { super.tick(); if (this.attackTick < 10) { this.bat.setAggroed(true); } else { this.bat.setAggroed(false); } } } MeleeAttackModifiedGoal.java: public class MeleeAttackModifiedGoal extends Goal { protected final IridiumBat attacker; protected int attackTick; private final double speedTowardsTarget; private final boolean longMemory; private Path path; private int delayCounter; private double targetX; private double targetY; private double targetZ; protected final int attackInterval = 20; private long field_220720_k; private int failedPathFindingPenalty = 0; private boolean canPenalize = false; public MeleeAttackModifiedGoal(IridiumBat creature, double speedIn, boolean useLongMemory) { this.attacker = creature; this.speedTowardsTarget = speedIn; this.longMemory = useLongMemory; this.setMutexFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK)); } /** * Returns whether the EntityAIBase should begin execution. */ public boolean shouldExecute() { long i = this.attacker.world.getGameTime(); if (i - this.field_220720_k < 20L) { return false; } else { this.field_220720_k = i; LivingEntity livingentity = this.attacker.getAttackTarget(); if (livingentity == null) { return false; } else if (!livingentity.isAlive()) { return false; } else { if (canPenalize) { if (--this.delayCounter <= 0) { this.path = this.attacker.getNavigator().getPathToEntityLiving(livingentity, 0); this.delayCounter = 4 + this.attacker.getRNG().nextInt(7); return this.path != null; } else { return true; } } this.path = this.attacker.getNavigator().getPathToEntityLiving(livingentity, 0); if (this.path != null) { return true; } else { return this.getAttackReachSqr(livingentity) >= this.attacker.getDistanceSq(livingentity.func_226277_ct_(), livingentity.func_226278_cu_(), livingentity.func_226281_cx_()); } } } } /** * Returns whether an in-progress EntityAIBase should continue executing */ public boolean shouldContinueExecuting() { LivingEntity livingentity = this.attacker.getAttackTarget(); if (livingentity == null) { return false; } else if (!livingentity.isAlive()) { return false; } else if (!this.longMemory) { return !this.attacker.getNavigator().noPath(); } else if (!this.attacker.isWithinHomeDistanceFromPosition(new BlockPos(livingentity))) { return false; } else { return !(livingentity instanceof PlayerEntity) || !livingentity.isSpectator() && !((PlayerEntity)livingentity).isCreative(); } } /** * Execute a one shot task or start executing a continuous task */ public void startExecuting() { this.attacker.getNavigator().setPath(this.path, this.speedTowardsTarget); this.attacker.setAggroed(true); this.delayCounter = 0; } /** * Reset the task's internal state. Called when this task is interrupted by another one */ public void resetTask() { LivingEntity livingentity = this.attacker.getAttackTarget(); if (!EntityPredicates.CAN_AI_TARGET.test(livingentity)) { this.attacker.setAttackTarget((LivingEntity)null); } this.attacker.setAggroed(false); this.attacker.getNavigator().clearPath(); } /** * Keep ticking a continuous task that has already been started */ public void tick() { LivingEntity livingentity = this.attacker.getAttackTarget(); this.attacker.getLookController().setLookPositionWithEntity(livingentity, 30.0F, 30.0F); double d0 = this.attacker.getDistanceSq(livingentity.func_226277_ct_(), livingentity.func_226278_cu_(), livingentity.func_226281_cx_()); --this.delayCounter; if ((this.longMemory || this.attacker.getEntitySenses().canSee(livingentity)) && this.delayCounter <= 0 && (this.targetX == 0.0D && this.targetY == 0.0D && this.targetZ == 0.0D || livingentity.getDistanceSq(this.targetX, this.targetY, this.targetZ) >= 1.0D || this.attacker.getRNG().nextFloat() < 0.05F)) { this.targetX = livingentity.func_226277_ct_(); this.targetY = livingentity.func_226278_cu_(); this.targetZ = livingentity.func_226281_cx_(); this.delayCounter = 4 + this.attacker.getRNG().nextInt(7); if (this.canPenalize) { this.delayCounter += failedPathFindingPenalty; if (this.attacker.getNavigator().getPath() != null) { net.minecraft.pathfinding.PathPoint finalPathPoint = this.attacker.getNavigator().getPath().getFinalPathPoint(); if (finalPathPoint != null && livingentity.getDistanceSq(finalPathPoint.x, finalPathPoint.y, finalPathPoint.z) < 1) failedPathFindingPenalty = 0; else failedPathFindingPenalty += 10; } else { failedPathFindingPenalty += 10; } } if (d0 > 1024.0D) { this.delayCounter += 10; } else if (d0 > 256.0D) { this.delayCounter += 5; } if (!this.attacker.getNavigator().tryMoveToEntityLiving(livingentity, this.speedTowardsTarget)) { this.delayCounter += 15; } } this.attackTick = Math.max(this.attackTick - 1, 0); this.checkAndPerformAttack(livingentity, d0); } protected void checkAndPerformAttack(LivingEntity enemy, double distToEnemySqr) { double d0 = this.getAttackReachSqr(enemy); if (distToEnemySqr <= d0 && this.attackTick <= 0) { this.attackTick = 20; this.attacker.swingArm(Hand.MAIN_HAND); this.attacker.attackEntityAsMob(enemy); } } protected double getAttackReachSqr(LivingEntity attackTarget) { return (double)(this.attacker.getWidth() * 2.0F * this.attacker.getWidth() * 2.0F + attackTarget.getWidth()); } } A small video of the current behavior I'm completely new to modding (just started a few days ago), so any lessons I can learn from this will be most useful, thanks.
×
×
  • Create New...

Important Information

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