Commit Graph

527 Commits

Author SHA1 Message Date
Aaron Kimbrell
9458230f0b refactor: property game messages as structs
Converts the property messages to NetGameMsgs in PropertyMessages.{h,cpp}.
Sent: OpenPropertyVendor, OpenPropertyManagement, DownloadPropertyData
(replaces PropertyDataMessage, now with the client's PropertyData field
names), PropertyRentalResponse, PropertyEntranceBegin,
PropertySelectQuery (replaces PropertySelectQueryProperty with the
client's PropertyInfo), GetModelsOnProperty, PlaceModelResponse and
HandleUGCEquipPre/PostDeleteBasedOnEditMode. Received, registered in
GameMessageHandler's map: SetPropertyAccess,
UpdatePropertyOrModelForFilterCheck, QueryPropertyData,
PropertyEditorBegin/End, PropertyContentsFromClient,
ZonePropertyModelEquipped/Rotated, PlacePropertyModel,
UpdateModelFromClient, DeleteModelFromClient, ControlBehaviors,
PropertyEntranceSync, EnterProperty1, UpdatePropertyPerformanceCost,
ReportOffensiveModel/Property and GetHotPropertyData. The news screen's
NewsSendHotPropertiesInfoToClient moves here with the top properties
lookup; the dashboard's player reports now take the decoded text.

Handlers keep their logic and hand the work to PropertyManagementComponent,
PropertyVendorComponent, PropertyEntranceComponent and
MultiZoneEntranceComponent as before. Messages whose payload DLU ignored
(PropertyEditorBegin, PropertyContentsFromClient, ZonePropertyModel*)
now read it with the client's layout. The never-called
SendZonePropertyModelEquipped (which wrote no default flags) is gone.

No wire change and no change in recipients. Verified byte for byte
against a frozen verbatim copy of the old functions, PropertyDataMessage
and PropertySelectQueryProperty over an input grid (to one client and
broadcast), received messages compared with the old handlers' read
sequences with every truncated payload rejected, hand computed golden
bytes, round trips and a mutation check. Layouts confirmed against the
1.10.64 client in Ghidra. Known wire bug kept as is: PlaceModelResponse
writes response where the client reads a rotation quaternion
(PlaceModelResponse::Deserialize 0x00dc0170).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:30:49 -05:00
Aaron Kimbrell
527f54488b refactor: pet game messages as structs
Converts the pet taming minigame, naming, command and bouncer messages to
NetGameMsgs in PetMessages.{h,cpp}: NotifyPetTamingMinigame,
NotifyTamingModelLoadedOnServer, NotifyPetTamingPuzzleSelected,
PetTamingTryBuildResult, PetResponse, AddPetToPlayer, RegisterPetID,
RegisterPetDBID, ShowPetActionButton, BouncerActiveStatus, SetPetName,
SetPetNameModerated and PetNameChanged (sent), and PetTamingTryBuild,
NotifyTamingBuildSuccess, RequestSetPetName, StartServerPetMinigameTimer,
ClientExitTamingMinigame, CommandPet and DespawnPet (received, registered
in GameMessageHandler's map; each Handle hands the message to the
player's taming or active PetComponent exactly as the old handler did).
PetComponent, BouncerComponent and the hydrant/catapult scripts build
the structs; the old Send*/Handle* functions and switch cases are gone.
The never-called SendClientExitTamingMinigame is folded into the
ClientExitTamingMinigame struct. MarkInventoryItemAsActive stays with
the inventory messages.

No wire change and no change in recipients. Verified byte for byte
against a frozen verbatim copy of the old functions over an input grid
(to one client and broadcast), received messages compared with the old
handlers' read sequences with every truncated payload rejected, hand
computed golden bytes, round trips, and a mutation check. Layouts
confirmed against the 1.10.64 client's Serialize/Deserialize in Ghidra.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:30:49 -05:00
Aaron Kimbrell
b489ee59f8 refactor: world packets as structs
WorldPackets now holds what a client sends a world server, one struct per
packet with Serialize/Deserialize: Validation, CharacterListRequest,
CharacterCreateRequest, CharacterLoginRequest, GameMessage,
CharacterDeleteRequest, CharacterRenameRequest, LevelLoadComplete,
PositionUpdate, MailPacket, RoutePacket, StringCheck, GeneralChatMessage,
HandleFunness, UIHelpTop5. WorldServer's switch became a dispatch map of
handlers (each overrides Handle in WorldServer.cpp, logic unchanged:
dashboard hooks, LoadPlayer, chat logging, migration checks, message
inspector capture all still run); a packet that does not deserialize is
logged and dropped. UserManager's create/delete/rename take the structs.

The answers are ClientPackets (the CLIENT service): LoadStaticZone,
CharacterListResponse, CharacterCreateResponse, CharacterRenameResponse,
DeleteCharacterResponse, TransferToWorld, ServerStates, CreateCharacter,
ChatModerationString, MakeGMResponse, HTTPMonitorInfoResponse and
DebugOutput, built at the call sites (world server, UserManager, slash
commands, dashboard actions, components, migration). The world -> chat
forward of a routed packet is ChatPackets::RoutedFromClient. All
WorldPackets::Send* functions, HTTPMonitorInfo and the ClientPackets parse
functions are gone. The architecture doc now states the file rule: a
packet lives in the file of the ServiceType in its header.

No wire change. Verified against frozen verbatim copies of the old code
(tests/dGameTests/dNetTests/Legacy/WorldPacketsLegacy.h): every response
is sent through the old function and the struct over grids of inputs
(all enum values, strings of every length class, IDs, >64 moderation
segments, big XML) and must match byte for byte; every request is read
by the old code and the struct and must give the same values; plus
golden bytes, round trips, truncation checks and a field width mutation
that made the tests fail. Only differences: malformed requests are
dropped instead of handled with partial values, and LevelLoadComplete now
reads the zone ID the client sends after it (lu_packets and captures show
the 1.10.64 client always sends it; DLU ignored it).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:30:49 -05:00
Aaron Kimbrell
2add7e064e fix: trigger commands can target the zone
Trigger commands with target="zone" gathered no targets, so they never
ran. Forbidden Valley uses it for two ActivateSpawnerNetwork commands
(qb1 on interact, qb2 on activation) in nd_forbidden_valley.lutriggers,
and the winter large property uses it too. The zone is now the zone
control object, the same entity scripts treat as the zone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:30:46 -05:00
Aaron Kimbrell
86ee6de544 fix: slows and speed buffs change enemy movement speed
Speed buffs (BuffParameters "speed", for example the slow from the Great
Katana of Freezing and the Shurikens of Ice) and speed behaviours go
through ControllablePhysicsComponent's speed multiplier, which only
players' clients used. Enemies move with MovementAIComponent, which
ignored it, so slows had no effect on them.

- MovementAIComponent scales its waypoint speed by the entity's speed
  multiplier when one is set.
- RemoveSpeedboost set the multiplier of any entity without a
  LevelProgressionComponent (every enemy and pet) to 0 once its last
  boost ended, which was harmless while nothing read it for them. It now
  goes back to the normal base of 500 (multiplier 1).

Needs an in-game check with the freezing katana charge-up against an
enemy.

Fixes #1179

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:30:46 -05:00
Aaron Kimbrell
363e02e963 fix: enemies and summons drop targets that have died
FindTarget kept returning the current target while it stayed inside the
tether radius, even after it died, so enemies stood over dead players
(most visible in long respawn areas like the Battle of Nimbus Station)
and pet or summon AI hovered over enemies playing their death animation.

A dead current target now loses its threat and a new target is picked,
and dead entities are skipped both as proximity candidates and as threat
entries. Players who respawn are picked up again through the usual
proximity and threat paths.

Verified by building WorldServer and the test suite; needs an in-game
check (die to an enemy, the enemy should return to idle or pick another
player).

Fixes #1428

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:30:44 -05:00
Aaron Kimbrell
e213a7aeff feat: web dashboard and playground work
The NexusDashboard-parity dashboard (dDashboardServer) and everything built on it on the experimental branch:
accounts, characters, properties and moderation tools, permissions shared with in-game slash commands, economy
reports, World 3D and property 3D views with client scenery, scheduled events (features, vanity changes, live
events, announcements, restarts), vanity files and events, the CDClient browser, the message inspector with saved
captures, chat filter tools, community challenges, live ops, the AI moderator helper, and the server-side changes
they need.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:30:43 -05:00
Aaron Kimbrell
d599b788d0 refactor: mission, flag and collectible game messages as structs
Converts OfferMission, NotifyMission, NotifyMissionTask, ResetMissions,
NotifyClientFlagChange and NotifyLevelRewards (sent with SendToClient:
the old functions never broadcast) and the received RespondToMission,
MissionDialogueOK, RequestLinkedMission, SetFlag and HasBeenCollected
to NetGameMsgs in MissionMessages.{h,cpp}. Callers are switched,
OfferMission's send-it-twice behaviour moves to MissionOfferComponent,
the received messages are registered in GameMessageHandler's map and
the old functions are deleted. Handlers are copied verbatim. The
byte-equality helper can now compare SendToClient messages.

No wire change and no change in recipients. Verified byte for byte
against a frozen verbatim copy of the old functions over an input grid
(including OfferMission's two packets), received messages compared with
the old handlers' read sequences and every truncated payload rejected,
hand computed golden bytes and round trips. Layouts confirmed against
the 1.10.64 client in Ghidra.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:30:36 -05:00
Aaron Kimbrell
2681cc51ff refactor: racing and vehicle game messages as structs
Converts the 12 racing / vehicle / modular assembly messages DLU sends
and the 8 it receives to NetGameMsgs in RacingMessages.{h,cpp}, adds
eRacingClientNotificationType for NotifyRacingClient's event type,
switches the callers (RacingControlComponent, CarBoostBehavior,
PossessorComponent, slash commands), registers the received messages
in GameMessageHandler's map and deletes the old functions. Handlers are
copied verbatim. Also moves the byte-equality test helpers into a
shared GameMessageTestUtils.h.

No wire change. Verified byte for byte against a frozen verbatim copy
of the old functions over an input grid, to one client and broadcast;
received messages compared with the old handlers' read sequences
(including all 16 optional-field combinations of
VehicleNotifyHitImaginationServer) and every truncated payload
rejected; hand computed golden bytes; round trips; a deliberate field
mutation made the tests fail. Layouts confirmed against the 1.10.64
client in Ghidra. Malformed received messages are
dropped (see the foundations commit).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:30:36 -05:00
Aaron Kimbrell
7fb75f0484 refactor: activity game messages as structs
Converts ActivityEnter, ActivityExit, ActivityStart, ActivityStop,
ActivityPause, StartActivityTime, RequestActivityEnter,
RequestActivityExit and ShowActivityCountdown to NetGameMsgs in
ActivityMessages.{h,cpp}, switches their callers (racing, shooting
gallery, survival, waves, AG course, NT combat challenge) and deletes
the old GameMessages::Send* / HandleRequestActivityExit functions.
REQUEST_ACTIVITY_EXIT is registered in GameMessageHandler's map.

No wire change. Verified by comparing every struct byte for byte with a
frozen verbatim copy of the old functions (tests/.../Legacy) over a
grid of inputs, both to one client and as a broadcast (a temporary test
proved the copy matched production before it was deleted), plus hand
computed golden bytes, round trips and a deliberate field mutation that
made the tests fail. Layouts confirmed against the 1.10.64 client in
Ghidra. Only difference: a broadcast no longer makes
the extra Send(UNASSIGNED, false) that RakNet already rejected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:30:35 -05:00
Aaron Kimbrell
350d35dab5 chore: foundations for struct based packets and game messages
First step of moving hand written bitstream code to struct based
messages (see docs/PacketArchitecture.md). No wire changes.

- GameMsg is now only a server-internal event (delivered to handlers
  registered with RegisterMsg); NetGameMsg is a wire message with
  Send(sysAddr) (UNASSIGNED broadcasts), SendToClient(sysAddr) (one
  client, never broadcasts), WritePacket, Serialize, Deserialize and
  Handle. Mixing them up is now a compile error. NetGameMsgEvent<T> /
  DeliverLocally carry a wire message to local handlers; loot drops,
  pickup, the object debugger, GM invisibility and model RequestUse
  use them. The GM invisibility message keeps its target, so its bytes
  are unchanged.
- Behaviour change: GameMessageHandler logs and drops messages whose
  Deserialize fails instead of handling them with default fields (the
  4 messages already registered: RequestUse, RequestServerObjectInfo,
  ShootingGalleryFire, PickupItem).
- LUBitStream (kept as on main) gets a virtual destructor (Mail deleted
  derived packets through the base) and WritePacket, also used by
  ChatPackets::SendRoutedMsg with identical bytes.
- BitStreamUtils::WriteOptional/ReadOptional for default-flag fields
  and WriteLengthPrefixed/ReadLengthPrefixed for length prefixed
  strings.
- Every message ID enumerator (MessageType::*, ServiceType, Mail's
  wire enums) is pinned with static_asserts, so renumbering or removing
  one fails to compile.
- Tests: dServerMock copies each sent packet (it kept a pointer to the
  caller's destroyed BitStream); PacketTestUtils.h compares packets bit
  for bit; helper tests use hand computed golden bytes and equality
  with the hand written patterns they replace; compile-time checks
  keep the wire/internal split in place.
- docs/PacketArchitecture.md: survey, target architecture,
  conventions, verification method and migration plan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:30:35 -05:00
David Markowitz
129199e452 fix: actually reject empty properties (#2036) 2026-09-18 04:49:55 -05:00
David Markowitz
8f2004c9a3 fix: enemies on path not resetting aggro radius correctly (#2015)
tested that aggro is reset correctly and enemies no longer infinitely path to players.  Tether now properly calculates the time to tether instead of guessing
2026-07-17 23:05:17 -07:00
David Markowitz
35337291fa feat: debugger additions (#2013)
* feat: debugger additions

Add type field for links in flash
Add warning level for dangerous buttons
fix uninitialzied memory with jetpack variable
remove a bunch of duplicated position push code

tested that the ui is still functional and components with multiple physics components have all their details visible.
tested that jetpack is initialized now

* remove amf3 header

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fixes

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-24 17:18:16 -05:00
Aaron Kimbrell
5d523a1e7b fix: handling of the same skill on multiple items (#1990)
* refactor: update behavior slot determination to use equipLocation instead of itemType

* fix: improve skill management in InventoryComponent to ensure correct client updates
2026-06-22 17:16:57 -07:00
David Markowitz
5745742c91 feat: dragon instance script (#2012)
* feat: dragon instance script

* Update FvDragonInstanceServer.h

* feat: implement ronin script

* Update CountdownDestroyAI.cpp

* default initialize

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* remove unused handlers

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* use float

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fixes

* Update ScriptComponent.h

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-22 17:16:21 -07:00
Aaron Kimbrell
62f58f5307 chore: cleanup possession handling (#1984)
* feat: enhance possession mechanics with skill set integration and improved message handling

* fix: restore SetPossessor in Mount() and scope IsRacing to vehicles

SetPossessor was missing from Mount(), breaking direct possessions via
PossessableComponent::OnUse which bypasses HandlePossession. IsRacing
now only set/cleared when the mount has HavokVehiclePhysicsComponent,
preventing non-vehicle possessions from incorrectly affecting the
distance-driven statistic.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 21:39:51 -07:00
David Markowitz
135aec8112 feat: hatchlings (#2008)
tested that hatchlings now function
fixes #759

Update MovementAIComponent.cpp

Update MovementAIComponent.cpp

Update HatchlingPets.cpp
2026-06-20 17:10:00 -05:00
David Markowitz
308412f46e fix: enemies snapping to the incorrect position if they had a path and trying to use the path if they were aggro'd to an enemy (#2005)
* fix: enemies snapping to the incorrect position if they had a path

tested that ags enemies no longer snap backwards a large amount

* fix: move the home point so we can aggro correctly
2026-06-19 02:12:47 -07:00
David Markowitz
56504d9447 fix: add range checks to npc combat skill behavior (#2003)
* fix: add range checks to npc combat skill behavior

tested that all enemies now cast skills smartly based on range to targets, and do not cast skills if they are out of range.

fixes an issue where the spider queen could attack you outside the normal range

fixes an issue where entering happy flower caused you to need to restart the client

fixes #965

* feedback
2026-06-19 01:27:49 -05:00
David Markowitz
ce9d4e823c feat: enemies now use weights on their attacks (#2004)
* feat: enemies now use weights on their attacks

tested that 8 times out of 10, in close range, spiders did a web attack instead of a melee attack, vs the prior behavior of always following a pattern

fixes #2002

* feedback
2026-06-19 01:27:14 -05:00
David Markowitz
0f17e1de3b feat: enemy npc pathing (#2000)
* feat: enemy npc pathing

they live 🎉
tested that enemies path all around the world should they have a path configured.
tested that the admiral in gf (at the first camp) paths now.
fixes #1546

* feedback
2026-06-17 23:07:36 -07:00
David Markowitz
0101933f5c chore: cleanup pointer management for LDF data (#1995)
* change network settings from vector to LwoNameValue

* move settings on Entity to managed memory

* Migrate more members

* chore: remove pointer leakage from raw ldf pointers

* feedback

* fix ci
2026-06-14 20:54:52 -07:00
David Markowitz
1e9b18fa9d chore: cleanup usage of pointers in the activity component (#1989)
* chore: cleanup usage of pointers in the activity component

* feedback
2026-06-11 09:12:43 -05:00
David Markowitz
e5b8e5c6b7 fix: buggy hitboxes during ag foot race (#1993)
* physics fixes

* check ptr
2026-06-11 09:12:31 -05:00
David Markowitz
707880b5fc fix: fv pipe quick build not spawning as it should (#1991)
tested that the pipe now spawns a ROCK that you can build.  This ROCK you build spawns the PIPE now.
new bug: if you start building the ROCK and stop, the pipe will spawn instead of the previous rock.
2026-06-11 09:12:06 -05:00
David Markowitz
93076dc36d chore: simplify metrics (#1987)
* chore: simplify metrics

rename to hpp and remove unused includes

* feedback
2026-06-08 21:42:32 -07:00
David Markowitz
a156a8fcba fix: security vulnerabilities (#1980)
* fix: security vulnerabilities

Tested that all functions related to the touched files work

will test sqlite on a CI build

* fix failing test

* ai feedback

* add buffer size checking

* use c_str

* dont log session key

* Try this for a mac definition

* be quiet apple
2026-06-07 20:59:11 -07:00
David Markowitz
4ab09cf1aa Remove non-functioning saving of gm invis, re-add gm invis as a feature (#1976)
Does not save, only works for this world.  Fixed an issue where the incorrect comparison was used to make players invisible again (the same check that makes then INvisible needs to make them visible.)
2026-05-27 04:35:00 -05:00
David Markowitz
4ef9f43266 feat: make gm registration simpler and safer (#1932)
* gm registration re-work

* fix errors

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* remove duplicate message

* Remove duplicate function

* add null check

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-05-19 13:42:56 -05:00
David Markowitz
67bbe4c1f0 fix(Missions): mission progression undefined behavior (#1973)
* fix: mission progression undefined behavior

defer the sub calls until after the loop has finished, that way no ub happens.  tested that mission progression all the way up until joining a faction still works and meta missions still function.

* default initialize

* Update MissionComponent.h
2026-05-17 14:21:08 -05:00
David Markowitz
482ff82656 fix: adding custom behaviors (#1969) 2026-04-14 01:04:26 -07:00
David Markowitz
8061f512aa feat: fix go outside and play mission (#1967)
* feat: fix go outside and play mission

* Update dWorldServer/WorldServer.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update dGame/dComponents/MissionComponent.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* const

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-09 00:55:57 -05:00
David Markowitz
8dfdca7fbd feat: add mission progression for behaviors (#1962)
* feat: add mission progression for behaviors

* Add const to ptr

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-31 13:02:23 -07:00
David Markowitz
434c9b6315 fix: imaginite on racing minigames and add null checks (#1958) 2026-02-23 01:16:36 -08:00
David Markowitz
40fef36530 fix: coins dropping on killer (#1948)
tested that when a player dies the coins spawn on their body instead
2025-12-13 22:00:58 -08:00
David Markowitz
bf020baa17 fix: temp fixes for ghosting so I can continue being on break (#1947)
* fix: temp fixes for ghosting so I can continue being on break

disables the ghost feature for now so i can continue my break

* Update GhostComponent.cpp
2025-12-08 20:39:33 -08:00
David Markowitz
a713216540 fix: saving gm invis for non gms (#1940) 2025-11-18 22:04:07 -06:00
David Markowitz
ea86a708e4 fix: uninitialized memory (#1937) 2025-11-18 19:06:03 -08:00
David Markowitz
991e55f305 feat: dont drop loot for dead players if configured in the zone activity settings (#1935)
* feat: dont drop loot for dead players if configured in the zone activity settings

* fix errors

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update dGame/dComponents/ActivityComponent.h

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update dGame/dUtilities/Loot.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-16 16:17:26 -06:00
Aaron Kimbrell
11d44ffb98 feat: proper gminvs with ghosting (#1920)
* feat: proper gminvis ghosting

* address feedback

---------

Co-authored-by: David Markowitz <39972741+EmosewaMC@users.noreply.github.com>
2025-11-15 16:43:33 -08:00
David Markowitz
eac50acfcc fix: correct mission tracking (#1930)
checked that live captures did not track achievements in this count
2025-11-15 13:29:03 -08:00
David Markowitz
0dd504c803 feat: behavior states (#1918) 2025-10-20 01:16:36 -05:00
David Markowitz
002aa896d8 feat: debug information (#1915) 2025-10-19 07:22:45 -05:00
David Markowitz
f3a5f60d81 feat: more destroyable debug info (#1912)
* feat: more destroyable info

* Change type and remove duplicate value
2025-10-16 14:15:02 -05:00
David Markowitz
4c9c773ec5 fix: powerup drops and hardcore loot drops (#1914)
tested the following are now functional
ag buff station
tiki torch
ve rocket part boxes
ns statue
property behavior
extra items from full inventory
hardcore drops (items and coins)
2025-10-16 14:13:38 -05:00
David Markowitz
ec6253c80c fix: coin dupe on same team (#1911)
* feat: Loot rework

* Allow dupe powerup pickups

* change default team loot to shared

* fix: coin dupe on team
2025-10-15 22:36:45 -05:00
David Markowitz
74630b56c8 feat: Loot rework (#1909)
* feat: Loot rework

* Allow dupe powerup pickups

* change default team loot to shared
2025-10-15 00:53:39 -05:00
David Markowitz
ff645a6662 feat: model debug (#1907) 2025-10-11 15:33:28 -07:00
David Markowitz
e051229fb6 feat: InventoryComponent debug info (#1902) 2025-10-11 00:58:52 -05:00