-
Notifications
You must be signed in to change notification settings - Fork 441
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add a method for copying components #5654
base: master
Are you sure you want to change the base?
Changes from all commits
bebc895
e5cbd34
9124d01
dfb97d4
fdba05d
f885b68
090a35b
ec8f3e8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1028,6 +1028,58 @@ public bool TryGetComponent([NotNullWhen(true)] EntityUid? uid, ushort netId, | |
return TryGetComponent(uid.Value, netId, out component, meta); | ||
} | ||
|
||
/// <inheritdoc/> | ||
public bool CopyComponent(EntityUid source, EntityUid target, IComponent sourceComponent, [NotNullWhen(true)] out IComponent? component, MetaDataComponent? meta = null) | ||
{ | ||
// Use the concrete type of the sourceComponent to call the generic version | ||
var type = sourceComponent.GetType(); | ||
var method = GetType().GetMethod(nameof(CopyComponent), 1, [typeof(EntityUid), typeof(EntityUid), type.MakeByRefType(), typeof(MetaDataComponent) | ||
])! | ||
.MakeGenericMethod(type); | ||
|
||
var parameters = new object?[] { source, target, null, meta }; | ||
var result = (bool)method.Invoke(this, parameters)!; | ||
component = (IComponent?)parameters[2]; | ||
return result; | ||
} | ||
|
||
/// <inheritdoc/> | ||
public bool CopyComponent<T>(EntityUid source, EntityUid target, [NotNullWhen(true)] out T? component, MetaDataComponent? meta = null) where T : IComponent | ||
{ | ||
component = default; | ||
|
||
if (!MetaQuery.Resolve(target, ref meta)) | ||
return false; | ||
|
||
if (!TryGetComponent<T>(source, out var sourceComp)) | ||
return false; | ||
|
||
var compReg = ComponentFactory.GetRegistration(typeof(T)); | ||
component = (T)ComponentFactory.GetComponent(compReg); | ||
|
||
_serManager.CopyTo(sourceComp, ref component, notNullableOverride: true); | ||
|
||
AddComponentInternal(target, component, compReg, true, false, meta); | ||
return true; | ||
} | ||
|
||
/// <inheritdoc/> | ||
public bool CopyComponents(EntityUid source, EntityUid target, MetaDataComponent? meta = null, params IComponent[] types) | ||
{ | ||
if (!MetaQuery.Resolve(target, ref meta)) | ||
return false; | ||
|
||
var allSuccessful = true; | ||
|
||
foreach (var type in types) | ||
{ | ||
if (!CopyComponent(source, target, type, out _, meta)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. each call will lead to dirty internally, i wonder if such bulk operations could be performed in a more optimal manner if dirty-related code would be called once?.. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If metadatacomp is passed through it is just a field check for lastmodified which is not super bad for now. |
||
allSuccessful = false; | ||
} | ||
|
||
return allSuccessful; | ||
} | ||
|
||
public EntityQuery<TComp1> GetEntityQuery<TComp1>() where TComp1 : IComponent | ||
{ | ||
var comps = _entTraitArray[CompIdx.ArrayIndex<TComp1>()]; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -341,6 +341,38 @@ public partial interface IEntityManager | |
/// <returns>If the component existed in the entity.</returns> | ||
bool TryGetComponent([NotNullWhen(true)] EntityUid? uid, ushort netId, [NotNullWhen(true)] out IComponent? component, MetaDataComponent? meta = null); | ||
|
||
/// <summary> | ||
/// Copy a single component from source to target entity and return a reference to the copied component. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'Tries to copy', and 'if source entity have it' should be here, probably There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Method description also leaves to interpretation the question of 'what will it do if target entity already have that component'. The closest thing we can imagine is - it will return false and null, but it is also possible it will this can be avoided by making more overloads and mimics for TryComp and Resolve methods but i wouldn't advice that until someone else asks. Clear description will suffice i think :3 (and no, u better have at least some more description in summary, as people will read summary first, and could read description on property only by doing extra work) |
||
/// </summary> | ||
/// <param name="source">The source entity to copy the component from</param> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Other xml-docs in file have dot at the end so this prolly all should too :3 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, thats fair for all of the comments here |
||
/// <param name="target">The target entity to copy the component to</param> | ||
/// <param name="type">The type of component to copy</param> | ||
/// <param name="component">The copied component if successful</param> | ||
/// <param name="meta">Optional metadata of the target entity</param> | ||
/// <returns>Whether the component was successfully copied</returns> | ||
bool CopyComponent(EntityUid source, EntityUid target, IComponent type, [NotNullWhen(true)] out IComponent? component, MetaDataComponent? meta = null); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldn't it all be TryCopyComponent, as it follow overall TryXXX Microsoft lovely pattern There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes it should, i will fix it one day i swear |
||
|
||
/// <summary> | ||
/// Copy a typed component from source to target entity and return a reference to the copied component. | ||
/// </summary> | ||
/// <typeparam name="T">The type of component to copy</typeparam> | ||
/// <param name="source">The source entity to copy from</param> | ||
/// <param name="target">The target entity to copy to</param> | ||
/// <param name="component">The copied component if successful</param> | ||
/// <param name="meta">Optional metadata of the target entity</param> | ||
/// <returns>Whether the component was successfully copied</returns> | ||
bool CopyComponent<T>(EntityUid source, EntityUid target, [NotNullWhen(true)] out T? component, MetaDataComponent? meta = null) where T : IComponent; | ||
|
||
/// <summary> | ||
/// Copy multiple components from source to target entity. | ||
/// </summary> | ||
/// <param name="source">The source entity to copy from</param> | ||
/// <param name="target">The target entity to copy to</param> | ||
/// <param name="meta">Optional metadata of the target entity</param> | ||
/// <param name="types">Array of component types to copy</param> | ||
/// <returns>Whether all components were successfully copied</returns> | ||
bool CopyComponents(EntityUid source, EntityUid target, MetaDataComponent? meta = null, params IComponent[] types); | ||
|
||
/// <summary> | ||
/// Returns a cached struct enumerator with the specified component. | ||
/// </summary> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
better use GetType result to duplicate generic version of code. Reflection of this type could be used if method that was generated dynamically would be cached for each requested type, but sadly it still will make code poorly readable. maybe there is an even better idea how to do it, but using dynamic method creation here is a bad fit :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The overhead of this will blow using generics out of the water, I'll try and re-write something if I get a chance.