Author Topic: Technical side discussion  (Read 164648 times)

Codewalker

  • Hero of the City
  • Titan Network Admin
  • Elite Boss
  • *****
  • Posts: 2,740
  • Moar Dots!
Re: Technical side discussion
« Reply #100 on: July 15, 2015, 03:31:29 AM »
For example, when the costume file data has quotation marks surrounding the name of the element, I am guessing those are just for the file format and they get stripped when the costume file is uploaded into City of Heroes.

Yes, those are just part of the generic text format the COH uses for everything. The quote marks are not part of the name and are parsed out by the client.

Second, for the 3D scales byte order is not explicitly specified.  It actually says the data is packed into a 32-bit integer and then converted back into hex, but the intervening int representation poses an odd and avoidable ambiguity.

Byte order shouldn't matter, as it's the hex representation of the number regardless of platform, not the representation of how that number is stored in memory. If it helps, assume big endian.

Or you could just call it "00" followed by three 8-bit signed integers, that would work, too.

Arcana

  • Sultaness of Stats
  • Elite Boss
  • *****
  • Posts: 3,672
Re: Technical side discussion
« Reply #101 on: July 15, 2015, 09:36:53 AM »
Also, dammit I really can't see any way around implementing a sequence engine if I want my animations to look right.  Have to dig up my root calculator and adapt that.  Not exactly hard, just ugh.

After thinking about it for a while and conducting experiments, there is a possibility that involves not implementing an entire sequence engine, which I think is overkill for a bot.  You could make a skeleton one that only has the moves you're interested in, and that would also be simple enough for people to tinker with.

This is extremely unoptimized, but I was fiddling with an idea like this:

Code: [Select]
jog_moves = [['RUNPRE', 'RUN_BACK_PRE', 'RUN_LEFT_PRE', 'RUN_RIGHT_PRE'],
             ['pcRUNCYCLE','pcRUN_BACK_CYCLE','pcRUN_LEFT_CYCLE','pcRUN_RUGHT_CYCLE'],
             ['RUNPOST', 'RUNPOST', 'RUNPOST', 'RUNPOST']]
fly_moves = [['A_FLYPOSE1_PRE', 'A_FLYPOSE1_PRE','A_FLYPOSE1_PRE','A_FLYPOSE1_PRE'],
             ['pcA_FLYPOSE1_CYCLE','pcA_FLYPOSE1_CYCLE','pcA_FLYPOSE1_CYCLE','pcA_FLYPOSE1_CYCLE'],
             ['A_FLYPOSE1_POST', 'A_FLYPOSE1_POST','A_FLYPOSE1_POST','A_FLYPOSE1_POST']]
walk_moves = [['PLAYER_WALK_FORWARD','PLAYER_WALK_BACKWARD','WALK_LEFT_PRE','WALK_RIGHT_PRE'],
              ['pcPLAYER_WALK_FORWARD_CYCLE','pcPLAYER_WALK_BACKWARD_CYCLE','pcWALK_LEFT_PRE_CYCLE','pcWALK_RIGHT_PRE_CYCLE'],
              ['PLAYER_WALK_POST','PLAYER_WALK_POST','PLAYER_WALK_POST','PLAYER_WALK_POST']]
pc_moves = []
pc_moves.append(jog_moves)
pc_moves.append(fly_moves)
pc_moves.append(walk_moves)

So I create an array of moves.  Each array element is itself a three element array which has intro moves, cycle moves, and exit moves.  These happen to handle movement and there's four movement directions (that the animation system honors): forward, left, right, and back, so there's four entries per.  The idea is that when you hit a movement key, the system looks up what MOV to send based on your current movement mode (run, fly, walk) and the direction you're moving (basically, wasd keys).  It then sets that animation and sends it.  On the next clock tick, if the current animation MOV state is any of the Prefix ones (by searching for them), the system automatically sets the next in the sequence.  If no keys are being pushed, the system checks to see if we are currently in any of the CYCLE states, and if so it sets to the POST MOV.  And one gimmick, when I send <u /> if the current animation state begins with "pc" I don't send that MOV.  Basically, I could have called them pcANYTHING but I just chose to call those moves what they actually are for (my) sanity sake.

The general idea is to make a state engine that is a micro version of the real sequencer with animation sequences with a single entry point and an exit point and a criteria for when to stay in the middle of the cycle and when to exit.  Then the bot writer can decide which sequences they care about and hard code them into the bot.  If they want to have the entire sequence library at their disposal, well, there is that dump of the sequence file they could choose to import and parse.  But this simplifies things greatly in theory, although I need to think a bit more about how to deal with non-movement sequences: the movement ones were special cases I wanted to fool around with first.

You know, I'm beginning to think this might have actually taken some serious time for Codewalker to implement.

Anyway, here's some test footage of my bot running, walking, and sort of flying.  Also, flying backwards.  Unlike game clients, bots don't have to make sense.

https://www.youtube.com/watch?v=Vd8FPTYcktw

I got half way through writing a costume hasher, then got bored.  Yawn.  I should have that finished tomorrow, and then I'm going to take a swing at maps.  Just enough to get by, not enough to re-render the entire environment.  Floor and wall collision mostly.  I still want to kick something, but I can't do simulated knock until I find the ground, and without that what's the point.

Firi1

  • Underling
  • *
  • Posts: 4
Re: Technical side discussion
« Reply #102 on: July 15, 2015, 01:48:26 PM »
Have you considered looking into generating nav meshes for the maps? In concept its much more realiayuc than hardcoded or breadcrumb style nav, but honestly its way beyond me at this point, but ive been thinking about ots off and on for years. I have seen it implemented for other game bots... gonna stop rambling here...

Leandro

  • Elite Boss
  • *****
  • Posts: 310
Re: Technical side discussion
« Reply #103 on: July 15, 2015, 02:19:04 PM »
Have you considered looking into generating nav meshes for the maps?

The client has some remnants of the nav mesh system that Paragon used (called beacons, with the process of generating them called beaconizer). I don't know if CW is planning to reimplement the same format in order to preserve the bits in the client that are compatible with it (mostly just debugging tools) or go in a different direction. I'd bring it up to him before trying to implement anything, to make sure the effort isn't duplicated or gone to waste.

Ironwolf

  • Stubborn as a
  • Elite Boss
  • *****
  • Posts: 1,503
Re: Technical side discussion
« Reply #104 on: July 15, 2015, 02:47:47 PM »
So what if you had someone who was working on rendering all of the City of Heroes maps into like a new game engine or something would that help Arcana?

I am kind of thinking perhaps meshing this effort with Irish Girls.....................

Arcana

  • Sultaness of Stats
  • Elite Boss
  • *****
  • Posts: 3,672
Re: Technical side discussion
« Reply #105 on: July 15, 2015, 05:47:18 PM »
So what if you had someone who was working on rendering all of the City of Heroes maps into like a new game engine or something would that help Arcana?

I am kind of thinking perhaps meshing this effort with Irish Girls.....................

On the one hand, that's massive overkill for what I need.  On the other hand, its also not what I need at all; what I need is less "how to read the map?" and more "what should I do with the map?"  This is not as straight forward as it sounds, as nothing really is.  For example, most players think of performing an animation as "perform animation" but to get those movements looking correctly above I needed to send the movement prefix animation, let the game fall naturally into the cycling animation, never send the pre again, check to see if the movement should no longer be happening, check to see if it is actually still happening, and if so send the prologue animation and then never send that again and let the game fall naturally out of it.  It basically requires a state engine, to send something when a key is pressed and but only once, to send another thing when the key is released but only once and only if you're in another state.  And even then you learn things.  For example, there's no such thing as walk backwards.  Interestingly, the walk backwards animation actually pivots the character 180 degrees.  Notice in the video above there is a way to run backwards and there is even sort of a way to fly backwards, but walk backwards does something unexpected.

Well, reading the map is one thing.  Then there's the question of how you honor the map.  Its not just a matter of "don't be below the ground level."  A naive approach would simply to be to move in any direction you want, and then clamp your y axis minimum to the map minimum.  But the map is three dimensional:  walking around steel canyon would cause you to sometimes warp underground.  And if you move towards a building, I don't think you want to instantly teleport to the roof (or maybe you do, but probably not by default).   You need some logic for deciding what moves are legal, and which have to be simply truncated due to collision with geometry.  And you could try to figure out what the game itself did, or you could decide the bot should have different rules.  Should it automatically hop fences, like the NPCs did?  Should it walk up walls (I think that will gimbal lock the character, but we'll see).

The rules are really the thing.  The map itself is an inconvenience.

Ironwolf

  • Stubborn as a
  • Elite Boss
  • *****
  • Posts: 1,503
Re: Technical side discussion
« Reply #106 on: July 15, 2015, 05:54:45 PM »
I guess that's what I am saying - does she have those rules already in place or is what she is doing strictly graphical in nature at this point?

I know you don't need the game engine at this point but she is recreating Paragon mapping as well. I guess I don't know if those rules would port over from that engine or not.


Arcana

  • Sultaness of Stats
  • Elite Boss
  • *****
  • Posts: 3,672
Re: Technical side discussion
« Reply #107 on: July 15, 2015, 05:55:30 PM »
Have you considered looking into generating nav meshes for the maps? In concept its much more realiayuc than hardcoded or breadcrumb style nav, but honestly its way beyond me at this point, but ive been thinking about ots off and on for years. I have seen it implemented for other game bots... gonna stop rambling here...

Generating?  No.  At least, not at the moment.  Supporting?  Maybe.  Which is to say, I've been thinking about a way for the bot writers themselves to create their own "safe zone navigation areas" for their bots, within which the bots could have more autonomy in motion, or goal-seeking behavior.  In fact, it occurred to me when Codewalker mentioned monkey fight club that it would be an interesting idea if the bots could have a preprogrammed pseudo-fence within which they were allowed to maneuver pseudo-randomly while they fought.

But autogenerating navigation meshes?  I'll leave that as an exercise for the reader.

Arcana

  • Sultaness of Stats
  • Elite Boss
  • *****
  • Posts: 3,672
Re: Technical side discussion
« Reply #108 on: July 15, 2015, 05:57:06 PM »
I guess that's what I am saying - does she have those rules already in place or is what she is doing strictly graphical in nature at this point?

I don't have first hand knowledge, but I thought her efforts were strictly modeling in nature.  There's no algorithmic nature to her project, nor would there be any logical reason for her to construct one (at the moment).

Arcana

  • Sultaness of Stats
  • Elite Boss
  • *****
  • Posts: 3,672
Re: Technical side discussion
« Reply #109 on: July 15, 2015, 06:01:44 PM »
The client has some remnants of the nav mesh system that Paragon used (called beacons, with the process of generating them called beaconizer). I don't know if CW is planning to reimplement the same format in order to preserve the bits in the client that are compatible with it (mostly just debugging tools) or go in a different direction. I'd bring it up to him before trying to implement anything, to make sure the effort isn't duplicated or gone to waste.

My concern with the beaconizers is that they may have been subtly optimized for what the devs wanted NPCs to do, pathing-wise, which might be contrary to what some bot writers would want to do, particularly as bot writers might explicitly want to do "unsafe" things relative to conventional NPC spawns.  But honestly I have no real idea until I get there, and I'm a long ways away from there.  I generally tell Codewalker whenever I am thinking about an area outside of what Paragon Chat has already implemented, usually by asking him to increase the area within which Paragon Chat is implemented.

Codewalker

  • Hero of the City
  • Titan Network Admin
  • Elite Boss
  • *****
  • Posts: 2,740
  • Moar Dots!
Re: Technical side discussion
« Reply #110 on: July 15, 2015, 06:03:18 PM »
(I think that will gimbal lock the character, but we'll see).

I would recommend not using PYR for your internal state. Paragon Chat itself uses a 4x4 matrix to represent the state for each entity and only normalizes the orientation to PYR in order to save in the database and transmit over the wire. The protocol to talk to the client itself uses quaternions to represent orientation, but I didn't duplicate that in XMPP because I didn't want to make people's head explode when they tried to write something to speak the XMPP version.

PYR works well enough for gross orientation sync, and since no transformations are actually taking place on it in that form, gimbal lock isn't an issue.

Eventually I'd like for the scripting interface (or even some sort of external API) to make this a lot easier, so that bots can plug in to Paragon Chat and take advantage of its geometry representation, animation sequencer, and collision engine that is reasonably close to the client's. That would avoid having to re-invent the wheel (again). It's just a matter of time, but for now the hard way is the only way.

Arcana

  • Sultaness of Stats
  • Elite Boss
  • *****
  • Posts: 3,672
Re: Technical side discussion
« Reply #111 on: July 15, 2015, 07:04:04 PM »
I would recommend not using PYR for your internal state. Paragon Chat itself uses a 4x4 matrix to represent the state for each entity and only normalizes the orientation to PYR in order to save in the database and transmit over the wire. The protocol to talk to the client itself uses quaternions to represent orientation, but I didn't duplicate that in XMPP because I didn't want to make people's head explode when they tried to write something to speak the XMPP version.

PYR works well enough for gross orientation sync, and since no transformations are actually taking place on it in that form, gimbal lock isn't an issue.

At the moment I use PYR for the bot state just because its simple, and because I currently have no way to tell the bot to face upward anyway.  As soon as I do, yeah, I would need to switch to a non-PYR (almost certainly quaternion) model to avoid problems.  The bot is doing an enormous amount of cheating to keep things simple at present, specifically to avoid the very problem I recommended Joshex avoid.

Also, if I went straight to numpy's matrix math for transformations, that would obscure some of the mechanics of what was happening behind less than transparent math, and Linear Algebra was 29 years ago even for me.  I hope at some point normal people can read the code and figure out what it is doing.  Although I was already thinking that computing rotational paths between two random defined orientations was already going to probably require (or rather be easier with) quaternions.  For when I can actually *face* random orientations outside the xz plane.

Quote
Eventually I'd like for the scripting interface (or even some sort of external API) to make this a lot easier, so that bots can plug in to Paragon Chat and take advantage of its geometry representation, animation sequencer, and collision engine that is reasonably close to the client's. That would avoid having to re-invent the wheel (again). It's just a matter of time, but for now the hard way is the only way.

Which is partially why I'm trying to reinvent as little wheel as I can get away with, while still being functional (and why I'm often looking for ugly cheats rather than complete solutions in some cases).  Ordinarily, I would have just jumped straight to the finish line, because every intermediate step between here and there is somewhat redundant when it comes to implementing solutions.  But that seems sideways to the point here.

Arcana

  • Sultaness of Stats
  • Elite Boss
  • *****
  • Posts: 3,672
Re: Technical side discussion
« Reply #112 on: July 15, 2015, 07:34:58 PM »
So I might as well take a quick look at maps before I head to work, give me some time to think about those.  It shouldn't be too hard to get just the information I want from...

...hmm...

Well.  Of course it would have to be.  I see.  I'm going to have to deal with all of this, aren't I.


Patch Notes: July 15, 2015

Ghostbot version 0.2a

New features:
* ArcanaBot has been renamed Ghostbot
* GhostBot can pass through walls, ground surfaces, objects, and NPCs.  This is not a bug, its a feature.

Known Issues:
* Enabling gravity can have unintended consequences

Codewalker

  • Hero of the City
  • Titan Network Admin
  • Elite Boss
  • *****
  • Posts: 2,740
  • Moar Dots!
Re: Technical side discussion
« Reply #113 on: July 15, 2015, 07:48:55 PM »
So I might as well take a quick look at maps before I head to work, give me some time to think about those.  It shouldn't be too hard to get just the information I want from...

...hmm...

Well.  Of course it would have to be.  I see.  I'm going to have to deal with all of this, aren't I.

Yes, it's a pain in the butt.

You know, I'm beginning to think this might have actually taken some serious time for Codewalker to implement.

I mentioned the XMPP phase of the project started around last November/December, but built on some existing work. What do you think I've been doing for the last couple years? :o

Arcana

  • Sultaness of Stats
  • Elite Boss
  • *****
  • Posts: 3,672
Re: Technical side discussion
« Reply #114 on: July 15, 2015, 08:32:48 PM »
Yes, it's a pain in the butt.

I'm sure Codewalker realizes this, but for the benefit of a few people who are recommending computer graphics books to me, I know a little more about this than I'm often letting on, just because I'm trying to approach this from the perspective of someone who might want to write a bot, and has to learn everything from scratch.  Also, I'm busy and lazy, and so I'm playing this completely by ear and detecting problems by running into them face first.  And I think it might be helpful if I discuss this (mostly but not always talking to myself) at a slower pace than normal.

In this case, my idea for somehow extracting just what I wanted from the map files was a bit naive.  I can always hope, but the problem with that idea is the notion that there is anything remotely called "the ground" I could pull from the map files, or anything like that.  Map files are organized by object (and probably implicitly space) trees.

See, there's just no way any game could figure out fast enough whether I hit every single thing on the map: it would take too long to check if I potentially hit thousands of different objects.  To speed that up, games with 3D collision detection all use some form of subdivision algorithm.  The idea is that rather than check to see if I hit any of a hundred trees in Atlas Park, Atlas Park itself is subdivided into groups of objects.  Each group is surrounded by a bounding box that contains all of them.  Before you go checking to see if you hit anything in the box, you first check to see if you are *inside* the box.  If you aren't, you can ignore everything in it.  If you make groups of objects, and groups of groups of objects, and groups of groups of groups of objects, you can eventually check for collisions much faster.  The ultimate in speed (but with caveats) is the binary space partitioning algorithm, where your entire map is split roughly into two parts, and each part is split into two parts, etc etc.  Even if you have a million objects, checking for collision is just a matter of making 20 checks for collision with ever smaller boxes, and then finally checking for detailed collisions between you and the few things in that final box.  That's fast.

Whether you use BSP or some other algorithm, it helps if you design the space in a manner that reflects how you intend to subdivide it.  Everything should be in one and only one box (or in a box inside a box inside a...), and the boxes should connect together in a reasonable fashion (or your map designers will go crazy).  So big maps like Atlas Park are actually "islands" of geometry, with City Hall here and the Tram station there, each with its own "ground" and all of the "grounds" connected together in a patchwork of ground.  You don't have to specifically deal with the tram, but you still have to handle the "Tram island" of geometry, which includes the ground in that area.

This is all redundant discussion for computer graphics geeks, but its something bot writers who are not computer graphics geeks need to be moderately aware of.  Or they need to make ghostbots.  There's nothing wrong with ghostbots per se.

While I'm thinking about that, I am going to redouble my efforts to get costumes and costume hashes working (of course, so far I've put in almost nothing, so that's not saying a lot).  At first, I thought combat was more interesting to get working (pseudo, no effects, shadow boxing type combat).  But last night, before I went to bed, I had an inspiration.  Now I think getting the costume hash is a lot more important.  Hopefully, by the weekend, I'll be able to demonstrate why.

slickriptide

  • Elite Boss
  • *****
  • Posts: 356
Re: Technical side discussion
« Reply #115 on: July 15, 2015, 09:20:35 PM »
When such a request is received, if the hash corresponds to a known costume, Paragon Chat will reply with a copy of the costume in the following format:

<iq to="user@domain/resource" id="id12345" type="result">
<costume xmlns="pc:costume">
  <appearance bodytype="1" scale="2.1" bone="0.5" head="0.5"
    shoulder="0.5" chest="0.5" waist="0.5" hip="0.5" leg="0.5"
    head3d="123456ab" brow3d="123456ab" cheek3d="123456ab"
    chin3d="123456ab" cranium3d="123456ab" jaw3d="123456ab"
    nose3d="123456ab" />
 

I don't see skin color in this description of the Appearance stanza. Is it safe to assume it should be included as "skincolor=123456ab"?


Codewalker

  • Hero of the City
  • Titan Network Admin
  • Elite Boss
  • *****
  • Posts: 2,740
  • Moar Dots!
Re: Technical side discussion
« Reply #116 on: July 15, 2015, 09:55:20 PM »
I don't see skin color in this description of the Appearance stanza. Is it safe to assume it should be included as "skincolor=123456ab"?

Whoops, yes, it should be an attribute of appearance. Except that it's 123456ff because alpha is always forced to ff.

Updated the original, thanks!

slickriptide

  • Elite Boss
  • *****
  • Posts: 356
Re: Technical side discussion
« Reply #117 on: July 15, 2015, 11:35:46 PM »
Okay.

The skin color value in the paragonchat.db database does not work out to anything that I can make sense of.

It sort of works when it's a positive value. Here's an excerpt from the .costume file for Element Guy:
Code: [Select]
JawScales  -0.7371,  -1,  1
NoseScales  -0.5371,  0.661,  0.3314
SkinColor  255,  178,  155
NumParts 28

Here's his character appearance record in ParagonChat.db:

Code: [Select]
select skincolor from costume where character = 3 and costume = 0;
10203903

A little handy python code tells me:
Code: [Select]
print(hex(255),hex(178),hex(155))
0xff 0xb2 0x9b
print(hex(10203903))
0x9bb2ff

So far, so good. It looks like BGR rather than RGB but otherwise the numbers are right.

Another character, Artiste, has a skin color of -9721635 in the SQL database.
His costume file defines it as: SkinColor  221,  168,  107

Here's what python says about that:
Code: [Select]
print(hex(221),hex(169),hex(107))
0xdd 0xa8 0x6b
print(hex(-9721635))
-0x945723

The minus sign on the on the hex number just represents an infinity of FF as far as I can determine.

I won't bore you with the various permutations I've tried to apply to make this work out, especially when there's probably a simple explanation for it.

So, what's going on? Why is it apparently backward for a positive value and seemingly unresolvable for a negative value?



Arcana

  • Sultaness of Stats
  • Elite Boss
  • *****
  • Posts: 3,672
Re: Technical side discussion
« Reply #118 on: July 16, 2015, 12:08:04 AM »
The order thing sounds like the thing I mentioned earlier involving pickle-packing into integers.  As to the negative numbers, that's a signed/unsigned thing.  Hint: try two's complement.

slickriptide

  • Elite Boss
  • *****
  • Posts: 356
Re: Technical side discussion
« Reply #119 on: July 16, 2015, 01:07:21 AM »
The order thing sounds like the thing I mentioned earlier involving pickle-packing into integers.  As to the negative numbers, that's a signed/unsigned thing.  Hint: try two's complement.

Bah. I knew about the two's complement but it helps things when you shift by the right number of bits when you decode.

Still, thanks for getting me to take a second look at it. I suppose I'll be shaking the rust out of a lot of barely used old skills by the time this is all said and done.

So, bottom line - the colors stored in the SQL database are BGR, and negative colors need to have (1 << 24) added to them before hexing them. I'm presuming that the other colors are encoded the same way as the skin color.

One step closer to that costume hash.