Hello,
There was a severe lag and the server went into a reboot. After it came back online, we found that some buildings and some players’ loot were missing.
The log contains the following error:Skipping entity <id> - it's a player <steamId> who is in the save multiple times
Buildings/loot missing after lag and server restart (error: “Skipping entity… player in the save multiple times”)
Did you every find a solution? I am experiencing the same.
Merged post
I found a solution to my problem, and perhaps yours as well...
TL;DR - Run the Python script at the end of this post in Duplicates mode to sanitize your save file. Happy days after... (hopefully)
Here is my understanding of the Skipping entity mechanic:
When Rust loads the save file, it reads entities one by one. When it encounters a entity with a basePlayer, it records the userid. If it later encounters another basePlayer with the same userid, it says "this player is in the save multiple times" and starts skipping that entity and everything that follows it in that section of the save (basically goes nuclear imo). I guess that this is Rust's protection against corrupted saves with duplicate players... the idea being that if there are two copies of a player, something went wrong, so skipping the duplicates.
As implied earlier, this method comes across as very agressive, and everything but fool proof. It does not appear to look at each entity individually and validates the legitimacy. It can't as not every entity contains a basePlayer ident. My observation is that the file is essentially a flat sequential list of entities and Rust relies on ordering to associate entities with players. So when it hits a basePlayer entity, it effectively says "everything that follows belongs to this player". Which I guess is evidently flaud based on the issue we are experiencing :/
My solution:
So my issue was Plugin/NPC related, this made it quite easy to detect and remove everything that was not a legitimate player. I guess in your case you'd have to identify the player(s) that were causing the duplicate entities and surgically remove them from the save file.
I've used a python script to read the save file and surgically remove ALL entities that were created by NPC's. Prompted for some adjustments in your case. The script has a selector between two modes: All NPC's or only duplicate basePlayer entities. Hope it is of help!
import struct
import sys
def decode_varint(buf, pos):
result = 0
shift = 0
while pos < len(buf):
b = buf[pos]
result |= (b & 0x7F) << shift
pos += 1
if not (b & 0x80):
break
shift += 7
return result, pos
def parse_proto_fields(buf):
fields = {}
pos = 0
while pos < len(buf):
try:
start = pos
tag, new_pos = decode_varint(buf, pos)
if tag == 0: break
field_num = tag >> 3
wire_type = tag & 7
if wire_type == 0:
val, pos = decode_varint(buf, new_pos)
fields[field_num] = ('varint', val)
elif wire_type == 1:
pos = new_pos + 8
fields[field_num] = ('fixed64', 0)
elif wire_type == 2:
length, dpos = decode_varint(buf, new_pos)
fields[field_num] = ('bytes', buf[dpos:dpos+length])
pos = dpos + length
elif wire_type == 5:
fields[field_num] = ('fixed32', struct.unpack_from('<I', buf, new_pos)[0])
pos = new_pos + 4
else:
break
except:
break
return fields
# ============================================================
# CONFIGURATION
# ============================================================
INPUT_FILE = "proceduralmap.5000.1337.281.sav"
OUTPUT_FILE = "proceduralmap.5000.1337.281.fixed.sav"
# Mode: "all_npc" = remove ALL basePlayer entities with non-Steam64 userids (my issue)
# "duplicates" = only remove DUPLICATE basePlayer entities (keeps first, removes copies)
MODE = "duplicates"
# ============================================================
STEAM64_MIN = 76561############
print("=" * 70)
print("RUST SAVE FILE FIXER")
print(f"Mode: {MODE}")
print("=" * 70)
with open(INPUT_FILE, 'rb') as f:
data = bytearray(f.read())
print(f"\nOriginal file size: {len(data):,} bytes")
json_end = data.find(b'}') + 1
header = bytes(data[:json_end + 9])
body = data[json_end:]
# Parse all entities
entities = []
pos = 9
while pos + 4 < len(body):
entity_len = struct.unpack_from('<I', body, pos)[0]
if entity_len == 0 or entity_len > 10000000: break
entities.append({'length': entity_len, 'data': bytes(body[pos+4:pos+4+entity_len])})
pos = pos + 4 + entity_len
print(f"Total entities parsed: {len(entities):,}")
# Scan all entities for basePlayer data
seen_userids = {} # userid -> first entity index
remove_indices = set()
all_baseplayer = []
for i, ent in enumerate(entities):
fields = parse_proto_fields(ent['data'])
if 3 not in fields or fields[3][0] != 'bytes':
continue
f3 = parse_proto_fields(fields[3][1])
if 2 not in f3:
continue
userid = f3[2][1]
# Get entity info
uid = None; prefab = None
if 1 in fields:
bn = parse_proto_fields(fields[1][1])
uid = bn.get(1, (None, None))[1]
prefab = bn.get(3, (None, None))[1]
is_steam = userid >= STEAM64_MIN
all_baseplayer.append({
'index': i, 'uid': uid, 'prefab': prefab,
'userid': userid, 'steam64': is_steam
})
if MODE == "all_npc":
if not is_steam:
remove_indices.add(i)
print(f" REMOVE entity #{i:>6}, uid={uid:>8}, userid={userid} (NPC)")
else:
print(f" KEEP entity #{i:>6}, uid={uid:>8}, userid={userid} (Steam64)")
elif MODE == "duplicates":
if userid in seen_userids:
remove_indices.add(i)
first = seen_userids[userid]
label = "Steam64" if is_steam else "NPC"
print(f" REMOVE entity #{i:>6}, uid={uid:>8}, userid={userid} ({label}) "
f"[duplicate of entity #{first}]")
else:
seen_userids[userid] = i
label = "Steam64" if is_steam else "NPC"
print(f" KEEP entity #{i:>6}, uid={uid:>8}, userid={userid} ({label}) [first occurrence]")
print(f"\n--- SUMMARY ---")
print(f" BasePlayer entities found: {len(all_baseplayer)}")
print(f" Entities to remove: {len(remove_indices)}")
print(f" Entities to keep: {len(entities) - len(remove_indices):,}")
# Write fixed save
output = bytearray()
output.extend(header)
for i, ent in enumerate(entities):
if i not in remove_indices:
output.extend(struct.pack('<I', ent['length']))
output.extend(ent['data'])
with open(OUTPUT_FILE, 'wb') as f:
f.write(output)
print(f"\n Original size: {len(data):>10,} bytes")
print(f" Fixed size: {len(output):>10,} bytes")
print(f" Removed: {len(data) - len(output):>10,} bytes")
# Verify
with open(OUTPUT_FILE, 'rb') as f:
fixed = bytearray(f.read())
fixed_body = fixed[fixed.find(b'}') + 1:]
count = 0
vpos = 9
while vpos + 4 < len(fixed_body):
el = struct.unpack_from('<I', fixed_body, vpos)[0]
if el == 0 or el > 10000000: break
count += 1
vpos = vpos + 4 + el
print(f"\n Verified: {count:,} entities, {len(fixed_body) - vpos} leftover bytes")
print(f" {'VALID' if len(fixed_body) - vpos == 0 else 'WARNING: leftover bytes!'}")
print("=" * 70) Hello, I've had the same problem since the Naval update after a server restart. It happens even when I start the server without plugins. Every time, something is removed from the players' accounts. In my opinion, this happens when you build a naval boat.
Merged post
This helped me with creating the LoadEntityBasePlayerFix.cs file.
https://umod.org/community/nteleportation/57248-skipping-entity-foundation-id-its-a-player-steamid-who-is-in-the-save-multiple-times-on-server-restart