Skip to content

Fix incorrect Caller after nested Rpc calls.#123

Closed
andy013 wants to merge 186 commits intoFacepunch:masterfrom
andy013:nested_rpc_fix
Closed

Fix incorrect Caller after nested Rpc calls.#123
andy013 wants to merge 186 commits intoFacepunch:masterfrom
andy013:nested_rpc_fix

Conversation

@andy013
Copy link
Copy Markdown
Contributor

@andy013 andy013 commented Dec 12, 2025

Fix incorrect Caller after nested Rpc calls.

Issue: #2363

Changes

  • Consume Caller in the outer Rpc so that any internal calls use Connection.Local
  • Restore correct Caller once the nested Rpc has finished
  • Renamed Calling to IsRemoteCall for clarity
  • Removed PreCall as it is no longer needed

Notes

There are 2 bugs in the current code.

  1. If you call an Rpc that is nested within another one, it will permanently change the Caller even once you exit back to the original Rpc scope.
  2. The Calling bool that should be true when the Rpc was invoked remotely is always false when accessed within an Rpc.

I found the name Calling to be quite confusing so I renamed it to IsRemoteCall which I think is clearer. I can change it back if you disagree. (Maybe I still need to keep Calling and mark it as obsolete for people who are currently using it? I doubt anyone will be using it since it's broken)

I'm not sure if this is the best way to solve this but it's the only way I could come up with after thinking about it for a while. If you have any better ideas let me know and I can try and rework it.

How It Works

  1. Remote RPC arrives → InvokeInstanceRpc/IncomingStaticRpcMsg sets PendingRpcCaller
  2. User's RPC method executes → __rpc_Wrapper/OnCallRpc consumes pending caller and creates WithCaller scope
  3. Any nested RPC calls → See null pending caller, correctly use Connection.Local
  4. When the nested Rpc is exited, we restore the previous values so the outer Rpc has the correct Caller again

Demo Project: rpc_caller_fix.zip

This is small project I made for testing the changes. To use it, just hit play, connect with a client and then look at the server logs.

The code is setup like this so that the broadcast is called in the middle of the Rpc:

	[Rpc.Host]
	public void ComponentRpc()
	{
		Log.Info( $"[Component] CallerId={Rpc.CallerId} isLocal={Rpc.Caller == Connection.Local} IsRemoteCall={Rpc.IsRemoteCall}" );
		ComponentBroadcast();
		Log.Info( $"[Component] CallerId={Rpc.CallerId} isLocal={Rpc.Caller == Connection.Local} IsRemoteCall={Rpc.IsRemoteCall}" );
	}

	[Rpc.Broadcast]
	public void ComponentBroadcast()
	{
		Log.Info( $"[Component Broadcast] CallerId={Rpc.CallerId} isLocal={Rpc.Caller == Connection.Local} IsRemoteCall={Rpc.IsRemoteCall}" );
	}

Current Behavior:

[Component] CallerId=6080a588-fd6e-4609-8d16-241481fe1967 isLocal=False Calling=False        // Calling is ALWAYS false
[Component Broadcast] CallerId=4210ea28-b854-453b-b2ef-bc1bf5eda6a7 isLocal=True Calling=False
[Component] CallerId=4210ea28-b854-453b-b2ef-bc1bf5eda6a7 isLocal=True Calling=False        // CallerId incorrectly stays set to nested Rpc value, even once we return to previous scope

[Static] CallerId=6080a588-fd6e-4609-8d16-241481fe1967 isLocal=False Calling=False
[Static Broadcast] CallerId=4210ea28-b854-453b-b2ef-bc1bf5eda6a7 isLocal=True Calling=False
[Static] CallerId=4210ea28-b854-453b-b2ef-bc1bf5eda6a7 isLocal=True Calling=False

[GOS] CallerId=6080a588-fd6e-4609-8d16-241481fe1967 isLocal=False Calling=False
[GOS Broadcast] CallerId=4210ea28-b854-453b-b2ef-bc1bf5eda6a7 isLocal=True Calling=False
[GOS] CallerId=4210ea28-b854-453b-b2ef-bc1bf5eda6a7 isLocal=True Calling=False

After Fix:

[Component] CallerId=6f6ef388-8a62-48d4-8447-8877e90884f2 isLocal=False IsRemoteCall=True        // IsRemoteCall is set correctly
[Component Broadcast] CallerId=d2c4917d-f7ca-4ee4-a7f9-35b713f53f7d isLocal=True IsRemoteCall=False
[Component] CallerId=6f6ef388-8a62-48d4-8447-8877e90884f2 isLocal=False IsRemoteCall=True        // CallerId correctly resets once inner Rpc has finished

[Static] CallerId=6f6ef388-8a62-48d4-8447-8877e90884f2 isLocal=False IsRemoteCall=True
[Static Broadcast] CallerId=d2c4917d-f7ca-4ee4-a7f9-35b713f53f7d isLocal=True IsRemoteCall=False
[Static] CallerId=6f6ef388-8a62-48d4-8447-8877e90884f2 isLocal=False IsRemoteCall=True

[GOS] CallerId=6f6ef388-8a62-48d4-8447-8877e90884f2 isLocal=False IsRemoteCall=True
[GOS Broadcast] CallerId=d2c4917d-f7ca-4ee4-a7f9-35b713f53f7d isLocal=True IsRemoteCall=False
[GOS] CallerId=6f6ef388-8a62-48d4-8447-8877e90884f2 isLocal=False IsRemoteCall=True

sboxbot and others added 30 commits November 24, 2025 09:05
This commit imports the C# engine code and game files, excluding C++ source code.

[Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
…cene.PhysicsWorld (Facepunch#3433)

Resolves Facepunch/sbox-issues#9598 (Fixes issues where traces in the editor can throw NREs after exiting play mode)
* Skip menu editor code outside of the menu project
* Asset Browser: skip menu project assets in Everything and Recents
Add slight delay because windows may still briefly hold a lock on some files even after the process exited
* Refactor sync script

Use single filter repo call
Use globs instead of python madness
Ensure shallow clone is clean before working on it

* Add dry run option to sync script
* Add public gitattributes
* Fix leaky swapchain when resizing on game mode and dispose of handle after usage
VideoRecorder would get a strong handle copy of the swapchain every frame and retain it, causing native to fail to shutdown the copies from it
Made usage of getting native swapchain consistent on managed on other stuff, doing it like this ensures GC properly disposes of the strong handles even not disposing explicitly

Remove now unused ScreenRecorder.def and ScreenshotService.def

There are still optimizations to swapchain I'd like to send on another commit, game is allocating way more swapchains than needed even without the leak, has two completely different paths depending if you are MSAA or not, this can all be much simpler
https://files.facepunch.com/sampavlovic/1b1811b1/EjDyxbTahs.png

* Remove NativeLayerRenderTarget, was unused and fucked

* Keep it as an ITexture/HRenderTextureStrong in managed so we avoid IDisposable, ReadTextureAsync with ITexture
…h#3449)

* Support instanced tint on Blendable and Material::From( i )

Blendable supports vertex tint color, but was initially intended for world geometry so there was no point in working with instance color, now works fine

https://files.facepunch.com/sampavlovic/1b2611b1/sbox-dev_qkWlvBOXW8.png

* Build shaders
* More robust downloading of artifacts

Don't download to a temp file first
Try to retry download up to 3 times, if it fails
Fail Bootstrap if any download fails

* Fix contentbuilder and shadercompiler not forwarding to stdout
…eleted

Move filter implementation to python so we have more flexibility when implementing filters.
Make sure deleted files are properly filtered by evaluating globs in the filter itself not before.
Make sure deleted LFS files are accounted for by scanning the history of the shallow clone for delete/changed lfs files.
Whitelist some additional shaders.
* Fix terrain seams and optimize

Overlap LODs by one step to fix holes in LOD transitions
Reuse vertices that exist on same key when building diamond square

https://files.facepunch.com/sampavlovic/1b2411b1/8mb.video-eW2-tNb22a60.mp4

* Add NoTile class and make terrain use it
https://files.facepunch.com/sampavlovic/1b2411b1/sbox-dev_R1FwUmLhvu.mp4
https://files.facepunch.com/sampavlovic/1b2411b1/sbox-dev_YhKyIwvhve.mp4

* Sure why not Mr. Robot
* SceneEditorSession: make game vs editor scenes more distinct, Scene is whichever is currently active

* Route prefab update, model reload etc events to both scenes if needed

* SceneTree update checking a bit cleaner

* Bring back GameEditorSessions instead, so undo, selection etc can all be linked 1:1 with scenes again

* tweak and tidy
aylaylay and others added 24 commits December 11, 2025 09:09
Co-authored-by: aidencurtis <109600275+aidencurtis@users.noreply.github.com>
Fixes public tests failing because of missing directory.
- Can now use modifier keys alongside the Mouse Wheel (lets you do CTRL+MWHEELUP, CTRL+MWHEELDOWN, ect)
- Keybinds are now captured on release instead of on press (Previously pressing CTRL+D would just capture CTRL so you'd have to hold CTRL before capturing and then press D)
Fixes an overload of Gizmo.Draw.Model returning SceneObject instead of SceneModel
…epunch#3610)

---------

Co-authored-by: johncosfm <splatterbiker@gmail.com>
---------

Co-authored-by: DrakeFruit <foxflowgaming@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…acepunch#3613)

* Fixes GameObject references in GameObjectSystem NetLists and NetDictionaries being null on clients.

* dotnet format

---------

Co-authored-by: Andy <10728824+andy013@users.noreply.github.com>
Tint pause button blue when the game is paused.
- `PolygonMesh.SetFaceTextureCoords()` now properly sets `IsDirty`
- Added `PolygonMesh.GetFaceTextureCoords()`
- Added `FastTextureWindow` (which extends RectEditor.Window) and `FastTextureSettings` classes
- Added `MeshRectangle` which is a RectEditor `Rectangle` that contains faces from a mesh unwrapped within the rectangle, reflecting any transform changes made back to the associated mesh faces
- Added `EdgeAwareFaceUnwrapper` class which handles all UV unwrapping
- Added a "Fast Texturing Tool" button to the Mapping Tool's Texture Mode which opens a FastTextureWindow with the selected faces. This can also be opened with the shortcut CTRL+G (from the Texture Mode OR the Face Mode)
- If a Fast Texturing Tool window is open and the faces are deselected (or the user exits the Mapping Tool) the window will automatically close itself
- Implemented U/V Alignment Settings (+ Horizontal/Vertical Flip)
- Implemented Inset X/Y Settings
- Implemented Square Unwrap, Planar Unwrap, and Use Existing mapping modes
- If the selected material has a rect asset, you can double-click on a rect to automatically fit your UV rectangle to the one you double-clicked. (You can also toggle the visibility of the material's rects)
- Implemented the "Pick Edge" button which allows you to select an edge from the unwrap and automatically orient the UVs so that the selected edge is aligned with the grid.
- Added `Rectangle,CanDelete`, used by MeshRectangles so they cant be deleted
- Fixed `RectView.DragResizeRect` behaviour so that resizing a rect will snap the dragged edges to the grid instead of just increasing/decreasing by the grid size
- Added Panning/Zooming to the Rect Editor
- Disabling the Grid in the RectEditor now disables grid snapping
- Can now resize rects in on themselves to resize in the other direction without making an invalid rect
- Added Tile View to RectView
@andy013 andy013 marked this pull request as ready for review December 18, 2025 20:09
@garrynewman
Copy link
Copy Markdown
Member

One for @kurozael to look at

@kurozael kurozael self-assigned this Dec 22, 2025
@kurozael
Copy link
Copy Markdown
Contributor

I'll take a look but at a glance it seems like a complicated way to solve the problem

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.