minecraft-data icon indicating copy to clipboard operation
minecraft-data copied to clipboard

Express Enum X metadata somewhere for each protocol version

Open zimurgh opened this issue 8 years ago • 4 comments

I'm currently implementing a generator for minecraft-data that will produce complete Haskell implementations for each protocol version currently present. However, due to how significant static typing is to my target language, it would be very useful to have the various enum values in the protocol included somewhere such that I can bound their respective packet fields to only valid values that actually have meaning.

For instance, this enum exists:

Animation 0 Swing main arm 1 Take damage 2 Leave bed 3 Swing offhand 4 Critical effect 5 Magic critical effect

This information can be statically encoded through Haskell's type system as an algebraic data type like such:

data Animation
  = SwingMainArm
  | TakeDamage
  | LeaveBed
  | SwingOffhand
  | CriticalEffect
  | MagicCriticalEffect
  deriving (Show,Eq,Enum)

Where the Enum at the bottom automatically maps SwingMainArm to 0, TakeDamage to 1, etc.

This allows me to generate functions that encode and decode the field to recognize and enforce valid animation values.

encodeAnimation :: Animation -> Word8
decodeAnimation :: Word8 -> Either String Animation

This way my API abstracts away from raw bytes and can instead talk at a type level in terms of the meanings those bytes have from the perspective of the protocol. Even better, Haskell's API documentation tool can produce some very helpful documentation if it's fed types like the one above instead of just explanatory comments informing the user which byte values actually mean something within the context of the current version of the protocol. They shouldn't have to keep track of how game state and behaviors serialize, that's the whole reason I'm writing this library in the first place.

So I guess the realization of this feature request would probably take the form of a enum.json included in each protocol version directory that provides mappings of bytes to names for each enum present in the given protocol version. So something like:

"enum": [
    "container",
    [
      {
        "name": "animation",
        "type": [
          "mapper",
          {
            "type": "u8",
            "mappings": {
              "0x00": "swing_main_arm",
              "0x01": "take_damage",
              "0x02": "leave_bed",
              "0x03": "swing_offhand",
              "0x04": "critical_effect",
              "0x05": "magic_critical_effect"
            }
          }
        ]
      },
      etc,etc,etc...
    ]
  ]

There would then need to be some way to map these enums onto their intended fields in protocol.json. Perhaps by specifying packet ID for all packets that use the enum field.

zimurgh avatar May 20 '16 17:05 zimurgh

First a comment, we are have a spec and links to current implementations of protocol.json in https://github.com/ProtoDef-io/ProtoDef . Node.js current implementation is run-time based but there is already an elixir compiler, it might be interesting to you (and the other way round, I'm interested by implementations of that spec).

The idea to have enums is interesting. We thought about it before (@roblabla) and one of the problem is where do we limit ourselves to : are blockId enums ?

I do agree that for simple enums like the animation it makes sense.

If we represent it as a mapper then it would simply be possible to put the mapper directly in protocol.json. That would break compatibility with current users though who consider ids and not names, but I guess that's not necessarily a problem.

rom1504 avatar May 20 '16 17:05 rom1504

Making another file for this is overkill. But clearly that info deserves to be in the protocol definition. I think just making that field into a mapper might be a good idea.

Concerning API breakage, I believe it'd be nice if there was a way to get mapper to somehow accept values from the underlying type. The reasoning behind that is quite simple : I sometimes want to send "invalid" value to support a mod or otherwise test the protocol for Fun Stuff ;). And it'd allow us to provide a way to not break API as a bonus. I'll have to look into that a bit. On May 20, 2016 7:13 PM, "Michael Carpenter" [email protected] wrote:

I'm currently implementing a generator for minecraft-data that will produce complete Haskell implementations for each protocol version currently present. However, due to how significant static typing is to my target language, it would be very useful to have the various enum values in the protocol included somewhere such that I can bound their respective packet fields to only valid values that actually have meaning.

For instance, this enum exists:

Animation 0 Swing main arm 1 Take damage 2 Leave bed 3 Swing offhand 4 Critical effect 5 Magic critical effect

This information can be statically encoded through Haskell's type system as an algebraic data type like such:

data Animation = SwingMainArm | TakeDamage | LeaveBed | SwingOffhand | CriticalEffect | MagicCriticalEffect deriving (Show,Eq,Enum)

Where the Enum at the bottom automatically maps SwingMainArm to 0, TakeDamage to 1, etc.

This allows me to generate functions that encode and decode the field to recognize and enforce valid animation values.

encodeAnimation :: Animation -> Word8 decodeAnimation :: Word8 -> Either String Animation

This way my API abstracts away from raw bytes and can instead talk at a type level in terms of the meanings those bytes have from the perspective of the protocol. Even better, Haskell's API documentation tool can produce some very helpful documentation if it's fed types like the one above instead of just explanatory comments informing the user which byte values actually mean something within the context of the current version of the protocol. They shouldn't have to keep track of how game state and behaviors serialize, that's the whole reason I'm writing this library in the first place.

So I guess the realization of this feature request would probably take the form of a enum.json included in each protocol version directory that provides mappings of bytes to names for each enum present in the given protocol version. So something like:

"enum": [ "container", [ { "name": "animation", "type": [ "mapper", { "type": "u8", "mappings": { "0x00": "swing_main_arm", "0x01": "take_damage", "0x02": "leave_bed", "0x03": "swing_offhand", "0x04": "critical_effect", "0x05": "magic_critical_effect" } } ] }, etc,etc,etc... ] ]

There would then need to be some way to map these enums onto their intended fields in protocol.json. Perhaps by specifying packet ID for all packets that use the enum field.

— You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub https://github.com/PrismarineJS/minecraft-data/issues/135

roblabla avatar May 20 '16 17:05 roblabla

Interesting, I was not aware ProtoDef existed - what exactly is it providing over minecraft-data? I see that it documents the types found in protocol.json, but since I've basically been writing a compiler to translate this stuff, I've more or less already implemented much of what ProtoDef describes.

I agree a separate file would be overkill, I suggested enum.json for the sake of backwards compatibility - the data is there for those who want it and everyone else gets to stick to the current protocol.json. But if breakage isn't the end of the world right now, great! I'd imagine for protocol.json it could be injected into the "packet" container along with the "name" and "params" mappings.

zimurgh avatar May 20 '16 17:05 zimurgh

ProtoDef aims to be a generic binary protocol description. You feed it a Json and it will give you a simple way to serialize/deserialize those packets.

ProtoDef implementations are able to read minecraft-data's Json and provide an API for reading/writing the packets.

roblabla avatar May 20 '16 18:05 roblabla