Creating PlayerMask
This commit is contained in:
@@ -33,6 +33,8 @@ namespace OpenRA
|
||||
|
||||
public enum WinState { Undefined, Won, Lost }
|
||||
|
||||
public class PlayerBitMask { }
|
||||
|
||||
public class Player : IScriptBindable, IScriptNotifyBind, ILuaTableBinding, ILuaEqualityBinding, ILuaToStringBinding
|
||||
{
|
||||
struct StanceColors
|
||||
@@ -71,6 +73,12 @@ namespace OpenRA
|
||||
readonly bool inMissionMap;
|
||||
readonly IUnlocksRenderPlayer[] unlockRenderPlayer;
|
||||
|
||||
// Each player is identified with a unique bit in the set
|
||||
// Cache masks for the player's index and ally/enemy player indices for performance.
|
||||
public LongBitSet<PlayerBitMask> PlayerMask;
|
||||
public LongBitSet<PlayerBitMask> AllyMask = default(LongBitSet<PlayerBitMask>);
|
||||
public LongBitSet<PlayerBitMask> EnemyMask = default(LongBitSet<PlayerBitMask>);
|
||||
|
||||
public bool UnlockedRenderPlayer
|
||||
{
|
||||
get
|
||||
@@ -153,6 +161,9 @@ namespace OpenRA
|
||||
DisplayFaction = ChooseDisplayFaction(world, pr.Faction);
|
||||
}
|
||||
|
||||
if (!Spectating)
|
||||
PlayerMask = new LongBitSet<PlayerBitMask>(InternalName);
|
||||
|
||||
var playerActorType = world.Type == WorldType.Editor ? "EditorPlayer" : "Player";
|
||||
PlayerActor = world.CreateActor(playerActorType, new TypeDictionary { new OwnerInit(this) });
|
||||
Shroud = PlayerActor.Trait<Shroud>();
|
||||
|
||||
194
OpenRA.Game/Primitives/LongBitSet.cs
Normal file
194
OpenRA.Game/Primitives/LongBitSet.cs
Normal file
@@ -0,0 +1,194 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Primitives
|
||||
{
|
||||
static class LongBitSetAllocator<T> where T : class
|
||||
{
|
||||
static readonly Cache<string, long> Bits = new Cache<string, long>(Allocate);
|
||||
static long nextBits = 1;
|
||||
|
||||
static long Allocate(string value)
|
||||
{
|
||||
lock (Bits)
|
||||
{
|
||||
var bits = nextBits;
|
||||
nextBits <<= 1;
|
||||
|
||||
if (nextBits == 0)
|
||||
throw new OverflowException("Trying to allocate bit index outside of index 64.");
|
||||
|
||||
return bits;
|
||||
}
|
||||
}
|
||||
|
||||
public static long GetBits(string[] values)
|
||||
{
|
||||
long bits = 0;
|
||||
lock (Bits)
|
||||
foreach (var value in values)
|
||||
bits |= Bits[value];
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
public static long GetBitsNoAlloc(string[] values)
|
||||
{
|
||||
// Map strings to existing bits; do not allocate missing values new bits
|
||||
long bits = 0;
|
||||
|
||||
lock (Bits)
|
||||
{
|
||||
foreach (var value in values)
|
||||
{
|
||||
long valueBit;
|
||||
if (Bits.TryGetValue(value, out valueBit))
|
||||
bits |= valueBit;
|
||||
}
|
||||
}
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetStrings(long bits)
|
||||
{
|
||||
var values = new List<string>();
|
||||
lock (Bits)
|
||||
foreach (var kvp in Bits)
|
||||
if ((kvp.Value & bits) != 0)
|
||||
values.Add(kvp.Key);
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
public static bool BitsContainString(long bits, string value)
|
||||
{
|
||||
long valueBit;
|
||||
lock (Bits)
|
||||
if (!Bits.TryGetValue(value, out valueBit))
|
||||
return false;
|
||||
return (bits & valueBit) != 0;
|
||||
}
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
lock (Bits)
|
||||
{
|
||||
Bits.Clear();
|
||||
nextBits = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Opitmized BitSet to be used only when guaranteed to be no more than 64 values.
|
||||
public struct LongBitSet<T> : IEnumerable<string>, IEquatable<LongBitSet<T>> where T : class
|
||||
{
|
||||
readonly long bits;
|
||||
|
||||
public LongBitSet(params string[] values)
|
||||
: this(LongBitSetAllocator<T>.GetBits(values)) { }
|
||||
|
||||
LongBitSet(long bits) { this.bits = bits; }
|
||||
|
||||
public static LongBitSet<T> FromStringsNoAlloc(string[] values)
|
||||
{
|
||||
return new LongBitSet<T>(LongBitSetAllocator<T>.GetBitsNoAlloc(values)) { };
|
||||
}
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
LongBitSetAllocator<T>.Reset();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return BitSetAllocator<T>.GetStrings(bits).JoinWith(",");
|
||||
}
|
||||
|
||||
public static bool operator ==(LongBitSet<T> me, LongBitSet<T> other) { return me.bits == other.bits; }
|
||||
public static bool operator !=(LongBitSet<T> me, LongBitSet<T> other) { return !(me == other); }
|
||||
|
||||
public bool Equals(LongBitSet<T> other) { return other == this; }
|
||||
public override bool Equals(object obj) { return obj is LongBitSet<T> && Equals((LongBitSet<T>)obj); }
|
||||
public override int GetHashCode() { return bits.GetHashCode(); }
|
||||
|
||||
public bool IsEmpty { get { return bits == 0; } }
|
||||
|
||||
public bool IsProperSubsetOf(LongBitSet<T> other)
|
||||
{
|
||||
return IsSubsetOf(other) && !SetEquals(other);
|
||||
}
|
||||
|
||||
public bool IsProperSupersetOf(LongBitSet<T> other)
|
||||
{
|
||||
return IsSupersetOf(other) && !SetEquals(other);
|
||||
}
|
||||
|
||||
public bool IsSubsetOf(LongBitSet<T> other)
|
||||
{
|
||||
return (bits | other.bits) == other.bits;
|
||||
}
|
||||
|
||||
public bool IsSupersetOf(LongBitSet<T> other)
|
||||
{
|
||||
return (bits | other.bits) == bits;
|
||||
}
|
||||
|
||||
public bool Overlaps(LongBitSet<T> other)
|
||||
{
|
||||
return (bits & other.bits) != 0;
|
||||
}
|
||||
|
||||
public bool SetEquals(LongBitSet<T> other)
|
||||
{
|
||||
return bits == other.bits;
|
||||
}
|
||||
|
||||
public bool Contains(string value)
|
||||
{
|
||||
return BitSetAllocator<T>.BitsContainString(bits, value);
|
||||
}
|
||||
|
||||
public IEnumerator<string> GetEnumerator()
|
||||
{
|
||||
return BitSetAllocator<T>.GetStrings(bits).GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public LongBitSet<T> Except(LongBitSet<T> other)
|
||||
{
|
||||
return new LongBitSet<T>(bits & ~other.bits);
|
||||
}
|
||||
|
||||
public LongBitSet<T> Intersect(LongBitSet<T> other)
|
||||
{
|
||||
return new LongBitSet<T>(bits & other.bits);
|
||||
}
|
||||
|
||||
public LongBitSet<T> SymmetricExcept(LongBitSet<T> other)
|
||||
{
|
||||
return new LongBitSet<T>(bits ^ other.bits);
|
||||
}
|
||||
|
||||
public LongBitSet<T> Union(LongBitSet<T> other)
|
||||
{
|
||||
return new LongBitSet<T>(bits | other.bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,7 @@ namespace OpenRA
|
||||
public readonly MersenneTwister SharedRandom;
|
||||
public readonly MersenneTwister LocalRandom;
|
||||
public readonly IModelCache ModelCache;
|
||||
public LongBitSet<PlayerBitMask> AllPlayerMask = default(LongBitSet<PlayerBitMask>);
|
||||
|
||||
public Player[] Players = new Player[0];
|
||||
|
||||
@@ -196,15 +197,27 @@ namespace OpenRA
|
||||
ScreenMap = WorldActor.Trait<ScreenMap>();
|
||||
Selection = WorldActor.Trait<ISelection>();
|
||||
|
||||
// Reset mask
|
||||
LongBitSet<PlayerBitMask>.Reset();
|
||||
|
||||
// Add players
|
||||
foreach (var cmp in WorldActor.TraitsImplementing<ICreatePlayers>())
|
||||
cmp.CreatePlayers(this);
|
||||
|
||||
// Set defaults for any unset stances
|
||||
foreach (var p in Players)
|
||||
{
|
||||
if (!p.Spectating)
|
||||
AllPlayerMask = AllPlayerMask.Union(p.PlayerMask);
|
||||
|
||||
foreach (var q in Players)
|
||||
{
|
||||
SetUpPlayerMask(p, q);
|
||||
|
||||
if (!p.Stances.ContainsKey(q))
|
||||
p.Stances[q] = Stance.Neutral;
|
||||
}
|
||||
}
|
||||
|
||||
Game.Sound.SoundVolumeModifier = 1.0f;
|
||||
|
||||
@@ -220,6 +233,25 @@ namespace OpenRA
|
||||
RulesContainTemporaryBlocker = map.Rules.Actors.Any(a => a.Value.HasTraitInfo<ITemporaryBlockerInfo>());
|
||||
}
|
||||
|
||||
void SetUpPlayerMask(Player p, Player q)
|
||||
{
|
||||
if (q.Spectating)
|
||||
return;
|
||||
|
||||
var bitSet = q.PlayerMask;
|
||||
|
||||
switch (p.Stances[q])
|
||||
{
|
||||
case Stance.Enemy:
|
||||
case Stance.Neutral:
|
||||
p.EnemyMask = p.EnemyMask.Union(bitSet);
|
||||
break;
|
||||
case Stance.Ally:
|
||||
p.AllyMask = p.AllyMask.Union(bitSet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddToMaps(Actor self, IOccupySpace ios)
|
||||
{
|
||||
ActorMap.AddInfluence(self, ios);
|
||||
|
||||
Reference in New Issue
Block a user