how do i solve this problem?
the netcode ghost collection produces this message at runtime when i add too many ghosts (11)
how do i solve this problem?
the netcode ghost collection produces this message at runtime when i add too many ghosts (11)
How do you know that the issue is adding too many ghosts? I started having this issue recently, but can’t say exactly which system the issue originates from.
disabling ghosts in the ghost collection authoring singleton until i have just 10 and clicking regenerate collection fixes the problem. it doesn’t seem to matter which ghosts you disable, just that its only 10 for me…
how many ghosts do you have?
Thanks! I have 7, but two of them have quite a few children. I’ll try removing ghosts too. Have you tried removing different ones each time to see if the issue stems not from the number of ghosts but from their configuration?
yes, it doesn’t seem to make a difference which ghosts i remove. my ones are all roughly the same size. i encounter this error when i have >10 of any ghosts
Ok, for me it’s the same – when I remove one ghost, I probably make it just under a limit (of 10000 what?). If not, I get InvalidProgramException: Passing an argument of size '10144'
.
I am not yet very well versed in C#, but is it possible that the inputJob
job handle size from in public sealed override void Update()
of JobComponentSystem
and that is passed into OnUpdate
is too large? In any case, I’ll have to do some reading…
@timjohansson Is this an issue you’ve seen already?
It’s not about the number of the ghosts but about the size of the GhostSerializers.
Currently code gen generates code like this for serializers:
private ArchetypeChunkComponentType<AbilityCollection> ghostAbilityCollectionType;
private ArchetypeChunkComponentType<PredictingPlayerId> ghostPredictingPlayerIdType;
private ArchetypeChunkBufferType<LinkedEntityGroup> ghostLinkedEntityGroupType;
private ComponentDataFromEntity<AbilityControl> ghostChild0AbilityControlType;
private ComponentDataFromEntity<AbilityControl> ghostChild1AbilityControlType;
private ComponentDataFromEntity<AbilityControl> ghostChild2AbilityControlType;
As you can see it creates duplicate ComponentDataFromEntity when a synced component exists on the main entity and children.
Until the new workflows drop you can just manually remove the duplicates which should free up some space.
I noticed the duplication, but did not make the connection. There should only be one ComponentDataFromEntity<T>
per T, I assume.
@Lukas_Kastern Do you have any insights when the new workflow drops?
Sadly no, all information i have are from forum threads.
Do you really need to sync all those translations?
In case you aren’t aware, you can remove them by toggling ManualFieldList on the GhostAuthoringComponent fields.
I’ve looked at the code gen to make a more automated workaround.
To implement it replace the GenerateSerializer method inside com.unity.netcode@0.2.0-preview.5\Editor\GhostAuthoringComponentEditor.cs with:
static void GenerateSerializer(GhostAuthoringComponent ghostInfo, string assetPath, GhostCodeGen.Batch batch)
{
var addedTypes = new List<string>( );
var codeGen = new GhostCodeGen("Packages/com.unity.netcode/Editor/CodeGenTemplates/GhostSerializer.cs");
var replacements = new Dictionary<string, string>();
int serverComponentCount = 0;
bool needsLinkedEntityGroup = false;
HashSet<string> imports = new HashSet<string>();
imports.Add("Unity.Entities");
imports.Add("Unity.Collections");
imports.Add("Unity.NetCode");
for (int comp = 0; comp < ghostInfo.Components.Length; ++comp)
{
var entityIndex = ghostInfo.Components[comp].entityIndex;
if (!ghostInfo.Components[comp].server)
continue;
imports.Add(ghostInfo.Components[comp].NamespaceName);
var componentTypeName = GetShortName(ghostInfo.Components[comp]);
replacements.Clear();
replacements.Add("GHOST_COMPONENT_TYPE_NAME", componentTypeName);
replacements.Add("GHOST_COMPONENT_TYPE", ghostInfo.Components[comp].ShortName.Replace("+", "."));
replacements.Add("GHOST_ENTITY_INDEX", entityIndex.ToString());
if (entityIndex == 0)
{
++serverComponentCount;
//codeGen.GenerateFragment("GHOST_COMPONENT_TYPE", replacements);
//codeGen.GenerateFragment("GHOST_ASSIGN_COMPONENT_TYPE", replacements);
}
if (ghostInfo.Components[comp].fields.Length > 0)
{
var doGenerateComponentData = !addedTypes.Contains( replacements["GHOST_COMPONENT_TYPE"] );
if ( doGenerateComponentData )
{
addedTypes.Add( replacements["GHOST_COMPONENT_TYPE"] );
}
if (entityIndex == 0)
{
codeGen.GenerateFragment("GHOST_COMPONENT_TYPE_DATA", replacements);
codeGen.GenerateFragment("GHOST_ASSIGN_COMPONENT_TYPE_DATA", replacements);
codeGen.GenerateFragment("GHOST_ASSIGN_CHUNK_ARRAY", replacements);
}
else
{
needsLinkedEntityGroup = true;
if ( doGenerateComponentData )
{
codeGen.GenerateFragment( "GHOST_COMPONENT_TYPE_CHILD_DATA", replacements );
codeGen.GenerateFragment("GHOST_ASSIGN_COMPONENT_TYPE_CHILD_DATA", replacements);
}
}
for (int field = 0; field < ghostInfo.Components[comp].fields.Length; ++field)
{
replacements["GHOST_FIELD_NAME"] = ghostInfo.Components[comp].fields[field].name;
if (entityIndex == 0)
{
codeGen.GenerateFragment("GHOST_ASSIGN_SNAPSHOT", replacements);
}
else
{
codeGen.GenerateFragment("GHOST_ASSIGN_CHILD_SNAPSHOT", replacements);
}
}
}
}
if (needsLinkedEntityGroup)
{
++serverComponentCount;
replacements.Clear();
replacements.Add("GHOST_COMPONENT_TYPE_NAME", "LinkedEntityGroup");
replacements.Add("GHOST_COMPONENT_TYPE", "LinkedEntityGroup");
//codeGen.GenerateFragment("GHOST_COMPONENT_TYPE", replacements);
//codeGen.GenerateFragment("GHOST_ASSIGN_COMPONENT_TYPE", replacements);
codeGen.GenerateFragment("GHOST_BUFFER_COMPONENT_TYPE_DATA", replacements);
codeGen.GenerateFragment("GHOST_ASSIGN_BUFFER_COMPONENT_TYPE_DATA", replacements);
codeGen.GenerateFragment("GHOST_ASSIGN_CHUNK_BUFFER_ARRAY", replacements);
}
replacements.Clear();
foreach (var ns in imports)
{
if (ns != null && ns != "")
{
replacements["GHOST_USING"] = ns;
codeGen.GenerateFragment("GHOST_USING_STATEMENT", replacements);
}
}
replacements.Clear();
replacements.Add("GHOST_NAME", ghostInfo.Name);
replacements.Add("GHOST_IMPORTANCE", ghostInfo.Importance);
replacements.Add("GHOST_COMPONENT_COUNT", serverComponentCount.ToString());
codeGen.GenerateFile(assetPath, ghostInfo.RootPath, ghostInfo.SerializerPath, replacements, batch);
}
I haven’t added anything crazy to that method, it just keeps track of the added child types and only creates one ComponentDataFromEntity fragment.
Than replace the serializer code gen file which is located at com.unity.netcode@0.2.0-preview.5\Editor\CodeGenTemplates\GhostSerializer.cs with the attached file.
6118730–666584–GhostSerializer.cs (3.15 KB)
Thanks for the reminder – that helps me get under the limit!
I had resorted to not messing with the child elements as they were/are unhelpfully named in the authoring component (what exactly is “child 7”) and one can’t set predicted/interpolated per child. Also, I have an automated workflow where I auto-generate the GhostAuthoringComponent, so now I’ll update that to override the field list for most children.
Not syncing Translation/Rotation in all children was quite easy to add to the ghost component authoring generator:
private static void postProcessGhost(GameObject prefab)
{
var t = prefab.transform;
var ghost = t.GetComponent<GhostAuthoringComponent>();
// Update component list.
GhostAuthoringComponentEditor.SyncComponentList(ghost);
// Unset prediction from all components in the list.
var components = ghost.Components;
for (var i = 0; i < components.Length; i++)
{
components[i].predictedClient = false;
// Do not sync Translation/Rotation in all children.
if (components[i].entityIndex != 0) // Child N
{
if (components[i].ShortName == "Translation" || components[i].ShortName == "Rotation")
{
components[i].manualFieldList = true;
components[i].fields = new GhostAuthoringComponent.GhostComponentField[] { };
}
}
}
// Generate the ghost code.
GhostAuthoringComponentEditor.GenerateGhost(ghost);
}
In case anyone is interested