using System; using System.Collections.Generic; namespace Superlazy { public interface IZone { IEnumerable Units { get; } SLEntity Entity { get; } SLEntity Player { get; } IUnit AddUnit(SLEntity unitEntity); IUnit GetUnit(int handle); SLEntity Message(string message, SLEntity context); void Event(Unit unit, string message, SLEntity context); } public class Zone : IZone { public IEnumerable Units => units; IEnumerable IZone.Units => units; // 인터페이스에서는 IUnit만 적용 public SLEntity Entity { get; } public SLEntity Player { get; } public event Action OnMessage; private int handleIndex = 0; private readonly Dictionary unitHandles = new Dictionary(); private readonly List units = new List(); private readonly List addUnits = new List(); private readonly List removeHandles = new List(); private bool useDelayUnit; internal List startComponents; internal SortedList> components; internal Dictionary>> componentMessages; public Zone(SLEntity session, SLEntity player) { Entity = session; Player = player; ZoneHandler.Begin(this); } public IUnit AddUnit(SLEntity unitEntity) { var unit = new Unit(unitEntity, this); if (useDelayUnit) { addUnits.Add(unit); } else { AddUnit(unit); } return unit; } private void AddUnit(Unit unit) { if (unit == null) { SLLog.Error("Unit is null"); return; } handleIndex += 1; unit.Entity["Handle"] = handleIndex; Entity["Units"][handleIndex] = unit.Entity; if (unit.Entity["UnitType"]) { Entity["UnitTypes"][unit.Entity["UnitType"]][unit.Entity["EventID"]] = handleIndex; } if (unit.Entity["EventID"]) { Entity["EventIDs"][unit.Entity["EventID"]] = handleIndex; } units.Add(unit); unitHandles[handleIndex] = unit; Event(unit, "AddUnit", unit.Entity); UnitHandler.Begin(unit); } private void RemoveUnit(Unit unit) { Event(unit, "RemoveUnit", unit.Entity); UnitHandler.End(unit); if (unit.Entity["UnitType"]) { Entity["UnitTypes"][unit.Entity["UnitType"]][unit.Entity["EventID"]] = false; } if (unit.Entity["EventID"]) { Entity["EventIDs"][unit.Entity["EventID"]] = false; } Entity["Units"][unit.Entity["Handle"]] = false; unitHandles.Remove(unit.Entity["Handle"]); units.Remove(unit); unit.Entity["Handle"] = false; } public IUnit GetUnit(int handle) { if (unitHandles.ContainsKey(handle)) { return unitHandles[handle]; } return null; } public void Update() { ZoneHandler.Update(this); useDelayUnit = true; foreach (var unit in units) { UnitHandler.Update(unit); } foreach (var unit in units) { unit.Message("OnEndUpdate", Entity); } useDelayUnit = false; foreach (var unit in addUnits) { AddUnit(unit); } addUnits.Clear(); removeHandles.Clear(); foreach (var unit in units) { if (unit.Entity.HasChild("End")) { removeHandles.Add(unit.Entity["Handle"]); } } foreach (var handle in removeHandles) { RemoveUnit(unitHandles[handle]); } } public SLEntity Message(string message, SLEntity context) { if (context) { context = context.Override(); } else { context = SLEntity.Empty; // TODO: 전달할때 빈거 전달한게 메모리가 아깝다면 최적화가 필요 } ZoneHandler.Message(message, this, context); return context; } public void Event(Unit unit, string message, SLEntity context) { OnMessage?.Invoke(unit, message, context); } public void AddComponent() where T : ZoneComponent { ZoneHandler.AddComponent(this, typeof(T).Name, typeof(T).Name, SLEntity.Empty); // Start의 경우 이후 즉시 호출하는 케이스들 대응용으로 즉시 실행한다 } public void AddComponent(SLEntity context) where T : ZoneComponent { ZoneHandler.AddComponent(this, typeof(T).Name, typeof(T).Name, context); } public void AddComponent(string key, SLEntity context) where T : ZoneComponent { ZoneHandler.AddComponent(this, key, typeof(T).Name, context); } public void AddComponent(string component) { ZoneHandler.AddComponent(this, component, component, SLEntity.Empty); // Start의 경우 이후 즉시 호출하는 케이스들 대응용으로 즉시 실행한다 } public void AddComponent(string component, SLEntity context) { ZoneHandler.AddComponent(this, component, component, context); } public void AddComponent(string key, string component, SLEntity context) { ZoneHandler.AddComponent(this, key, component, context); } public void RemoveComponent() where T : ZoneComponent { RemoveComponent(typeof(T).Name); } public void RemoveComponent(string component) { if (Entity["Components"][component] == false) return; Entity["Components"][component]["End"] = true; } public void Clear() { foreach (var unit in Units) { unit.Entity["End"] = true; unit.Entity["Force"] = true; } EffectView.ClearEffect(); Update(); handleIndex = 0; ZoneHandler.End(this); } } }