FFXIV 1.0 Classic Server Dev Blog

Taking a look at inventory packets with experienced eyes...

With all the experience and familiarity I have now working with 1.0, it's protocol, and reverse engineering... I took another look at the inventory packets. These were one of the first things I tackled when I first started and you can see my post here and here. Anyway I figured out that I got a lot of it wrong and overcomplicated things. Simply put, the game has 3 types of inventory body packets (items, equipment index, and an unknown type which I am not sure what it's used for), that come in entry sizes of 1, 8, 16, 32, and 64. Yes, you can set 64 equipment indices at once even though there are only 20 or so. I guess SE was future proofing?
The opcodes are:

0x0146	Inventory Chunk Start
0x0147	Inventory Chunk End
0x0148	Inventory List (x01)
0x0149	Inventory List (x08, variable)
0x014A	Inventory List (x16)
0x014B	Inventory List (x32)
0x014C	Inventory List (x64)
0x014D	Set Equipment Id (x01)
0x014E	Set Equipment Id (x08, variable)
0x014F	Set Equipment Id (x16)
0x0150	Set Equipment Id (x32)
0x0151	Set Equipment Id (x64)
0x0152	Unknown (x01)
0x0153	Unknown (x08, variable)
0x0154	Unknown (x16)
0x0155	Unknown (x32)
0x0156	Unknown (x64)

0x016D	Inventory Start
0x016E	Inventory End

and how it works is:

[16D]
	[146 (Capacity, Code)]
		[14B]
		[14B]
		[14A]
	[147]
	[146 (Capacity, Code)]
		[149]
	[147]
[16E]

In this case, two sets of item types (say inventory and key items) are being changed, with the first one changing 32 + 32 + 16ish (can be less for the last one), while the second one is doing just up to 8.

Big List of Progress

If you've been following my Youtube channel you may already know about some of the progress I've made. Over the last week I've been jumping from one part of the server to the next. First; With the scripting system somewhat built I could get some of the game commands working. I wrote a bunch of npc scripts to say their spiel when you talk to them, as well as the script needed for riding a chocobo, emotes, rolling a dice, and switching between active and passive modes. A few of the side menu scripts were also written but I'll need to take a better look at how those work (it's difficult to find what part of the menu the player is in from the server's point of view). Here is a video of both the chocobo script and it in action:

Behind the scenes I rewrote how zones work, allowing for both isolated zones and private areas (a concept the game uses). A "zone" is a public area where all player coexist, while a private area is a instance inside the zone, used for quest phasing, instance dungeons, and areas like the market ward. Isolated zones are public zones that do not share the existence of other players to one another. This is used for things like the inn and opening areas. Speaking of multiplayer, I fixed an issue with the pong (server response to the client's ping) packet and player updates are sent a lot more quickly. Here is a multiplayer test I did sometime ago:

as well as the dice roll command working:

undefined

With scripts, npcs, and the isolated zones working properly... I began playing with the opening scenes' scripts. Basically it involves running a bunch of functions in the Quest Actor (man0l0 for limsa), which triggers various things like playing a cutscene. I haven't scripted anything (that will require quest scripts on the server), but here is what I got so far:

Here are some of the starting zones filled in:

undefined

undefined

annnnnd finally! I have finished figuring out 90% of the battle action packets (0x139, 0x13A, 0x13B, 0x13C). These four packets handle playing a battle animation (from auto attacking, using a WS, Ability, Spell, etc) and showing various feedback (scrolling combat text, the visual effect, the log message, ui graphics). These packets are all the same, the only difference being how many actions each can hold. 13C doesn't hold any actions and just plays an animation. 139, 13a, and 13b hold 1,10, and 18 actions respectively. An action takes a textId (the log message), and amount (damage, exp gain, healed, etc), a param (direction, body attack, chain timer number, etc), and an effect id (this handles the SCT to show the damage, if it was a miss, crit, etc. Also a status icon if it's status gained.). So if you do wide volley and hit 14 enemies, most likely 13B will be sent to show all the stuff. Here is me going through the effect ids:

Also here is a bunch of actions I tested... from mobs linking, to EXP Chain timers:

undefined

Anyway, that's the big update of the progress so far!

Original Images can be found: http://imgur.com/a/nyzv2

Npc progress and more

I've made a lot of progress with npcs, figuring out the last few packets related to actors. Using the exe's RTTI data (debug info left over from when the game was compiled) there was, I was able to find the true names for a lot of the packets. Here are some of the ones I found:

0x12E: SetTalkEventCondition
0x16B: SetNoticeEventCondition
0x16C: SetEmoteEventCondition
0x16F: SetPushEventConditionWithCircle
0x171: SetPushEventConditionWithFan
0x175: SetPushEventConditionWithTriggerBox

0x12F: KickClientOrderEvent
0x138: SetTargetTime
0x18E: ChangeSystemStat

0x1A2: JobQuestCompleteTriple
0x1A5: EntrustItem (????)
0x1A6: HamletSupplyRanking
0x1A8: HamletDefenseScore

The big win is the first group. These are used to set how an actor will activate an event. The talk condition is when a player targets and presses 'enter' on an npc. The notice condition I am still figuring out. Emote is when a npc is emoted. Finally push conditions are activated when a player touches the bounding box defined. The bound box can take the shape of a circle, fan, or box. I've also found the last of the 0x1A_ packets.

I haven't looked at all of these packets nor have I figured out all their fields, however I have finished working on the talk, notice, and emote condition packets... and built the code to manage all that. The npc table in the DB also has a new column storing these conditions. I used a json object to defined them... since there can be any number of conditions. With this all setup, I've removed all the inn room actors from the hardcoded packets and moved them into the db. Suffice to say they are working correctly. The only actor I haven't move is the inn room door due to push packets not full implemented (will be soon).

undefined

With npcs working, I was able to test the instance system. Each player has their own personal "instance" of actors they can see. As you move around, actors are added and removed as they enter/exit your surroundings. Packets are sent to update the client's own instance. While actors were being added, I didn't really have a way to test if they were being removed since there wasn't anything dynamic. I've fixed it up and now you will no longer see inn room actors in the middle of Coerthas.... actually due to the inn room door still being hard coded (as mentioned above), my server is blind to it and it still appears under Dzemael Darkhold if you warp to Coerthas lol.

undefined

You may notice some commands in the chat log. I have also rewritten the server command function to allow for both the server console and the in game log to fire off commands.

undefined

Now that we have zones... let's put some NPCs in...

I've started writing the db tables to store all the NPCs as well as the code to load and display them. There are a lot of NPCs in FFXIV but luckily the client has an internal table of all of them. Well... kinda. There are three main sheets that have to deal with NPCs: actorClass, actorGraphic, and xtx/displayName. ActorClass and ActorGraphic both share the same ids, and are linked together 1-1. I have a suspicion that this file is duplicated on the server but contains a lot more info (position, animation, etc) because all the fields are empty except for "displayName id". The displayName id links to xtx/displayName which contains the name of every NPC in the game. ActorGraphic has all the model, head, armor, and weapon Ids needed to set the appearance. With this data, the really hard part; name and appearance is already done! Also because the appearance data is the same as the player's appearance data (they are both character actors), you can set characters to look like NPCs!

Note: an NPC can be a static talkable one OR a monster. 

Here is my character looking like Y'shtola:

undefined

This was an earlier attempt that had a bug, resulting in a hilarious glitch:

After getting the data uploaded and the NPC's loading I worked on the code that would send the correct actor packets to the clients so it would appear to players. This was pretty quick after some bugfixing due to player actors already using this same system for multiplayer. I still need to implement some NPC specific packets relating to events before it can be finished, but below is some actors I spawned. Their names are grey because they have no health state (so technically "dead") and no "talkEvent" handler set which would have made their names green like most NPCs.

undefined

 PS: Just realized comments were disabled >.<. Enabled em on all pages.

Freeeedom: Zoning now works!

I was originally going to publish a post titled "minor update" as I connect more parts of the player to the database... but then for the last three days I made huge strides with zoning. First; I was able to find the internal table that defined all the zones in the game, and a lot of their zone names. This will aid in creating actors later as well as managing and splitting the whole world up. Here is the database table that stores all the zones and their settings:

undefined

http://i.imgur.com/hTCJ7PC.png

Next, I decoupled a lot of systems that were being jammed into the packet processor since I was just figuring things out and writing over time. Now that player login works and I have a list of zones... I moved all zone related things into a "WorldManager". This handles moving the player actors around between the various zones and also informing the player actors to send packets to their clients when needed.

With this system in place, I could write the code to signal a client to do a zone change. Suffice to say... it seems to work flawlessly, and even didn't have the weird graphically glitch Seventh Umbral had. It seems if things aren't 100%, the character will move before the screen fades causing a weird jump into the void. Not the case with this.

I also found the last bit of info about the packet header. First, game packets aren't encrypted... only compressed (lobby packets are however). Second, when you first connect, a field I didn't notice before informs the server what the connection type of that socket is... either Zone or Chat. XIV uses two connections on two separate ports. Before this code was a total mess, but after finding this field... it's much cleaner and less error prone.

Before I started this work I was going to mention: all achievement data is now loaded from the DB, and the debug and WorldMaster (now handled by the WorldManager) actors are generated by the server. This means only npc actors are left in the "hardcoded" files I use to simulate login. Soon the server will be able to do it fully on it's own w.o help from sniffed hardcode packets.

 

Newer posts → Home ← Older posts