Jump to content
View in the app

A better way to browse. Learn more.

Forge Forums

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Snoopy_WWI_Ace

Members
  • Joined

  • Last visited

  1. Alright, I have modified the message handler to be thread safe and removed the unnecessary player variable, thanks for those tips Ernio. I also changed my capability provider to implement ICapabilitySerializable. Unfortunately, I am still running into the same problem: when I send a rune to the server, the console prints out the rune array with only the first index filled. I know that the index is being incremented, so every time that I send a packet it seems to be interacting with a new DefaultImplementation object. [spoiler=Default Implementation] public class DefaultImplementation implements ISpellCasting { private Runes[] spell = new Runes[spell.MAX_RUNES_IN_SPELL]; private long[] castTimes = new long[spell.MAX_RUNES_IN_SPELL]; private int index; private static final float MAX_TIME_BETWEEN_CASTS = 3 * 1000; public DefaultImplementation() { for (int i = 0; i < Spell.MAX_RUNES_IN_SPELL; i++) { spell[i] = Runes.EMPTY; castTimes[i] = 0; } index = 0; } @Override public void addRune(EntityPlayer p, Runes r) { printArrays(); long curTime = System.currentTimeMillis(); // if (index < 0) // return; // if (index >= Spell.MAX_RUNES_IN_SPELL) // clearFirstIndex(); // if (index > 0 && curTime - castTimes[index - 1] > MAX_TIME_BETWEEN_CASTS) // clearArrays(); spell[index] = r; castTimes[index] = curTime; index++; isValidSpell(p); } private boolean isValidSpell(EntityPlayer p) { printArrays(); Spell sp = SpellsCompendium.isValidSpell(spell, index); if (sp == null) return false; sp.cast(p); clearArrays(); return true; } private void clearFirstIndex() { index = Spell.MAX_RUNES_IN_SPELL - 1; for (int i = 1; i < Spell.MAX_RUNES_IN_SPELL; i--) { spell[i - 1] = spell[i]; castTimes[i - 1] = castTimes[i]; } } private void clearArrays() { index = 0; for (int i = 0; i < Spell.MAX_RUNES_IN_SPELL; i++) { spell[i] = Runes.EMPTY; castTimes[i] = 0; } } private void printArrays() { for (int i = 0; i < Spell.MAX_RUNES_IN_SPELL; i++) { System.out.print(Runes.getInt(spell[i]) + " "); } System.out.println("\n" + index); } private int[] runesToIntArray() { int[] ret = new int[spell.MAX_RUNES_IN_SPELL]; for (int i = 0; i < spell.length; i ++) { ret[i] = Runes.getInt(spell[i]); } return ret; } private Runes[] intToRunesArray(int[] ary) { Runes[] ret = new Runes[spell.MAX_RUNES_IN_SPELL]; for (int i = 0; i < ary.length; i ++) { ret[i] = Runes.getRune(ary[i]); } return ret; } @Override public NBTTagCompound getNBT() { NBTTagCompound tag = new NBTTagCompound(); tag.setInteger("index", index); tag.setIntArray("spell", runesToIntArray()); return tag; } @Override public void setNBT(NBTTagCompound comp) { index = comp.getInteger("index"); spell = intToRunesArray(comp.getIntArray("spell")); } } [spoiler=Registration and storage for the capability] public class CapabilitySpellCasting { @CapabilityInject(ISpellCasting.class) public static final Capability<ISpellCasting> SPELL_CASTING_CAPABILITY = null; public static void register() { CapabilityManager.INSTANCE.register(ISpellCasting.class, new Storage(), DefaultImplementation.class); } public static class Storage implements IStorage<ISpellCasting> { @Override public NBTTagCompound writeNBT(Capability<ISpellCasting> capability, ISpellCasting instance, EnumFacing side) { return instance.getNBT(); } @Override public void readNBT(Capability<ISpellCasting> capability, ISpellCasting instance, EnumFacing side, NBTBase nbt) { instance.setNBT((NBTTagCompound)nbt); } } } [spoiler=The new provider code] public class ProviderSpellCasting implements ICapabilitySerializable<NBTTagCompound> { ISpellCasting instance = CapabilitySpellCasting.SPELL_CASTING_CAPABILITY.getDefaultInstance(); @Override public boolean hasCapability(Capability<?> capability, EnumFacing facing) { return CapabilitySpellCasting.SPELL_CASTING_CAPABILITY != null && capability == CapabilitySpellCasting.SPELL_CASTING_CAPABILITY; } @Override public <T> T getCapability(Capability<T> capability, EnumFacing facing) { if (hasCapability(capability, facing)) return CapabilitySpellCasting.SPELL_CASTING_CAPABILITY .<T> cast(CapabilitySpellCasting.SPELL_CASTING_CAPABILITY.getDefaultInstance()); return null; } @Override public NBTTagCompound serializeNBT() { return (NBTTagCompound) CapabilitySpellCasting.SPELL_CASTING_CAPABILITY.getStorage().writeNBT(CapabilitySpellCasting.SPELL_CASTING_CAPABILITY, instance, null); } @Override public void deserializeNBT(NBTTagCompound nbt) { CapabilitySpellCasting.SPELL_CASTING_CAPABILITY.getStorage().readNBT(CapabilitySpellCasting.SPELL_CASTING_CAPABILITY, instance, null, nbt); } } [spoiler=The new message handler code] public static class Handler implements IMessageHandler<SpellMessage, IMessage> { @Override public IMessage onMessage(final SpellMessage message, final MessageContext ctx) { System.out .println("Got Spell Packet from: " + message.player + " with rune: " + Runes.getInt(message.rune)); ctx.getServerHandler().playerEntity.getServer().addScheduledTask(new Runnable() { public void run() { addMessageRune(ctx.getServerHandler().playerEntity, message.rune); } }); return null; } public void addMessageRune(EntityPlayer player, Runes rune) { ISpellCasting cap = player.getCapability(CapabilitySpellCasting.SPELL_CASTING_CAPABILITY, null); cap.addRune(player, rune); } } Could the problem be in my provider's getCapability? That seems correct to me, but I wouldn't be shocked if I was wrong.
  2. I've been trying to debug this for awhile now, and I'm not sure whether the issue is my understanding of capabilities or if I just need a second pair of eyes to help with my code. The code is intended to work as follows: 1) The client sends a packet containing the player name and an integer to the server. 2) The server gets the PlayerEntity from the name 3) The player's capability is called, and the integer is added to the array. The idea is to store which runes the player inputs from the keyboard, as certain rune combinations will make a spell. Unfortunately, the capability never gets more than one rune in the array, and the index is always at zero or one. My guess is that I am either always getting a new default implementation of the capability when calling the player's capability, or I need to do something extra to store capability data between calls. [spoiler=adding the capability] public class SpellEventHandler { @SubscribeEvent public void onEntityLoad(AttachCapabilitiesEvent.Entity event) { event.addCapability(new ResourceLocation(FantasyMod.MODID, "spellCasting"), new ProviderSpellCasting()); } } [spoiler=the capability interface] public interface ISpellCasting { public void addRune(EntityPlayer p, Runes r); public int[] getArray(); public void setArray(int[] set); } [spoiler=The default implementation] public class DefaultImplementation implements ISpellCasting { private Runes[] spell = new Runes[spell.MAX_RUNES_IN_SPELL]; private long[] castTimes = new long[spell.MAX_RUNES_IN_SPELL]; private int index; private static final float MAX_TIME_BETWEEN_CASTS = 3 * 1000; public DefaultImplementation() { for (int i = 0; i < Spell.MAX_RUNES_IN_SPELL; i++) { spell[i] = Runes.EMPTY; castTimes[i] = 0; } index = 0; } @Override public void addRune(EntityPlayer p, Runes r) { printArrays(); long curTime = System.currentTimeMillis(); // if (index < 0) // return; // if (index >= Spell.MAX_RUNES_IN_SPELL) // clearFirstIndex(); // if (index > 0 && curTime - castTimes[index - 1] > MAX_TIME_BETWEEN_CASTS) // clearArrays(); spell[index] = r; castTimes[index] = curTime; index++; isValidSpell(p); } private boolean isValidSpell(EntityPlayer p) { printArrays(); Spell sp = SpellsCompendium.isValidSpell(spell, index); if (sp == null) return false; sp.cast(p); clearArrays(); return true; } private void clearFirstIndex() { index = Spell.MAX_RUNES_IN_SPELL - 1; for (int i = 1; i < Spell.MAX_RUNES_IN_SPELL; i--) { spell[i - 1] = spell[i]; castTimes[i - 1] = castTimes[i]; } } private void clearArrays() { index = 0; for (int i = 0; i < Spell.MAX_RUNES_IN_SPELL; i++) { spell[i] = Runes.EMPTY; castTimes[i] = 0; } } private void printArrays() { for (int i = 0; i < Spell.MAX_RUNES_IN_SPELL; i++) { System.out.print(Runes.getInt(spell[i]) + " "); } System.out.println("\n" + index); } @Override public int[] getArray() { int[] ret = new int[1 + index]; ret[0] = index; for (int i = 1; i < ret.length; i++) { ret[i] = Runes.getInt(spell[i - 1]); } return null; } @Override public void setArray(int[] set) { index = set[0]; for (int i = 1; i < set.length; i++) { spell[i - 1] = Runes.getRune(set[i]); } } } [/spoiler] [spoiler=The capability registration] public class CapabilitySpellCasting { @CapabilityInject(ISpellCasting.class) public static final Capability<ISpellCasting> SPELL_CASTING_CAPABILITY = null; public static void register() { CapabilityManager.INSTANCE.register(ISpellCasting.class, new Storage(), DefaultImplementation.class); } public static class Storage implements IStorage<ISpellCasting> { @Override public NBTBase writeNBT(Capability<ISpellCasting> capability, ISpellCasting instance, EnumFacing side) { return new NBTTagIntArray(instance.getArray()); } @Override public void readNBT(Capability<ISpellCasting> capability, ISpellCasting instance, EnumFacing side, NBTBase nbt) { instance.setArray(((NBTTagIntArray)nbt).getIntArray()); } } } [spoiler=The capability provider] public class ProviderSpellCasting implements ICapabilityProvider { @Override public boolean hasCapability(Capability<?> capability, EnumFacing facing) { return CapabilitySpellCasting.SPELL_CASTING_CAPABILITY != null && capability == CapabilitySpellCasting.SPELL_CASTING_CAPABILITY; } @Override public <T> T getCapability(Capability<T> capability, EnumFacing facing) { if (hasCapability(capability, facing)) return CapabilitySpellCasting.SPELL_CASTING_CAPABILITY .<T> cast(CapabilitySpellCasting.SPELL_CASTING_CAPABILITY.getDefaultInstance()); return null; } } [spoiler=Calling the capability] public static class Handler implements IMessageHandler<SpellMessage, IMessage> { @Override public IMessage onMessage(SpellMessage message, MessageContext ctx) { System.out .println("Got Spell Packet from: " + message.player + " with rune: " + Runes.getInt(message.rune)); World world = ctx.getServerHandler().playerEntity.worldObj; EntityPlayer player = world.getPlayerEntityByName(message.player); ISpellCasting cap = player.getCapability(CapabilitySpellCasting.SPELL_CASTING_CAPABILITY, null); cap.addRune(player, message.rune); return null; } } I don't need to store the capability between different world loadings, so the serializable interface isn't something that I spent much time looking into. Could that be the issue? Any help would be appreciated.

Important Information

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

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.