From 9fe1334d286b3d2d9676ebf0bdf9acd844279812 Mon Sep 17 00:00:00 2001 From: James Protzman Date: Sun, 23 Aug 2026 00:11:18 -0700 Subject: [PATCH 1/2] Set default mag color --- internal/character_server.go | 11 +++++++++++ internal/defaults.go | 15 +++++++++++++++ internal/items.go | 3 ++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/internal/character_server.go b/internal/character_server.go index abc0718..b214136 100644 --- a/internal/character_server.go +++ b/internal/character_server.go @@ -528,6 +528,17 @@ func (s *CharacterServer) handleCharacterUpdate(ctx context.Context, c *Client, // Set up the starting inventory. copied := copy(newCharacter.Inventory.Items[:], DefaultInventory[:]) copied += copy(newCharacter.Inventory.Items[copied:], DefaultWeaponsByClass[int(charPkt.Visual.Class)]) + + colorIdx := charPkt.Visual.Costume + if class := charPkt.Visual.Class; class == 2 || class == 4 || class == 5 || class == 9 { + colorIdx = charPkt.Visual.Skin + } + + // Set up the starting Mag. + mag := DefaultMag + mag.Item.Data2[3] = DefaultMagColors[charPkt.Visual.Class][colorIdx] + + copied += copy(newCharacter.Inventory.Items[copied:], []commands.CharacterInventoryItem{mag}) newCharacter.Inventory.NumItems = uint8(copied) // We're done, persist the new character. diff --git a/internal/defaults.go b/internal/defaults.go index 32ac937..917d34c 100644 --- a/internal/defaults.go +++ b/internal/defaults.go @@ -152,3 +152,18 @@ var DefaultVisualConfigForce = []uint8{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, } + +var DefaultMagColors = [][]uint8{ + {0x09, 0x01, 0x02, 0x11, 0x0A, 0x05, 0x06, 0x0B, 0x05, 0x00, 0x07, 0x0B, 0x0C, 0x04, 0x05, 0x06, 0x0E, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x01, 0x02, 0x11, 0x04, 0x05, 0x06, 0x08, 0x11, 0x0D, 0x01, 0x02, 0x0C, 0x04, 0x05, 0x06, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x01, 0x02, 0x11, 0x04, 0x0E, 0x06, 0x01, 0x0E, 0x09, 0x07, 0x02, 0x11, 0x04, 0x05, 0x06, 0x04, 0x11, 0x0D, 0x01, 0x0B, 0x11, 0x0D, 0x05, 0x06}, + {0x00, 0x01, 0x0B, 0x11, 0x04, 0x05, 0x06, 0x0F, 0x05, 0x09, 0x07, 0x02, 0x11, 0x04, 0x05, 0x0F, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x01, 0x0B, 0x11, 0x0A, 0x05, 0x06, 0x06, 0x09, 0x09, 0x01, 0x02, 0x11, 0x0A, 0x0E, 0x06, 0x01, 0x04, 0x0D, 0x07, 0x01, 0x0C, 0x0A, 0x05, 0x06}, + {0x10, 0x07, 0x02, 0x11, 0x0A, 0x05, 0x0A, 0x00, 0x07, 0x00, 0x01, 0x08, 0x11, 0x04, 0x09, 0x0F, 0x0D, 0x02, 0x0A, 0x07, 0x02, 0x0C, 0x04, 0x0E, 0x0E}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x10, 0x01, 0x00, 0x07, 0x02, 0x0C, 0x04, 0x05, 0x06, 0x10, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x0D, 0x01, 0x02, 0x11, 0x04, 0x05, 0x06, 0x00, 0x11, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x04, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x10, 0x05, 0x09, 0x01, 0x0B, 0x0C, 0x04, 0x05, 0x06, 0x0E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x01, 0x02, 0x0C, 0x04, 0x05, 0x0F, 0x0A, 0x04, 0x0D, 0x01, 0x08, 0x11, 0x04, 0x05, 0x0F, 0x05, 0x10, 0x10, 0x07, 0x02, 0x0B, 0x0A, 0x0A, 0x0F}, + {0x00, 0x01, 0x0B, 0x0C, 0x04, 0x05, 0x06, 0x08, 0x0A, 0x0D, 0x07, 0x02, 0x11, 0x0A, 0x05, 0x06, 0x01, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x07, 0x02, 0x11, 0x04, 0x05, 0x06, 0x09, 0x0C, 0x00, 0x01, 0x02, 0x11, 0x0D, 0x05, 0x10, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, +} diff --git a/internal/items.go b/internal/items.go index 656891b..55876a7 100644 --- a/internal/items.go +++ b/internal/items.go @@ -28,9 +28,10 @@ var DefaultInventory = []commands.CharacterInventoryItem{ {Item: NewItemData(0x0301000000040000, 0)}, {Item: NewItemData(0x0300000000040000, 0)}, {Item: NewItemData(0x0101000000000000, 0), Flags: commands.ItemFlagEquipped}, - {Item: NewItemData(0x02000500F4010000, 0x0000000028000012), Flags: commands.ItemFlagEquipped}, } +var DefaultMag = commands.CharacterInventoryItem{Item: NewItemData(0x02000500F4010000, 0x0000000028000012), Flags: commands.ItemFlagEquipped} + // DefaultWeaponsByClass are the class specific starting weapons, in canonical order of class. var DefaultWeaponsByClass = [][]commands.CharacterInventoryItem{ {{Item: NewItemData(0x0001000000000000, 0), Flags: commands.ItemFlagEquipped}}, From f791e9a2723f51a09ddd273d3301bc42d6605d43 Mon Sep 17 00:00:00 2001 From: James Protzman Date: Sun, 23 Aug 2026 00:52:53 -0700 Subject: [PATCH 2/2] Set up techniques for new characters Forces should start with Foie. No other class starts with a technique. --- internal/character_server.go | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/internal/character_server.go b/internal/character_server.go index b214136..9e47966 100644 --- a/internal/character_server.go +++ b/internal/character_server.go @@ -469,6 +469,10 @@ func SendParameterChunk(ctx context.Context, c *Client, chunkData []byte, chunk }) } +func IsForce(charPkt *commands.CharacterSummary) bool { + return charPkt.Visual.ClassFlags > 80 +} + // Performs a create or update/delete depending on whether the user followed the // "dressing room" or "recreate" flows (as indicated by a client flag). func (s *CharacterServer) handleCharacterUpdate(ctx context.Context, c *Client, charPkt *commands.CharacterSummary) error { @@ -506,7 +510,6 @@ func (s *CharacterServer) handleCharacterUpdate(ctx context.Context, c *Client, }, // Set the character's attributes directly from the preview packet. Visual: charPkt.Visual, - // TechLevels: }, Signature: 0xC87ED5B1, OptionFlags: 0x00040058, @@ -516,7 +519,7 @@ func (s *CharacterServer) handleCharacterUpdate(ctx context.Context, c *Client, visualConfig := DefaultVisualConfigHunterRanger // TODO: Sooner or later probably ought to add constants for the classes. - if charPkt.Visual.ClassFlags == 0x80 { + if IsForce(charPkt) { visualConfig = DefaultVisualConfigForce } copy(newCharacter.DisplayData.Config[:], visualConfig) @@ -541,6 +544,19 @@ func (s *CharacterServer) handleCharacterUpdate(ctx context.Context, c *Client, copied += copy(newCharacter.Inventory.Items[copied:], []commands.CharacterInventoryItem{mag}) newCharacter.Inventory.NumItems = uint8(copied) + // All characters start with no techniques. + techLevels := [20]uint8{} + for i := range techLevels { + // disabled + techLevels[i] = 0xFF + } + + // Forces, however, start with Foie. + if IsForce(charPkt) { + techLevels[0] = 0x00 + } + copy(newCharacter.DisplayData.TechLevels[:], techLevels[:]) + // We're done, persist the new character. err = shipgate.Shipgate.UpsertCharacter(ctx, c.Account.ID, charPkt.Slot, newCharacter) if err != nil {