mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-25 23:18:44 -07:00
feat: Update README with branch version and single-server defaults; enhance inventory and room handling for equipped items
This commit is contained in:
@@ -66,6 +66,13 @@ public class InventoryController(
|
|||||||
public string PrefabName { get; set; } = string.Empty;
|
public string PrefabName { get; set; } = string.Empty;
|
||||||
public string ModificationGuid { get; set; } = string.Empty;
|
public string ModificationGuid { get; set; } = string.Empty;
|
||||||
public bool Favorited { get; set; }
|
public bool Favorited { get; set; }
|
||||||
|
// The 2023 client sends Equipped/IsEquipped when a weapon skin is
|
||||||
|
// equipped (distinct from Favorited). We only have one IsActive flag,
|
||||||
|
// and for skins "active" == "equipped", so honor whichever the client
|
||||||
|
// sent. Without this the equip was dropped (only Favorited was read)
|
||||||
|
// and the skin never stuck.
|
||||||
|
public bool? Equipped { get; set; }
|
||||||
|
public bool? IsEquipped { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>POST <c>api/equipment/v1/update</c> — toggle the
|
/// <summary>POST <c>api/equipment/v1/update</c> — toggle the
|
||||||
@@ -103,7 +110,27 @@ public class InventoryController(
|
|||||||
// to themselves).
|
// to themselves).
|
||||||
return Forbid();
|
return Forbid();
|
||||||
}
|
}
|
||||||
row.IsActive = req.Favorited;
|
// "equipped" is the meaningful state for weapon skins; prefer it,
|
||||||
|
// fall back to Favorited for plain tool-pin updates.
|
||||||
|
var active = req.Equipped ?? req.IsEquipped ?? req.Favorited;
|
||||||
|
|
||||||
|
// One skin equipped per weapon: when equipping a catalog-backed skin,
|
||||||
|
// clear the equipped flag on the player's OTHER skins for the SAME
|
||||||
|
// prefab (slugs share the "{prefix}{prefab}:" head) so the weapon
|
||||||
|
// doesn't end up with two "equipped" skins.
|
||||||
|
if (active && !string.IsNullOrWhiteSpace(req.ModificationGuid)
|
||||||
|
&& !string.IsNullOrWhiteSpace(req.PrefabName))
|
||||||
|
{
|
||||||
|
var prefabPrefix = StoreService.EquipmentSkinSlug(req.PrefabName, string.Empty);
|
||||||
|
var siblings = await db.PlayerInventory
|
||||||
|
.Where(inv => inv.PlayerId == pid && inv.IsActive
|
||||||
|
&& inv.ItemSlug != slug
|
||||||
|
&& inv.ItemSlug.StartsWith(prefabPrefix))
|
||||||
|
.ToListAsync();
|
||||||
|
foreach (var sib in siblings) sib.IsActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
row.IsActive = active;
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
return Ok(new { Updated = true });
|
return Ok(new { Updated = true });
|
||||||
}
|
}
|
||||||
@@ -261,7 +288,11 @@ public class InventoryController(
|
|||||||
FriendlyName = item.DisplayName,
|
FriendlyName = item.DisplayName,
|
||||||
Tooltip = item.Description,
|
Tooltip = item.Description,
|
||||||
Rarity = rarity,
|
Rarity = rarity,
|
||||||
|
// IsActive is the equipped/active flag; surface it under every key
|
||||||
|
// the 2023 client reads so the equipped skin shows on reload.
|
||||||
Favorited = inv.IsActive,
|
Favorited = inv.IsActive,
|
||||||
|
Equipped = inv.IsActive,
|
||||||
|
IsEquipped = inv.IsActive,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2534,6 +2534,8 @@ public class RoomsController(
|
|||||||
/// verifying ownership and intra-room uniqueness.</summary>
|
/// verifying ownership and intra-room uniqueness.</summary>
|
||||||
[HttpPost("rooms/{roomId:long}/subrooms/{subRoomId:long}/name")]
|
[HttpPost("rooms/{roomId:long}/subrooms/{subRoomId:long}/name")]
|
||||||
[HttpPut("rooms/{roomId:long}/subrooms/{subRoomId:long}/name")]
|
[HttpPut("rooms/{roomId:long}/subrooms/{subRoomId:long}/name")]
|
||||||
|
[HttpPost("roomserver/rooms/{roomId:long}/subrooms/{subRoomId:long}/name")]
|
||||||
|
[HttpPut("roomserver/rooms/{roomId:long}/subrooms/{subRoomId:long}/name")]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<IActionResult> RenameSubroom(
|
public async Task<IActionResult> RenameSubroom(
|
||||||
long roomId,
|
long roomId,
|
||||||
@@ -3353,8 +3355,13 @@ public class RoomsController(
|
|||||||
return Ok(SceneWire(clone));
|
return Ok(SceneWire(clone));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Subroom settings save POSTs here on the roomserver host ("failed to
|
||||||
|
// modify room" = the bare-only routes 404'd). Same roomserver/ prefix as
|
||||||
|
// the sibling subroom mutations.
|
||||||
[HttpPost("rooms/{roomId:long}/subrooms/{subRoomId:long}/modify")]
|
[HttpPost("rooms/{roomId:long}/subrooms/{subRoomId:long}/modify")]
|
||||||
[HttpPut("rooms/{roomId:long}/subrooms/{subRoomId:long}/modify")]
|
[HttpPut("rooms/{roomId:long}/subrooms/{subRoomId:long}/modify")]
|
||||||
|
[HttpPost("roomserver/rooms/{roomId:long}/subrooms/{subRoomId:long}/modify")]
|
||||||
|
[HttpPut("roomserver/rooms/{roomId:long}/subrooms/{subRoomId:long}/modify")]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public Task<IActionResult> ModifySubRoom(long roomId, long subRoomId, [FromBody] SubRoomModifyRequest req) =>
|
public Task<IActionResult> ModifySubRoom(long roomId, long subRoomId, [FromBody] SubRoomModifyRequest req) =>
|
||||||
MutateScene(roomId, subRoomId, s =>
|
MutateScene(roomId, subRoomId, s =>
|
||||||
@@ -3370,6 +3377,7 @@ public class RoomsController(
|
|||||||
/// scene. Body NewIndex is the target OrderIndex; the in-between
|
/// scene. Body NewIndex is the target OrderIndex; the in-between
|
||||||
/// rows shift to fill the gap.</summary>
|
/// rows shift to fill the gap.</summary>
|
||||||
[HttpPost("rooms/{roomId:long}/subrooms/{subRoomId:long}/move")]
|
[HttpPost("rooms/{roomId:long}/subrooms/{subRoomId:long}/move")]
|
||||||
|
[HttpPost("roomserver/rooms/{roomId:long}/subrooms/{subRoomId:long}/move")]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<IActionResult> MoveSubRoom(long roomId, long subRoomId, [FromBody] SubRoomMoveRequest req)
|
public async Task<IActionResult> MoveSubRoom(long roomId, long subRoomId, [FromBody] SubRoomMoveRequest req)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ public class MatchPlayerController(
|
|||||||
return Ok(new PresenceDto
|
return Ok(new PresenceDto
|
||||||
{
|
{
|
||||||
PlayerId = playerId,
|
PlayerId = playerId,
|
||||||
StatusVisibility = 1,
|
StatusVisibility = 0, // Everyone (was 1 = FriendsOnly)
|
||||||
DeviceClass = 0,
|
DeviceClass = 0,
|
||||||
VrMovementMode = 0,
|
VrMovementMode = 0,
|
||||||
RoomInstance = room,
|
RoomInstance = room,
|
||||||
@@ -174,7 +174,7 @@ public class MatchPlayerController(
|
|||||||
return Ok(new PresenceDto
|
return Ok(new PresenceDto
|
||||||
{
|
{
|
||||||
PlayerId = playerId,
|
PlayerId = playerId,
|
||||||
StatusVisibility = value ?? 1,
|
StatusVisibility = value ?? 0, // default Everyone; honor explicit client choice
|
||||||
DeviceClass = 0,
|
DeviceClass = 0,
|
||||||
VrMovementMode = 0,
|
VrMovementMode = 0,
|
||||||
RoomInstance = room,
|
RoomInstance = room,
|
||||||
@@ -190,7 +190,7 @@ public class MatchPlayerController(
|
|||||||
return Ok(new PresenceDto
|
return Ok(new PresenceDto
|
||||||
{
|
{
|
||||||
PlayerId = playerId,
|
PlayerId = playerId,
|
||||||
StatusVisibility = 1,
|
StatusVisibility = 0, // Everyone (was 1 = FriendsOnly)
|
||||||
DeviceClass = 0,
|
DeviceClass = 0,
|
||||||
VrMovementMode = value ?? 0,
|
VrMovementMode = value ?? 0,
|
||||||
RoomInstance = room,
|
RoomInstance = room,
|
||||||
|
|||||||
@@ -98,12 +98,14 @@ public class PlayerPresenceController(
|
|||||||
return new PlayerPresenceDto
|
return new PlayerPresenceDto
|
||||||
{
|
{
|
||||||
PlayerId = (int)id,
|
PlayerId = (int)id,
|
||||||
// StatusVisibility is the player's *preference* (would
|
// StatusVisibility is the player's *preference* for who may
|
||||||
// they like to appear online if they were online?). For
|
// see them online. The enum is Everyone=0 / FriendsOnly=1 /
|
||||||
// offline players we still report Visible so when they
|
// Nobody=2 — so the previous value 1 (mislabeled "Visible")
|
||||||
// come back the friend's cached preference is correct,
|
// actually meant FriendsOnly, and anyone who wasn't your
|
||||||
// and IsOnline=false is what gates the "Online" badge.
|
// friend saw you as OFFLINE. On a private server everyone
|
||||||
StatusVisibility = 1, // Visible
|
// should see everyone, so report Everyone (0). IsOnline=false
|
||||||
|
// still gates the "Online" badge for offline players.
|
||||||
|
StatusVisibility = 0, // Everyone
|
||||||
DeviceClass = 0, // Desktop / unknown — not VR
|
DeviceClass = 0, // Desktop / unknown — not VR
|
||||||
VrMovementMode = 0,
|
VrMovementMode = 0,
|
||||||
// Full instance details are safe, and necessary, when the
|
// Full instance details are safe, and necessary, when the
|
||||||
|
|||||||
@@ -270,7 +270,8 @@ public class NotificationService(
|
|||||||
var msg = new System.Text.Json.Nodes.JsonObject
|
var msg = new System.Text.Json.Nodes.JsonObject
|
||||||
{
|
{
|
||||||
["playerId"] = (int)playerId,
|
["playerId"] = (int)playerId,
|
||||||
["statusVisibility"] = 1,
|
// Everyone=0 (was 1=FriendsOnly, which hid you from non-friends).
|
||||||
|
["statusVisibility"] = 0,
|
||||||
["deviceClass"] = 0,
|
["deviceClass"] = 0,
|
||||||
["vrMovementMode"] = 0,
|
["vrMovementMode"] = 0,
|
||||||
["roomInstance"] = redacted is null
|
["roomInstance"] = redacted is null
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# DorkNet — `december-2020-12-18`
|
# DorkNet — `march-2023-03-21`
|
||||||
|
|
||||||
This is the **December 2020.12.18** branch of DorkNet — a self-hostable
|
This is the **December 2020.12.18** branch of DorkNet — a self-hostable
|
||||||
reimplementation of the Rec Room backend tuned to the wire protocol of
|
reimplementation of the Rec Room backend tuned to the wire protocol of
|
||||||
@@ -298,6 +298,51 @@ and room-move presence fan-out.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Single-server defaults (review before going public)
|
||||||
|
|
||||||
|
Several values are hardcoded or defaulted for the convenience of running a
|
||||||
|
small, trusted, single-operator server. They work out of the box for a group
|
||||||
|
of friends but should be reviewed / adapted before exposing the server to the
|
||||||
|
public internet:
|
||||||
|
|
||||||
|
- **Client build version (`appVersion`).** Hardcoded to this branch's client
|
||||||
|
build (`20230317`) in the presence/match/notification responses
|
||||||
|
(`MatchPlayerController`, `PlayerPresenceController`, `NotificationService`,
|
||||||
|
`RoomsController`). It must match the build everyone runs, or players get a
|
||||||
|
"version mismatch" and can't join each other. If you serve a different
|
||||||
|
client build, change it (ideally hoist it to one shared constant).
|
||||||
|
- **No real authentication.** Accounts are keyed by a per-install `deviceId`
|
||||||
|
the client generates (`PlayerService.GetOrCreateByDeviceAsync`) — **not** a
|
||||||
|
verified identity (Steam ID is deliberately ignored so emulators work).
|
||||||
|
Anyone who can reach the server with a patched client gets/creates an
|
||||||
|
account. Use **Settings → Server → disable signups** + the
|
||||||
|
[signup-code](#signup-codes) flow to gate who can join; there is no password
|
||||||
|
wall by default.
|
||||||
|
- **First account becomes admin.** The first account created on a fresh DB is
|
||||||
|
granted `IsAdmin` so there's always a root admin. On a public server, create
|
||||||
|
your admin account first and verify no one else beat you to it.
|
||||||
|
- **Online status = Everyone.** Presence reports `StatusVisibility = 0`
|
||||||
|
(Everyone) so every player appears online to every other player, matching
|
||||||
|
the [everyone-is-friends](#everyone-is-friends-toggle) convenience. A public
|
||||||
|
server may instead want to persist and honor each player's own visibility
|
||||||
|
preference.
|
||||||
|
- **Room / matchmaking capacity.** New matchmade sessions and subrooms default
|
||||||
|
to **8** players and are capped at **40** (`GameSessionService`,
|
||||||
|
`RoomSceneEntity.MaxPlayers`, admin `MaxCapacity` clamp). The in-game "Max
|
||||||
|
Player Count in This Subroom" slider raises it per room (slider ceiling 40).
|
||||||
|
- **Avatar unlock clamp.** The wardrobe clamp defaults high
|
||||||
|
(`Avatar:MaxUnlockedItems` 4000 / per-slot 1000) for this desktop client —
|
||||||
|
tune in config if you change the ownership model.
|
||||||
|
- **Hosts / domain.** The apex and per-service subdomains come from
|
||||||
|
`DomainConfig` (`Domain:Apex`) / `appsettings`; set these to your own
|
||||||
|
domain. The `Everyone-is-friends`, signup-disable, and similar switches live
|
||||||
|
in **admin Settings**, not source.
|
||||||
|
|
||||||
|
None of these are security boundaries as shipped — treat the server as trusted
|
||||||
|
LAN/friends infrastructure unless you harden the items above.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
See [main's CONTRIBUTING guide](../../blob/main/CONTRIBUTING.md) for
|
See [main's CONTRIBUTING guide](../../blob/main/CONTRIBUTING.md) for
|
||||||
|
|||||||
Reference in New Issue
Block a user