fix(infostand): show Edit Furni button for wall items

The "Edit Furni" button was nested inside the `(!avatarInfo.isWallItem
&& canMove)` guard, together with the floor-only Buildtools position/
height/rotation controls, so it never rendered for wall furni (e.g.
`ads_campguitar`). Move it out so it shows for any furni when
`godMode` + `isModerator`, leaving the position controls floor-only.
The onClick already resolved WALL vs FLOOR correctly.

While touching this file, clean up two pre-existing lint errors:
- hoist `getValidRoomObjectDirection` to module scope (it is pure and
  uses no component state) so it is no longer accessed before its
  declaration (react-hooks/immutability)
- expand the inline `'scale'` branch to Allman braces (brace-style)
This commit is contained in:
simoleo89
2026-06-07 01:00:18 +02:00
parent 110363ab1c
commit e2cc708497
@@ -18,6 +18,56 @@ const PICKUP_MODE_NONE: number = 0;
const PICKUP_MODE_EJECT: number = 1;
const PICKUP_MODE_FULL: number = 2;
function getValidRoomObjectDirection(roomObject: any, isPositive: boolean)
{
if(!roomObject || !roomObject.model) return 0;
let allowedDirections: number[] = [];
if(roomObject.type === 'monster_plant')
{
allowedDirections = roomObject.model.getValue('pet_allowed_directions');
}
else
{
allowedDirections = roomObject.model.getValue('furniture_allowed_directions');
}
let direction = roomObject.getDirection().x;
if(allowedDirections && allowedDirections.length)
{
let index = allowedDirections.indexOf(direction);
if(index < 0)
{
index = 0;
for(let i = 0; i < allowedDirections.length; i++)
{
if(direction <= allowedDirections[i]) break;
index++;
}
index = index % allowedDirections.length;
}
if(isPositive)
{
index = (index + 1) % allowedDirections.length;
}
else
{
index = (index - 1 + allowedDirections.length) % allowedDirections.length;
}
direction = allowedDirections[index];
}
return direction;
}
export const InfoStandWidgetFurniView: FC<InfoStandWidgetFurniViewProps> = props =>
{
const { avatarInfo = null, onClose = null } = props;
@@ -78,56 +128,6 @@ export const InfoStandWidgetFurniView: FC<InfoStandWidgetFurniViewProps> = props
SendMessageComposer(new UpdateFurniturePositionComposer(avatarInfo.id, newX, newY, Math.round(newZ * 10000), newDirection));
}, [ avatarInfo ]);
function getValidRoomObjectDirection(roomObject: any, isPositive: boolean)
{
if(!roomObject || !roomObject.model) return 0;
let allowedDirections: number[] = [];
if(roomObject.type === 'monster_plant')
{
allowedDirections = roomObject.model.getValue('pet_allowed_directions');
}
else
{
allowedDirections = roomObject.model.getValue('furniture_allowed_directions');
}
let direction = roomObject.getDirection().x;
if(allowedDirections && allowedDirections.length)
{
let index = allowedDirections.indexOf(direction);
if(index < 0)
{
index = 0;
for(let i = 0; i < allowedDirections.length; i++)
{
if(direction <= allowedDirections[i]) break;
index++;
}
index = index % allowedDirections.length;
}
if(isPositive)
{
index = (index + 1) % allowedDirections.length;
}
else
{
index = (index - 1 + allowedDirections.length) % allowedDirections.length;
}
direction = allowedDirections[index];
}
return direction;
}
const handleHeightChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) =>
{
let newZ = parseFloat(event.target.value);
@@ -421,7 +421,11 @@ export const InfoStandWidgetFurniView: FC<InfoStandWidgetFurniViewProps> = props
if(key === 'offsetX') value = String(x);
else if(key === 'offsetY') value = String(y);
else if(key === 'offsetZ') value = String(z);
else if(key === 'scale') { value = String(scale); hasScale = true; }
else if(key === 'scale')
{
value = String(scale);
hasScale = true;
}
clone[i] = value;
map.set(key, value);
@@ -638,6 +642,20 @@ export const InfoStandWidgetFurniView: FC<InfoStandWidgetFurniViewProps> = props
})() }</Text>
</div>
</div> }
{ isModerator &&
<button
className="w-full text-white text-xs bg-[#1e7295] hover:bg-[#1a617f] border border-[#ffffff33] rounded px-2 py-1 cursor-pointer transition-colors"
onClick={ () =>
{
const roomObject = GetRoomEngine().getRoomObject(roomSession.roomId, avatarInfo.id, avatarInfo.isWallItem ? RoomObjectCategory.WALL : RoomObjectCategory.FLOOR);
const typeId = roomObject?.model?.getValue(RoomObjectVariable.FURNITURE_TYPE_ID);
CreateLinkEvent('furni-editor/show');
if(typeId) window.dispatchEvent(new CustomEvent('furni-editor:open', { detail: { spriteId: typeId } }));
} }>
Edit Furni
</button> }
{ (!avatarInfo.isWallItem && canMove) &&
<>
<button
@@ -645,20 +663,6 @@ export const InfoStandWidgetFurniView: FC<InfoStandWidgetFurniViewProps> = props
onClick={ () => setDropdownOpen(!dropdownOpen) }>
{ dropdownOpen ? `${LocalizeText('widget.furni.present.close')} Buildtools` : `${LocalizeText('navigator.roomsettings.doormode.open')} Buildtools` }
</button>
{ isModerator &&
<button
className="w-full text-white text-xs bg-[#1e7295] hover:bg-[#1a617f] border border-[#ffffff33] rounded px-2 py-1 cursor-pointer transition-colors"
onClick={ () =>
{
const roomObject = GetRoomEngine().getRoomObject(roomSession.roomId, avatarInfo.id, avatarInfo.isWallItem ? RoomObjectCategory.WALL : RoomObjectCategory.FLOOR);
const typeId = roomObject?.model?.getValue(RoomObjectVariable.FURNITURE_TYPE_ID);
CreateLinkEvent('furni-editor/show');
if(typeId) window.dispatchEvent(new CustomEvent('furni-editor:open', { detail: { spriteId: typeId } }));
} }>
Edit Furni
</button> }
{ dropdownOpen &&
<div className="flex gap-[4px] w-full">
{ /* Left panel: position + rotation */ }