mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-09-24 21:51:19 -04:00
IEvent uses volatile array instead of a list, fixes multithreading modification errors
This commit is contained in:
parent
348b62f5f7
commit
0128e3c3b2
@ -17,10 +17,9 @@
|
||||
*/
|
||||
using System;
|
||||
|
||||
namespace MCGalaxy
|
||||
{
|
||||
public sealed partial class Block
|
||||
{
|
||||
namespace MCGalaxy {
|
||||
public sealed partial class Block {
|
||||
|
||||
public static string Name(byte block) { return Props[block].Name; }
|
||||
|
||||
public static byte Byte(string type) {
|
||||
|
@ -15,12 +15,11 @@
|
||||
or implied. See the Licenses for the specific language governing
|
||||
permissions and limitations under the Licenses.
|
||||
*/
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using MCGalaxy.Blocks;
|
||||
using MCGalaxy.Network;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.IO;
|
||||
using MCGalaxy.Blocks;
|
||||
using MCGalaxy.Network;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MCGalaxy {
|
||||
public sealed class BlockDefinition {
|
||||
|
@ -16,7 +16,6 @@
|
||||
permissions and limitations under the Licenses.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace MCGalaxy.Blocks {
|
||||
|
@ -17,7 +17,6 @@
|
||||
*/
|
||||
using System;
|
||||
using System.Text;
|
||||
using MCGalaxy.Blocks;
|
||||
|
||||
namespace MCGalaxy.Blocks {
|
||||
|
||||
|
@ -275,7 +275,7 @@ namespace MCGalaxy.Commands.Fun {
|
||||
|
||||
|
||||
public override void Help(Player p) {
|
||||
Player.Message(p, "%T/cd joins/leave %H- joins/leaves the game");
|
||||
Player.Message(p, "%T/cd join/leave %H- joins/leaves the game");
|
||||
Player.Message(p, "%T/cd players %H- lists players currently playing");
|
||||
Player.Message(p, "%T/cd rules %H- view the rules of countdown");
|
||||
if (CheckExtraPerm(p, 1)) {
|
||||
@ -289,7 +289,7 @@ namespace MCGalaxy.Commands.Fun {
|
||||
Player.Message(p, "%H speed can be: slow, normal, fast, extreme or ultimate");
|
||||
Player.Message(p, "%H mode can be: normal or freeze");
|
||||
Player.Message(p, "%T/cd end %H- force ends current round of countdown");
|
||||
Player.Message(p, "%T/cd reset %H- resets the map. Note %T/cd start %Hauto does this.");
|
||||
Player.Message(p, "%T/cd reset %H- resets the map. %T/cd start %Halso resets map.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ namespace MCGalaxy.Events.EconomyEvents {
|
||||
public sealed class OnMoneyChangedEvent : IEvent<OnMoneyChanged> {
|
||||
public static void Call(Player p) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(p));
|
||||
CallCommon(pl => pl(p));
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ namespace MCGalaxy.Events.EconomyEvents {
|
||||
public sealed class OnEcoTransactionEvent : IEvent<OnEcoTransaction> {
|
||||
public static void Call(EcoTransaction transaction) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(transaction));
|
||||
CallCommon(pl => pl(transaction));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ namespace MCGalaxy.Events.GroupEvents {
|
||||
public sealed class OnGroupLoadedEvent : IEvent<GroupLoaded> {
|
||||
public static void Call(Group g) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(g));
|
||||
CallCommon(pl => pl(g));
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ namespace MCGalaxy.Events.GroupEvents {
|
||||
public sealed class OnGroupLoadEvent : IEvent<GroupLoad> {
|
||||
public static void Call() {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl());
|
||||
CallCommon(pl => pl());
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ namespace MCGalaxy.Events.GroupEvents {
|
||||
public sealed class OnGroupSaveEvent : IEvent<GroupSave> {
|
||||
public static void Call() {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl());
|
||||
CallCommon(pl => pl());
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ namespace MCGalaxy.Events.GroupEvents {
|
||||
public sealed class OnChangingGroupEvent : IEvent<OnChangingGroup> {
|
||||
public static void Call(string player, Group curRank, Group newRank) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(player, curRank, newRank));
|
||||
CallCommon(pl => pl(player, curRank, newRank));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
or implied. See the Licenses for the specific language governing
|
||||
permissions and limitations under the Licenses.
|
||||
*/
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@ -23,7 +23,7 @@ namespace MCGalaxy.Events {
|
||||
/// <remarks> *** You MUST use a DIFFERENT delegate type for each subclass *** <br/><br/>
|
||||
/// This is because the static event lists are unique to each new generic type instantiation, not each new subclass. </remarks>
|
||||
public class IEvent<IMethod> {
|
||||
protected internal static List<IEvent<IMethod>> handlers = new List<IEvent<IMethod>>();
|
||||
protected internal static VolatileArray<IEvent<IMethod>> handlers = new VolatileArray<IEvent<IMethod>>();
|
||||
protected IMethod method;
|
||||
protected Priority priority;
|
||||
|
||||
@ -36,21 +36,23 @@ namespace MCGalaxy.Events {
|
||||
|
||||
IEvent<IMethod> handler = new IEvent<IMethod>();
|
||||
handler.method = method; handler.priority = priority;
|
||||
handlers.Add(handler);
|
||||
SortHandlers();
|
||||
AddHandler(handler);
|
||||
}
|
||||
|
||||
/// <summary> Unregisters the given handler from this event. </summary>
|
||||
public static void Unregister(IMethod method) {
|
||||
if (Find(method) == null)
|
||||
IEvent<IMethod> handler = Find(method);
|
||||
if (handler == null)
|
||||
throw new ArgumentException("Method was not registered as a handler!");
|
||||
|
||||
handlers.Remove(Find(method));
|
||||
|
||||
handlers.Remove(handler);
|
||||
}
|
||||
|
||||
public static IEvent<IMethod> Find(IMethod method) {
|
||||
Delegate methodDel = (Delegate)((object)method);
|
||||
foreach (var p in handlers) {
|
||||
IEvent<IMethod>[] items = handlers.Items;
|
||||
|
||||
foreach (var p in items) {
|
||||
Delegate pMethodDel = (Delegate)((object)p.method);
|
||||
if (pMethodDel == methodDel) return p;
|
||||
}
|
||||
@ -58,27 +60,40 @@ namespace MCGalaxy.Events {
|
||||
}
|
||||
|
||||
|
||||
protected static void SortHandlers() {
|
||||
handlers.Sort((a, b) => b.priority.CompareTo(a.priority));
|
||||
static void AddHandler(IEvent<IMethod> handler) {
|
||||
// We want both the add and sorting is in one step
|
||||
lock (handlers.locker) {
|
||||
IEvent<IMethod>[] old = handlers.Items;
|
||||
IEvent<IMethod>[] items = new IEvent<IMethod>[old.Length + 1];
|
||||
for (int i = 0; i < old.Length; i++) {
|
||||
items[i] = old[i];
|
||||
}
|
||||
|
||||
items[old.Length] = handler;
|
||||
Array.Sort(items, (a, b) => b.priority.CompareTo(a.priority));
|
||||
handlers.Items = items;
|
||||
}
|
||||
}
|
||||
|
||||
protected static void CallImpl(Action<IMethod> action) {
|
||||
try {
|
||||
foreach (var pl in handlers) {
|
||||
try {
|
||||
action(pl.method);
|
||||
} catch (Exception ex) {
|
||||
Logger.Log(LogType.Warning, "Plugin {0} errored when calling {1} event",
|
||||
GetFullMethodName(pl.method), typeof(IMethod).Name);
|
||||
Logger.LogError(ex);
|
||||
}
|
||||
protected static void CallCommon(Action<IMethod> action) {
|
||||
IEvent<IMethod>[] items = handlers.Items;
|
||||
for (int i = 0; i < items.Length; i++) {
|
||||
IEvent<IMethod> handler = items[i];
|
||||
|
||||
try {
|
||||
action(handler.method);
|
||||
} catch (Exception ex) {
|
||||
LogHandlerException(ex, handler);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Logger.Log(LogType.Warning, "Error when calling {0} event", typeof(IMethod).Name);
|
||||
Logger.LogError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void LogHandlerException(Exception ex, IEvent<IMethod> handler) {
|
||||
Logger.Log(LogType.Warning, "Plugin {0} errored when calling {1} event",
|
||||
GetFullMethodName(handler.method), typeof(IMethod).Name);
|
||||
Logger.LogError(ex);
|
||||
}
|
||||
|
||||
static string GetFullMethodName(object method) {
|
||||
Delegate del = (Delegate)((object)method);
|
||||
return del.Method.ReflectedType.FullName + "." + del.Method.Name;
|
||||
|
@ -24,7 +24,7 @@ namespace MCGalaxy.Events.LevelEvents {
|
||||
public sealed class OnLevelLoadedEvent : IEvent<OnLevelLoaded> {
|
||||
public static void Call(Level lvl) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(lvl));
|
||||
CallCommon(pl => pl(lvl));
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ namespace MCGalaxy.Events.LevelEvents {
|
||||
public sealed class OnLevelLoadEvent : IEvent<OnLevelLoad> {
|
||||
public static void Call(string name) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(name));
|
||||
CallCommon(pl => pl(name));
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ namespace MCGalaxy.Events.LevelEvents {
|
||||
public sealed class OnLevelSaveEvent : IEvent<OnLevelSave> {
|
||||
public static void Call(Level lvl) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(lvl));
|
||||
CallCommon(pl => pl(lvl));
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,7 +48,7 @@ namespace MCGalaxy.Events.LevelEvents {
|
||||
public sealed class OnLevelUnloadEvent : IEvent<OnLevelUnload> {
|
||||
public static void Call(Level lvl) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(lvl));
|
||||
CallCommon(pl => pl(lvl));
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ namespace MCGalaxy.Events.LevelEvents {
|
||||
public sealed class OnPhysicsStateChangedEvent : IEvent<OnPhysicsStateChanged> {
|
||||
public static void Call(Level lvl, PhysicsState state) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(lvl, state));
|
||||
CallCommon(pl => pl(lvl, state));
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ namespace MCGalaxy.Events.LevelEvents {
|
||||
public sealed class OnPhysicsUpdateEvent : IEvent<OnPhysicsUpdate> {
|
||||
public static void Call(ushort x, ushort y, ushort z, PhysicsArgs extraInfo, Level l) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(x, y, z, extraInfo, l));
|
||||
CallCommon(pl => pl(x, y, z, extraInfo, l));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ namespace MCGalaxy.Events {
|
||||
public sealed class OnModActionEvent : IEvent<OnModAction> {
|
||||
public static void Call(ModAction e) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(e));
|
||||
CallCommon(pl => pl(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ namespace MCGalaxy.Events.PlayerEvents {
|
||||
public sealed class OnPlayerChatEvent : IEvent<OnPlayerChat> {
|
||||
public static void Call(Player p, string message) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(p, message));
|
||||
CallCommon(pl => pl(p, message));
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ namespace MCGalaxy.Events.PlayerEvents {
|
||||
public sealed class OnPlayerMoveEvent : IEvent<OnPlayerMove> {
|
||||
public static void Call(Player p, Position next, byte yaw, byte pitch) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(p, next, yaw, pitch));
|
||||
CallCommon(pl => pl(p, next, yaw, pitch));
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ namespace MCGalaxy.Events.PlayerEvents {
|
||||
public sealed class OnSQLSaveEvent : IEvent<OnSQLSave> {
|
||||
public static void Call(Player p, string ysqlcommand) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(p, ysqlcommand));
|
||||
CallCommon(pl => pl(p, ysqlcommand));
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ namespace MCGalaxy.Events.PlayerEvents {
|
||||
public sealed class OnPlayerCommandEvent : IEvent<OnPlayerCommand> {
|
||||
public static void Call(Player p, string cmd, string args) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(p, cmd, args));
|
||||
CallCommon(pl => pl(p, cmd, args));
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ namespace MCGalaxy.Events.PlayerEvents {
|
||||
public sealed class OnPlayerConnectEvent: IEvent<OnPlayerConnect> {
|
||||
public static void Call(Player p) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(p));
|
||||
CallCommon(pl => pl(p));
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,7 +73,7 @@ namespace MCGalaxy.Events.PlayerEvents {
|
||||
public sealed class OnPlayerConnectingEvent: IEvent<OnPlayerConnecting> {
|
||||
public static void Call(Player p, string mppass) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(p, mppass));
|
||||
CallCommon(pl => pl(p, mppass));
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,7 +82,7 @@ namespace MCGalaxy.Events.PlayerEvents {
|
||||
public sealed class OnPlayerDeathEvent : IEvent<OnPlayerDeath> {
|
||||
public static void Call(Player p, ExtBlock block) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(p, block));
|
||||
CallCommon(pl => pl(p, block));
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ namespace MCGalaxy.Events.PlayerEvents {
|
||||
public sealed class OnPlayerDisconnectEvent : IEvent<OnPlayerDisconnect> {
|
||||
public static void Call(Player p, string reason) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(p, reason));
|
||||
CallCommon(pl => pl(p, reason));
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,7 +100,7 @@ namespace MCGalaxy.Events.PlayerEvents {
|
||||
public sealed class OnBlockChangeEvent : IEvent<OnBlockChange> {
|
||||
public static void Call(Player p, ushort x, ushort y, ushort z, ExtBlock block) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(p, x, y, z, block));
|
||||
CallCommon(pl => pl(p, x, y, z, block));
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,7 +113,7 @@ namespace MCGalaxy.Events.PlayerEvents {
|
||||
ushort yaw, ushort pitch, byte entity,
|
||||
ushort x, ushort y, ushort z, TargetBlockFace face) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(p, button, action, yaw,
|
||||
CallCommon(pl => pl(p, button, action, yaw,
|
||||
pitch, entity, x, y, z, face));
|
||||
}
|
||||
}
|
||||
@ -123,7 +123,7 @@ namespace MCGalaxy.Events.PlayerEvents {
|
||||
public sealed class OnMessageRecievedEvent : IEvent<OnMessageReceived> {
|
||||
public static void Call(Player p, string message) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(p, message));
|
||||
CallCommon(pl => pl(p, message));
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,7 +132,7 @@ namespace MCGalaxy.Events.PlayerEvents {
|
||||
public sealed class OnJoinedLevelEvent : IEvent<OnJoinedLevel> {
|
||||
public static void Call(Player p, Level prevLevl, Level level) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(p, prevLevl, level));
|
||||
CallCommon(pl => pl(p, prevLevl, level));
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,7 +143,7 @@ namespace MCGalaxy.Events.PlayerEvents {
|
||||
public static void Call(Player p, PlayerAction action,
|
||||
string message = null, bool stealth = false) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(p, action, message, stealth));
|
||||
CallCommon(pl => pl(p, action, message, stealth));
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,7 +152,7 @@ namespace MCGalaxy.Events.PlayerEvents {
|
||||
public sealed class OnSendingMotdEvent : IEvent<OnSendingMotd> {
|
||||
public static void Call(Player p, byte[] packet) {
|
||||
if (handlers.Count == 0) return;
|
||||
CallImpl(pl => pl(p, packet));
|
||||
CallCommon(pl => pl(p, packet));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ namespace MCGalaxy.Games {
|
||||
public int Points;
|
||||
|
||||
/// <summary> Players on this team. </summary>
|
||||
public VolatileArray<Player> Members = new VolatileArray<Player>(false);
|
||||
public VolatileArray<Player> Members = new VolatileArray<Player>();
|
||||
|
||||
|
||||
/// <summary> Position in the world the flag is located at. </summary>
|
||||
|
@ -24,10 +24,10 @@ namespace MCGalaxy.Games {
|
||||
public sealed class CountdownGame : IGame {
|
||||
|
||||
/// <summary> All players who are playing this countdown game. </summary>
|
||||
public VolatileArray<Player> Players = new VolatileArray<Player>(false);
|
||||
public VolatileArray<Player> Players = new VolatileArray<Player>();
|
||||
|
||||
/// <summary> Players who are still alive in the current round. </summary>
|
||||
public VolatileArray<Player> Remaining = new VolatileArray<Player>(false);
|
||||
public VolatileArray<Player> Remaining = new VolatileArray<Player>();
|
||||
|
||||
/// <summary> Map countdown is running on. </summary>
|
||||
public Level Map;
|
||||
|
@ -70,10 +70,10 @@ namespace MCGalaxy.Games {
|
||||
public Level CurLevel = null;
|
||||
|
||||
/// <summary> List of alive/human players. </summary>
|
||||
public VolatileArray<Player> Alive = new VolatileArray<Player>(false);
|
||||
public VolatileArray<Player> Alive = new VolatileArray<Player>();
|
||||
|
||||
/// <summary> List of dead/infected players. </summary>
|
||||
public VolatileArray<Player> Infected = new VolatileArray<Player>(false);
|
||||
public VolatileArray<Player> Infected = new VolatileArray<Player>();
|
||||
|
||||
public List<string> RecentMaps = new List<string>();
|
||||
|
||||
@ -92,10 +92,10 @@ namespace MCGalaxy.Games {
|
||||
int infectCombo = 0;
|
||||
|
||||
/// <summary> List of players who have a bounty on them. </summary>
|
||||
public VolatileArray<BountyData> Bounties = new VolatileArray<BountyData>(false);
|
||||
public VolatileArray<BountyData> Bounties = new VolatileArray<BountyData>();
|
||||
|
||||
/// <summary> List of players who are in the lottery. </summary>
|
||||
public VolatileArray<string> Lottery = new VolatileArray<string>(false);
|
||||
public VolatileArray<string> Lottery = new VolatileArray<string>();
|
||||
}
|
||||
|
||||
public static class ZSConfig {
|
||||
|
@ -140,7 +140,7 @@ namespace MCGalaxy {
|
||||
|
||||
public bool staticCommands = false;
|
||||
public DateTime ZoneSpam;
|
||||
public VolatileArray<SchedulerTask> CriticalTasks = new VolatileArray<SchedulerTask>(false);
|
||||
public VolatileArray<SchedulerTask> CriticalTasks = new VolatileArray<SchedulerTask>();
|
||||
|
||||
public bool aiming;
|
||||
public bool isFlying = false;
|
||||
@ -187,7 +187,7 @@ namespace MCGalaxy {
|
||||
public bool spawned = false;
|
||||
|
||||
//Undo
|
||||
internal VolatileArray<UndoDrawOpEntry> DrawOps = new VolatileArray<UndoDrawOpEntry>(false);
|
||||
internal VolatileArray<UndoDrawOpEntry> DrawOps = new VolatileArray<UndoDrawOpEntry>();
|
||||
internal readonly object pendingDrawOpsLock = new object();
|
||||
internal List<PendingDrawOp> PendingDrawOps = new List<PendingDrawOp>();
|
||||
|
||||
|
@ -36,7 +36,7 @@ namespace MCGalaxy {
|
||||
|
||||
readonly bool useList;
|
||||
|
||||
public VolatileArray(bool useList) {
|
||||
public VolatileArray(bool useList = false) {
|
||||
this.useList = useList;
|
||||
if (useList) list = new List<T>();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user