diff --git a/QSB/AuthoritySync/IAuthWorldObject.cs b/QSB/AuthoritySync/IAuthWorldObject.cs
new file mode 100644
index 00000000..323f4849
--- /dev/null
+++ b/QSB/AuthoritySync/IAuthWorldObject.cs
@@ -0,0 +1,15 @@
+using QSB.WorldSync;
+
+namespace QSB.AuthoritySync;
+
+///
+/// a world object that has an owner
+///
+public interface IAuthWorldObject : IWorldObject
+{
+ public uint Owner { get; set; }
+ ///
+ /// can the world object have authority
+ ///
+ public bool CanOwn { get; }
+}
diff --git a/QSB/AuthoritySync/WorldObjectAuthMessage.cs b/QSB/AuthoritySync/WorldObjectAuthMessage.cs
new file mode 100644
index 00000000..d4269520
--- /dev/null
+++ b/QSB/AuthoritySync/WorldObjectAuthMessage.cs
@@ -0,0 +1,45 @@
+using QSB.Messaging;
+using QSB.Player;
+
+namespace QSB.AuthoritySync;
+
+///
+/// request ownership of a world object
+///
+public class WorldObjectAuthMessage : QSBWorldObjectMessage
+{
+ public WorldObjectAuthMessage(uint owner) : base(owner) { }
+
+ public override bool ShouldReceive
+ {
+ get
+ {
+ if (!base.ShouldReceive)
+ {
+ return false;
+ }
+
+ // Deciding if to change the object's owner
+ // Message
+ // | = 0 | > 0 |
+ // = 0 | No | Yes |
+ // > 0 | Yes | No |
+ // if Obj==Message then No
+ // Obj
+
+ return (WorldObject.Owner == 0 || Data == 0) && WorldObject.Owner != Data;
+ }
+ }
+
+ public override void OnReceiveLocal() => WorldObject.Owner = Data;
+
+ public override void OnReceiveRemote()
+ {
+ WorldObject.Owner = Data;
+ if (WorldObject.Owner == 0 && WorldObject.CanOwn)
+ {
+ // object has no owner, but is still active for this player. request ownership
+ WorldObject.SendMessage(new WorldObjectAuthMessage(QSBPlayerManager.LocalPlayerId));
+ }
+ }
+}