Skip to content

Building placement is confirmed on the client before the server actually agrees #4

Description

@CanReader

BuildingPlacementController.approve() commits a building placement fully on the client before the server has actually confirmed anything:

grid.occupy(placing, position.x, position.z, placing.getFootprint());
placing.finishMoving();
...
persistPlacement(placing, position);   // just sends the event, does not wait
windowManager.hideBuildConfirm();
windowManager.toast(Localization.getString("BUILDING_PLACED"));
placing = null;

persistPlacement sends SCENE_EVENT_CHANGE_BUILDING_POS to the server and returns immediately, it does not wait for or check the result. On the server side, WorldHandlers.ts calls world.placeBuilding(...) and pushes the result code back wrapped in a generic SCENE_EVENT (400 out of bounds, 403 not yours, 409 cell occupied, 200 success).

I went looking for where the client reads that result back and I don't think it exists. UserSceneSocketBridge.onSceneEvent switches on the scene event type, and it only handles SCENE_EVENT_VERSION, CHAR_MESSAGE, SCENE_EVENT_GET_BUILDING, and SCENE_EVENT_CHANGE_CAMERA_POS. SCENE_EVENT_CHANGE_BUILDING_POS isn't one of the cases, so it falls into the default branch and just gets logged as "Unhandled scene event."

So if the server ever rejects a placement (say the grid race condition in the other issue lets two placements land on the same cell and the second one gets a 409), the player already saw "Building placed", the local grid already marked those cells occupied, and there's no code path that walks any of that back. The client and server end up disagreeing about where that building is (or whether it's placed at all), and the player won't find out until the world reloads from the server and the building isn't where they left it.

Feels like persistPlacement needs some way to get the ack back, and SCENE_EVENT_CHANGE_BUILDING_POS needs a case in onSceneEvent that rolls back grid.occupy and the building's position/toast when the result code isn't 200.

Files: core/src/com/focus/kingdom/world/building/BuildingPlacementController.java (approve(), around line 170-192) and core/src/com/focus/kingdom/world/sync/UserSceneSocketBridge.java (onSceneEvent, around line 196-223).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions