Up to Main Index                              Up to Journal for June, 2021

                     JOURNAL FOR SATURDAY 5TH JUNE, 2021

SUBJECT: I nearly have my world back
   DATE: Sat  5 Jun 19:15:52 BST 2021

The recent ‘code sprint’ has continued and I’ve been spending most of my spare
time continuing to hack away on WolfMini.

The above title is somewhat inaccurate. What I actually have are locations and
things loading into WolfMini from the zinara.wrj zone file. Walking around the
zone is very eerie, nothing is happening — no guards patrolling, the vendor
not shouting, the tavern door not closing. Without any events being scheduled
everything is frozen in time.

The loader I’m using is one heck of a lash up. I’ve copied over the recordjar
and text packages from WolfMUD proper. I also copied the zone preprocessor to
handle the zone file @refs. I’ve then hacked up a quick loader which only
understands  a few basic attributes: name, description, narrative, location,
inventory, exit and door. The loader can just about manage to resolve item
references and cobble the zone together enough for me to go wandering around.
Aliases are not handled properly yet, I’m still using a single alias parser.
To open the tavern door I have to use "open +tavern” as aliases are defined in
the zone file using a qualifier as “+TAVERN DOOR” and I only pick the first
alias at the moment.

Still, it’s progress…

The loader is about 100 lines of code. It still needs to handle the remaining
item attributes, multiple zones and a whole bunch of other stuff.

To make writing the loader easier I slightly altered the new Thing, dropping
the Thing.Name, Thing.Description and Thing.UID struct fields and making them
Thing.As entries. Name is retrieved as Thing.As[Name] instead of Thing.Name
for example. The UID is the familiar “#UID-xxx” as in WolfMUD. Having made
everything an attribute, and not treating the UID, name and description as a
special case, greatly simplified the loader.

Due to that large refactoring, which I’d planned for, I still have tests to
write. I have documented a lot of the code, just need the tests…

I’ve still got a few ugly corners I need to poke. The main two being numeric
attributes and keyed attributes. The current Thing is:

  type Thing struct {
    Is  uint32
    As  map[uint32]string
    In  []*Thing

I need a way to store numeric attributes and multi-value attributes. Numeric
attributes I can probably handle with a map[uint32]int. Multi-value attributes
can be handled as map[string][]string maybe? The multi-value is mostly for
aliases and vetoes where I’d access them with something like item.Any["Alias"]
and item.Any["VETO:GET"]. I’m a little unhappy about the composite key being
‘VETO:GET’, but the alternative is something like map[uint32][string][]string…

My current Thing as of writing this is defined as:

  type (
    isKey  uint32 // index for Thing.Is
    asKey  uint32 // index for Thing.As
    anyKey string // index for Thing.Any

  type Thing struct {
    Is  isKey               // Bit flags for item capability/state
    As  map[asKey]string    // Single value for an id
    Any map[anyKey][]string // Any value in a list for a key
    In  []*Thing            // Inventory for the item

All of the key values for Is, As and Any are defined as named constants. The
keys for ‘Any’ can be mostly defined as constants, although I need to think
more about the composite keys. The reason for defining all of the keys as
constants is so that they are documented and values don’t get picked and used
willy-nilly. I’m thinking that if an Any key has a colon ‘:’ suffix as in
‘Veto:’ it’s an indication that it’s a composite key. So ‘Veto:’ defined as
the constant ‘Veto’ might be used as item.Any[Veto+"GET"] as in the example
below. A key of ‘Alias’, on the other hand, defined as the constant Alias,
would be used as item.Any[Alias]. Some other usage examples:

  if item.Is&Open == Open { ... }
  if item.As[Name] != "" { ... }
  if item.Any[Veto+"GET"] != nil { ... }
  for _, v := range item.Any[Alias] { ... }
  for _, item := range item.In { ... }

One really nice Go feature is that zero values work really well here. I think
the fields also make the code quite readable.

I’m not sure who I’m trying to convince here — you, dear reader, or myself.
It’s one of those situations where you have to try an approach and then
iterate or start over until it feels right. When does it feel right? Hard to
say, as a programmer you know, just like you know when it feels wrong ;)


  Up to Main Index                              Up to Journal for June, 2021