EverestAPI / EverestAPI/Everest

add attribute to make entities always load in the first room entered, regardless of what room they are placed in

Đang mở
#653 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
enhancement
Ngôn ngữ chính
C#
Star
516
Fork
106
Merge trung bình
4 ngày 9 giờ
Pull request đã merge (30 ngày)
5

Mô tả

### i am planning on implementing this myself

Yes

### describe your request

i don't really have a good name for this attribute _(currently i'm calling it `GlobalEntityAttribute`, but global is already a different thing, so if anyone else has a better name i'm happy to change it)_, but it's useful for a variety of things, principally map-wide controllers.
currently i have this in an as-of-yet unreleased helper, so i have a working implementation, but it seems common enough to deserve a place in Everest.

it works by filtering out any entitydata entries corresponding to classes with the annotation during `MapData.Load`, storing them in a `List>` associated with the mapdata, and then adding them to the level in `LevelLoader.LoadingThread`.
the way the entity names corresponding to attribute-having classes are obtained currently requires the entities to be tracked, but this could be easily changed.

### additional context

full example code

```cs
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class GlobalEntityAttribute : Attribute {
private static string[] _entityNames;
private static string[] entityNames {
get {
if (_entityNames != null)
return _entityNames;

_entityNames = Tracker.TrackedEntityTypes
.SelectMany((pair) => {
if (pair.Key.IsDefined(typeof(GlobalEntityAttribute))) {
var attrs = pair.Key
.GetCustomAttributes()
.SelectMany((a) =>
a.IDs.SelectMany((id) => {
var parts = id.Split('=');
if (parts.Length > 0)
return new string[] { parts[0] };
return new string[] { };
})
);
return attrs.ToList();
}
return new List();
}).ToArray();

return _entityNames;
}
}

internal static void Load() {
Everest.Events.LevelLoader.OnLoadingThread += onLoad;
On.Celeste.MapData.Load += onMapDataLoad;
}

internal static void Unload() {
Everest.Events.LevelLoader.OnLoadingThread -= onLoad;
On.Celeste.MapData.Load -= onMapDataLoad;
}

private static void onMapDataLoad(On.Celeste.MapData.orig_Load orig, MapData mapData) {
orig(mapData);

var dyndata = DynamicData.For(mapData);

List> entities;
if (dyndata.TryGet("global_entities", out entities)) {
entities.Clear();
} else {
entities = new();
dyndata.Set("global_entities", entities);
}

var names = entityNames;
foreach (var levelData in mapData.Levels) {
levelData.Entities.RemoveAll((e) => {
if (!names.Contains(e.Name))
return false;

entities.Add(new(e, levelData.Position));
return true;
});
}
}

private static void onLoad(Level level) {
var mapData = level.Session.MapData;
var dyndata = DynamicData.For(mapData);

if (dyndata.TryGet>>("global_entities", out var shadowData)) {
foreach (var shadow in shadowData) {
var loader = Level.EntityLoaders[shadow.Item1.Name];
var entity = loader.Invoke(level, shadow.Item1.Level, shadow.Item2, shadow.Item1);
if (entity is not null)
level.Add(entity);
}
}
}
}
```

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.