Jump to content

[1.10.2] [Scala] Capabilities clashing with each other (SOLVED)


Recommended Posts

Posted

So I'm working on a fairly large mod in Scala, and I have two different capabilities, one for handling mana and the other for handling a custom level/exp system. However, it seems like I've done something wrong, as Forge appears to try to connect an instance of the mana handler to where there should be a level handler.

 

ServerProxy (usually called CommonProxy, I'm weird)

 

  Reveal hidden contents

 

 

Relevant event handler code

 

  Reveal hidden contents

 

 

Relevant capability code

 

  Reveal hidden contents

 

 

There is also an abstract class LevelHandler, but none of it's code should really be relevant. DefaultLevelHandler is a typical double-inheritance from LevelHandler and ICapabilitySerializable, and it's Storage is fairly standard as well. The same is true of ManaHandler's parts.

 

Can you spot my error? I'm completely stumped. Thanks!

Posted

Ah yes, sorry. The game crashes with this error when I try to load a world:

 

java.lang.ClassCastException: chuunimod.capabilities.DefaultManaHandler cannot be cast to chuunimod.capabilities.LevelHandler
at chuunimod.capabilities.LevelHandler$.instanceFor(LevelHandler.scala:58)
at chuunimod.gui.GuiChuuniOverlay.onRenderGameOverlay(GuiChuuniOverlay.scala:22)
at net.minecraftforge.fml.common.eventhandler.ASMEventHandler_9_GuiChuuniOverlay_onRenderGameOverlay_Post.invoke(.dynamic)
at net.minecraftforge.fml.common.eventhandler.ASMEventHandler.invoke(ASMEventHandler.java:90)
at net.minecraftforge.fml.common.eventhandler.EventBus.post(EventBus.java:168)
at net.minecraftforge.client.GuiIngameForge.post(GuiIngameForge.java:888)
at net.minecraftforge.client.GuiIngameForge.renderExperience(GuiIngameForge.java:586)
at net.minecraftforge.client.GuiIngameForge.renderGameOverlay(GuiIngameForge.java:167)
at net.minecraft.client.renderer.EntityRenderer.updateCameraAndRender(EntityRenderer.java:1125)
at net.minecraft.client.Minecraft.runGameLoop(Minecraft.java:1139)
at net.minecraft.client.Minecraft.run(Minecraft.java:406)
at net.minecraft.client.main.Main.main(Main.java:118)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at net.minecraft.launchwrapper.Launch.launch(Launch.java:135)
at net.minecraft.launchwrapper.Launch.main(Launch.java:28)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at net.minecraftforge.gradle.GradleStartCommon.launch(GradleStartCommon.java:97)
at GradleStart.main(GradleStart.java:26)

 

Full crash report:

 

  Reveal hidden contents

 

 

All I'm doing is trying to access the handlers via the instanceFor method to render their information to a GUI.

Posted

Mana:

class DefaultManaHandler(cur:Float=0,max:Float=250,regen:Float=.25f) extends ManaHandler(cur,max,regen) with ICapabilitySerializable[NBTTagCompound] {
def hasCapability(capability:Capability[_], f:EnumFacing) = capability == ManaHandler.CAP
def getCapability[T](capability:Capability[T], f:EnumFacing) = { if(capability == ManaHandler.CAP) this else null }.asInstanceOf[T]

def serializeNBT:NBTTagCompound = new NBTManaHandler(this).nbt
def deserializeNBT(nbt:NBTTagCompound) = new NBTManaHandler(nbt).copyTo(this)
}

object DefaultManaHandler {
class Storage extends IStorage[ManaHandler] {
	def writeNBT(cap:Capability[ManaHandler], ins:ManaHandler, f:EnumFacing) = ins.asInstanceOf[DefaultManaHandler].serializeNBT
	def readNBT(cap:Capability[ManaHandler], ins:ManaHandler, f:EnumFacing, nbt:NBTBase) = ins.asInstanceOf[DefaultManaHandler].deserializeNBT(nbt.asInstanceOf[NBTTagCompound])
}
}

 

Levels:

class DefaultLevelHandler(lvl:Int=1,xp:Float=0) extends LevelHandler(lvl,xp) with ICapabilitySerializable[NBTTagCompound] {
def hasCapability(capability:Capability[_], f:EnumFacing) = capability == LevelHandler.CAP
def getCapability[T](capability:Capability[T], f:EnumFacing) = { if(capability == LevelHandler.CAP) this else null }.asInstanceOf[T]

def serializeNBT:NBTTagCompound = new NBTLevelHandler(this).nbt
def deserializeNBT(nbt:NBTTagCompound) = new NBTLevelHandler(nbt).copyTo(this)
}

object DefaultLevelHandler {
class Storage extends IStorage[LevelHandler] {
	def writeNBT(cap:Capability[LevelHandler], ins:LevelHandler, f:EnumFacing) = ins.asInstanceOf[DefaultLevelHandler].serializeNBT
	def readNBT(cap:Capability[LevelHandler], ins:LevelHandler, f:EnumFacing, nbt:NBTBase) = ins.asInstanceOf[DefaultLevelHandler].deserializeNBT(nbt.asInstanceOf[NBTTagCompound])
}
}

Posted

Not really sure what you mean by the same class - the capability type is Handler, and the default implementation is DefaultHandler.

 

As to the debugger idea, the only option I have is the Eclipse debugger, which doesn't seem to be up to the task.

Posted
  Quote
DefaultLevelHandler implements both LevelHandler and ICapabilitySerializable (i.e. ICapabilityProvider)

Ah, ok. Honestly, I've used this structure before and not had any problems with keeping track of it... For brevity's sake I'll leave it for now, especially as I don't think that's where the problem is (the mana handler worked fine before I added the level handler)

Posted

I have only the vaguest idea why, but for some reason that worked. Thank you! My updated code is below for anyone having the same issue.

 

object (x)Handler

object ManaHandler {
def instanceFor(player:EntityPlayer) = player.getCapability(Capabilities.MANA, null)
def getHandlerInstance = new DefaultManaHandler
def getStorageInstance = new DefaultManaHandler.Storage
def getHandlerFactory = new Callable[DefaultManaHandler] { def call = new DefaultManaHandler }
}

object LevelHandler {
def instanceFor(player:EntityPlayer) = player.getCapability(Capabilities.LEVEL, null)
def getHandlerInstance = new DefaultLevelHandler
def getStorageInstance = new DefaultLevelHandler.Storage
def getHandlerFactory = new Callable[DefaultLevelHandler] { def call = new DefaultLevelHandler }
}

 

Capabilities.java

public class Capabilities {
@CapabilityInject(ManaHandler.class) public static final Capability<ManaHandler> MANA = null;
@CapabilityInject(LevelHandler.class) public static final Capability<LevelHandler> LEVEL = null;
}

 

Moral of the story, don't try to inject capabilities into Scala code if you intend to use more than one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

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