Merge pull request #4852 from pchote/timer-fixup

Overhaul ingame timer displays.
This commit is contained in:
Chris Forbes
2014-03-12 22:40:21 +13:00
21 changed files with 265 additions and 176 deletions

View File

@@ -73,7 +73,8 @@ namespace OpenRA
public static int RenderFrame = 0; public static int RenderFrame = 0;
public static int NetFrameNumber { get { return orderManager.NetFrameNumber; } } public static int NetFrameNumber { get { return orderManager.NetFrameNumber; } }
public static int LocalTick { get { return orderManager.LocalFrameNumber; } } public static int LocalTick { get { return orderManager.LocalFrameNumber; } }
public const int NetTickScale = 3; // 120ms net tick for 40ms local tick public const int NetTickScale = 3; // 120ms net tick for 40ms local tick
public const int Timestep = 40;
public static event Action<OrderManager> ConnectionStateChanged = _ => { }; public static event Action<OrderManager> ConnectionStateChanged = _ => { };
static ConnectionState lastConnectionState = ConnectionState.PreConnecting; static ConnectionState lastConnectionState = ConnectionState.PreConnecting;
@@ -224,6 +225,7 @@ namespace OpenRA
var map = modData.PrepareMap(mapUID); var map = modData.PrepareMap(mapUID);
orderManager.world = new World(modData.Manifest, map, orderManager, isShellmap); orderManager.world = new World(modData.Manifest, map, orderManager, isShellmap);
orderManager.world.Timestep = Timestep;
worldRenderer = new WorldRenderer(orderManager.world); worldRenderer = new WorldRenderer(orderManager.world);
orderManager.world.LoadComplete(worldRenderer); orderManager.world.LoadComplete(worldRenderer);

View File

@@ -200,7 +200,6 @@
<Compile Include="Widgets\ShpImageWidget.cs" /> <Compile Include="Widgets\ShpImageWidget.cs" />
<Compile Include="Widgets\SliderWidget.cs" /> <Compile Include="Widgets\SliderWidget.cs" />
<Compile Include="Widgets\TextFieldWidget.cs" /> <Compile Include="Widgets\TextFieldWidget.cs" />
<Compile Include="Widgets\TimerWidget.cs" />
<Compile Include="Widgets\VqaPlayerWidget.cs" /> <Compile Include="Widgets\VqaPlayerWidget.cs" />
<Compile Include="Widgets\Widget.cs" /> <Compile Include="Widgets\Widget.cs" />
<Compile Include="Widgets\WidgetLoader.cs" /> <Compile Include="Widgets\WidgetLoader.cs" />

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information #region Copyright & License Information
/* /*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -37,8 +37,8 @@ namespace OpenRA
if (filename.ToLowerInvariant().EndsWith("wav")) if (filename.ToLowerInvariant().EndsWith("wav"))
return LoadWave(new WavLoader(FileSystem.Open(filename))); return LoadWave(new WavLoader(FileSystem.Open(filename)));
else
return LoadSoundRaw(AudLoader.LoadSound(FileSystem.Open(filename))); return LoadSoundRaw(AudLoader.LoadSound(FileSystem.Open(filename)));
} }
static ISoundSource LoadWave(WavLoader wave) static ISoundSource LoadWave(WavLoader wave)
@@ -55,12 +55,12 @@ namespace OpenRA
{ {
engine = Game.Settings.Server.Dedicated ? "Null" : engine; engine = Game.Settings.Server.Dedicated ? "Null" : engine;
switch (engine) switch (engine)
{ /* TODO: if someone cares about pluggable crap here, ship this out */ {
case "AL": return new OpenAlSoundEngine(); case "AL": return new OpenAlSoundEngine();
case "Null": return new NullSoundEngine(); case "Null": return new NullSoundEngine();
default: default:
throw new InvalidOperationException("Unsupported sound engine: {0}".F (engine)); throw new InvalidOperationException("Unsupported sound engine: {0}".F(engine));
} }
} }
@@ -79,23 +79,26 @@ namespace OpenRA
public static SoundDevice[] AvailableDevices() public static SoundDevice[] AvailableDevices()
{ {
var defaultDevices = new [] var defaultDevices = new[]
{ {
new SoundDevice("AL", null, "Default Output"), new SoundDevice("AL", null, "Default Output"),
new SoundDevice("Null", null, "Output Disabled") new SoundDevice("Null", null, "Output Disabled")
}; };
var alDevices = OpenAlSoundEngine.AvailableDevices() var devices = OpenAlSoundEngine.AvailableDevices()
.Select(d => new SoundDevice("AL", d, d)); .Select(d => new SoundDevice("AL", d, d));
return defaultDevices.Concat(alDevices).ToArray(); return defaultDevices.Concat(devices).ToArray();
} }
public static void SetListenerPosition(WPos position) { soundEngine.SetListenerPosition(position); } public static void SetListenerPosition(WPos position)
{
soundEngine.SetListenerPosition(position);
}
static ISound Play(Player player, string name, bool headRelative, WPos pos, float volumeModifier) static ISound Play(Player player, string name, bool headRelative, WPos pos, float volumeModifier)
{ {
if (String.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
return null; return null;
if (player != null && player != player.World.LocalPlayer) if (player != null && player != player.World.LocalPlayer)
return null; return null;
@@ -142,11 +145,11 @@ namespace OpenRA
if (MusicPlaying && !music.Playing) if (MusicPlaying && !music.Playing)
{ {
StopMusic(); StopMusic();
OnMusicComplete(); onMusicComplete();
} }
} }
static Action OnMusicComplete; static Action onMusicComplete;
public static bool MusicPlaying { get; private set; } public static bool MusicPlaying { get; private set; }
public static MusicInfo CurrentMusic { get { return currentMusic; } } public static MusicInfo CurrentMusic { get { return currentMusic; } }
@@ -160,7 +163,7 @@ namespace OpenRA
if (m == null || !m.Exists) if (m == null || !m.Exists)
return; return;
OnMusicComplete = then; onMusicComplete = then;
if (m == currentMusic && music != null) if (m == currentMusic && music != null)
{ {
@@ -168,6 +171,7 @@ namespace OpenRA
MusicPlaying = true; MusicPlaying = true;
return; return;
} }
StopMusic(); StopMusic();
var sound = sounds[m.Filename]; var sound = sounds[m.Filename];
@@ -183,6 +187,7 @@ namespace OpenRA
{ {
if (music == null) if (music == null)
return; return;
MusicPlaying = true; MusicPlaying = true;
soundEngine.PauseSound(music, false); soundEngine.PauseSound(music, false);
} }
@@ -220,7 +225,11 @@ namespace OpenRA
static float soundVolumeModifier = 1.0f; static float soundVolumeModifier = 1.0f;
public static float SoundVolumeModifier public static float SoundVolumeModifier
{ {
get { return soundVolumeModifier; } get
{
return soundVolumeModifier;
}
set set
{ {
soundVolumeModifier = value; soundVolumeModifier = value;
@@ -231,7 +240,11 @@ namespace OpenRA
static float InternalSoundVolume { get { return SoundVolume * soundVolumeModifier; } } static float InternalSoundVolume { get { return SoundVolume * soundVolumeModifier; } }
public static float SoundVolume public static float SoundVolume
{ {
get { return Game.Settings.Sound.SoundVolume; } get
{
return Game.Settings.Sound.SoundVolume;
}
set set
{ {
Game.Settings.Sound.SoundVolume = value; Game.Settings.Sound.SoundVolume = value;
@@ -241,7 +254,11 @@ namespace OpenRA
public static float MusicVolume public static float MusicVolume
{ {
get { return Game.Settings.Sound.MusicVolume; } get
{
return Game.Settings.Sound.MusicVolume;
}
set set
{ {
Game.Settings.Sound.MusicVolume = value; Game.Settings.Sound.MusicVolume = value;
@@ -252,7 +269,11 @@ namespace OpenRA
public static float VideoVolume public static float VideoVolume
{ {
get { return Game.Settings.Sound.VideoVolume; } get
{
return Game.Settings.Sound.VideoVolume;
}
set set
{ {
Game.Settings.Sound.VideoVolume = value; Game.Settings.Sound.VideoVolume = value;
@@ -263,25 +284,28 @@ namespace OpenRA
public static float MusicSeekPosition public static float MusicSeekPosition
{ {
get { return (music != null) ? music.SeekPosition : 0; } get { return music != null ? music.SeekPosition : 0; }
} }
public static float VideoSeekPosition public static float VideoSeekPosition
{ {
get { return (video != null) ? video.SeekPosition : 0; } get { return video != null ? video.SeekPosition : 0; }
} }
// Returns true if played successfully // Returns true if played successfully
public static bool PlayPredefined(Player p, Actor voicedUnit, string type, string definition, string variant, bool attenuateVolume) public static bool PlayPredefined(Player p, Actor voicedUnit, string type, string definition, string variant, bool attenuateVolume)
{ {
if (definition == null) return false; if (definition == null)
return false;
if (Rules.Voices == null || Rules.Notifications == null)
return false;
if (Rules.Voices == null) return false;
if (Rules.Notifications == null) return false;
var rules = (voicedUnit != null) ? Rules.Voices[type] : Rules.Notifications[type]; var rules = (voicedUnit != null) ? Rules.Voices[type] : Rules.Notifications[type];
if (rules == null) return false; if (rules == null)
return false;
var ID = (voicedUnit != null) ? voicedUnit.ActorID : 0; var id = voicedUnit != null ? voicedUnit.ActorID : 0;
string clip; string clip;
var suffix = rules.DefaultVariant; var suffix = rules.DefaultVariant;
@@ -308,19 +332,20 @@ namespace OpenRA
clip = rules.NotificationsPools.Value[definition].GetNext(); clip = rules.NotificationsPools.Value[definition].GetNext();
} }
if (String.IsNullOrEmpty(clip)) return false; if (string.IsNullOrEmpty(clip))
return false;
if (variant != null) if (variant != null)
{ {
if (rules.Variants.ContainsKey(variant) && !rules.DisableVariants.Contains(definition)) if (rules.Variants.ContainsKey(variant) && !rules.DisableVariants.Contains(definition))
suffix = rules.Variants[variant][ID % rules.Variants[variant].Length]; suffix = rules.Variants[variant][id % rules.Variants[variant].Length];
if (rules.Prefixes.ContainsKey(variant) && !rules.DisablePrefixes.Contains(definition)) if (rules.Prefixes.ContainsKey(variant) && !rules.DisablePrefixes.Contains(definition))
prefix = rules.Prefixes[variant][ID % rules.Prefixes[variant].Length]; prefix = rules.Prefixes[variant][id % rules.Prefixes[variant].Length];
} }
var name = prefix + clip + suffix; var name = prefix + clip + suffix;
if (!String.IsNullOrEmpty(name) && (p == null || p == p.World.LocalPlayer)) if (!string.IsNullOrEmpty(name) && (p == null || p == p.World.LocalPlayer))
soundEngine.Play2D(sounds[name], soundEngine.Play2D(sounds[name],
false, true, WPos.Zero, false, true, WPos.Zero,
InternalSoundVolume, attenuateVolume); InternalSoundVolume, attenuateVolume);
@@ -330,22 +355,21 @@ namespace OpenRA
public static bool PlayVoice(string phrase, Actor voicedUnit, string variant) public static bool PlayVoice(string phrase, Actor voicedUnit, string variant)
{ {
if (voicedUnit == null) return false; if (voicedUnit == null || phrase == null)
if (phrase == null) return false; return false;
var mi = voicedUnit.Info.Traits.GetOrDefault<SelectableInfo>(); var mi = voicedUnit.Info.Traits.GetOrDefault<SelectableInfo>();
if (mi == null) return false; if (mi == null || mi.Voice == null)
if (mi.Voice == null) return false; return false;
var type = mi.Voice.ToLowerInvariant(); var type = mi.Voice.ToLowerInvariant();
return PlayPredefined(null, voicedUnit, type, phrase, variant, true); return PlayPredefined(null, voicedUnit, type, phrase, variant, true);
} }
public static bool PlayNotification(Player player, string type, string notification, string variant) public static bool PlayNotification(Player player, string type, string notification, string variant)
{ {
if (type == null) return false; if (type == null || notification == null)
if (notification == null) return false; return false;
return PlayPredefined(player, null, type.ToLowerInvariant(), notification, variant, false); return PlayPredefined(player, null, type.ToLowerInvariant(), notification, variant, false);
} }
@@ -395,16 +419,20 @@ namespace OpenRA
{ {
class PoolSlot class PoolSlot
{ {
public bool isActive; public bool IsActive;
public int frameStarted; public int FrameStarted;
public WPos pos; public WPos Pos;
public bool isRelative; public bool IsRelative;
public ISoundSource sound; public ISoundSource Sound;
} }
const int MaxInstancesPerFrame = 3;
const int GroupDistance = 2730;
const int GroupDistanceSqr = GroupDistance * GroupDistance;
const int PoolSize = 32;
float volume = 1f; float volume = 1f;
Dictionary<int, PoolSlot> sourcePool = new Dictionary<int, PoolSlot>(); Dictionary<int, PoolSlot> sourcePool = new Dictionary<int, PoolSlot>();
const int POOL_SIZE = 32;
static string[] QueryDevices(string label, int type) static string[] QueryDevices(string label, int type)
{ {
@@ -415,7 +443,7 @@ namespace OpenRA
if (Al.alGetError() != Al.AL_NO_ERROR) if (Al.alGetError() != Al.AL_NO_ERROR)
{ {
Log.Write("sound", "Failed to query OpenAL device list using {0}", label); Log.Write("sound", "Failed to query OpenAL device list using {0}", label);
return new string[] {}; return new string[] { };
} }
return devices; return devices;
@@ -430,7 +458,7 @@ namespace OpenRA
if (Alc.alcIsExtensionPresent(IntPtr.Zero, "ALC_ENUMERATION_EXT") == Alc.ALC_TRUE) if (Alc.alcIsExtensionPresent(IntPtr.Zero, "ALC_ENUMERATION_EXT") == Alc.ALC_TRUE)
return QueryDevices("ALC_ENUMERATION_EXT", Alc.ALC_DEVICE_SPECIFIER); return QueryDevices("ALC_ENUMERATION_EXT", Alc.ALC_DEVICE_SPECIFIER);
return new string[] {}; return new string[] { };
} }
public OpenAlSoundEngine() public OpenAlSoundEngine()
@@ -456,7 +484,7 @@ namespace OpenRA
throw new InvalidOperationException("Can't create OpenAL context"); throw new InvalidOperationException("Can't create OpenAL context");
Alc.alcMakeContextCurrent(ctx); Alc.alcMakeContextCurrent(ctx);
for (var i = 0; i < POOL_SIZE; i++) for (var i = 0; i < PoolSize; i++)
{ {
var source = 0; var source = 0;
Al.alGenSources(1, out source); Al.alGenSources(1, out source);
@@ -466,7 +494,7 @@ namespace OpenRA
return; return;
} }
sourcePool.Add(source, new PoolSlot() { isActive = false }); sourcePool.Add(source, new PoolSlot() { IsActive = false });
} }
} }
@@ -474,9 +502,9 @@ namespace OpenRA
{ {
foreach (var kvp in sourcePool) foreach (var kvp in sourcePool)
{ {
if (!kvp.Value.isActive) if (!kvp.Value.IsActive)
{ {
sourcePool[kvp.Key].isActive = true; sourcePool[kvp.Key].IsActive = true;
return kvp.Key; return kvp.Key;
} }
} }
@@ -494,9 +522,9 @@ namespace OpenRA
return -1; return -1;
foreach (int i in freeSources) foreach (int i in freeSources)
sourcePool[i].isActive = false; sourcePool[i].IsActive = false;
sourcePool[freeSources[0]].isActive = true; sourcePool[freeSources[0]].IsActive = true;
return freeSources[0]; return freeSources[0];
} }
@@ -506,10 +534,6 @@ namespace OpenRA
return new OpenAlSoundSource(data, channels, sampleBits, sampleRate); return new OpenAlSoundSource(data, channels, sampleBits, sampleRate);
} }
const int maxInstancesPerFrame = 3;
const int groupDistance = 2730;
const int groupDistanceSqr = groupDistance * groupDistance;
public ISound Play2D(ISoundSource sound, bool loop, bool relative, WPos pos, float volume, bool attenuateVolume) public ISound Play2D(ISoundSource sound, bool loop, bool relative, WPos pos, float volume, bool attenuateVolume)
{ {
if (sound == null) if (sound == null)
@@ -518,9 +542,8 @@ namespace OpenRA
return null; return null;
} }
var world = Game.orderManager.world; var currFrame = Game.orderManager.LocalFrameNumber;
int currFrame = world != null ? world.FrameNumber : 0; var atten = 1f;
float atten = 1f;
// Check if max # of instances-per-location reached: // Check if max # of instances-per-location reached:
if (attenuateVolume) if (attenuateVolume)
@@ -528,40 +551,41 @@ namespace OpenRA
int instances = 0, activeCount = 0; int instances = 0, activeCount = 0;
foreach (var s in sourcePool.Values) foreach (var s in sourcePool.Values)
{ {
if (!s.isActive) if (!s.IsActive)
continue; continue;
if (s.isRelative != relative) if (s.IsRelative != relative)
continue; continue;
++activeCount; ++activeCount;
if (s.sound != sound) if (s.Sound != sound)
continue; continue;
if (currFrame - s.frameStarted >= 5) if (currFrame - s.FrameStarted >= 5)
continue; continue;
// Too far away to count? // Too far away to count?
var lensqr = (s.pos - pos).LengthSquared; var lensqr = (s.Pos - pos).LengthSquared;
if (lensqr >= groupDistanceSqr) if (lensqr >= GroupDistanceSqr)
continue; continue;
// If we are starting too many instances of the same sound within a short time then stop this one: // If we are starting too many instances of the same sound within a short time then stop this one:
if (++instances == maxInstancesPerFrame) if (++instances == MaxInstancesPerFrame)
return null; return null;
} }
// Attenuate a little bit based on number of active sounds: // Attenuate a little bit based on number of active sounds:
atten = 0.66f * ((POOL_SIZE - activeCount * 0.5f) / POOL_SIZE); atten = 0.66f * ((PoolSize - activeCount * 0.5f) / PoolSize);
} }
int source = GetSourceFromPool(); var source = GetSourceFromPool();
if (source == -1) return null; if (source == -1)
return null;
var slot = sourcePool[source]; var slot = sourcePool[source];
slot.pos = pos; slot.Pos = pos;
slot.frameStarted = currFrame; slot.FrameStarted = currFrame;
slot.sound = sound; slot.Sound = sound;
slot.isRelative = relative; slot.IsRelative = relative;
return new OpenAlSound(source, (sound as OpenAlSoundSource).buffer, loop, relative, pos, volume * atten); return new OpenAlSound(source, (sound as OpenAlSoundSource).Buffer, loop, relative, pos, volume * atten);
} }
public float Volume public float Volume
@@ -575,7 +599,7 @@ namespace OpenRA
if (sound == null) if (sound == null)
return; return;
int key = ((OpenAlSound)sound).source; var key = ((OpenAlSound)sound).Source;
int state; int state;
Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state); Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state);
if (state == Al.AL_PLAYING && paused) if (state == Al.AL_PLAYING && paused)
@@ -586,7 +610,7 @@ namespace OpenRA
public void SetAllSoundsPaused(bool paused) public void SetAllSoundsPaused(bool paused)
{ {
foreach (int key in sourcePool.Keys) foreach (var key in sourcePool.Keys)
{ {
int state; int state;
Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state); Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state);
@@ -603,21 +627,21 @@ namespace OpenRA
{ {
int state; int state;
Al.alGetSourcei(b, Al.AL_SOURCE_STATE, out state); Al.alGetSourcei(b, Al.AL_SOURCE_STATE, out state);
return ((state == Al.AL_PLAYING || state == Al.AL_PAUSED) && return (state == Al.AL_PLAYING || state == Al.AL_PAUSED) &&
((music == null) || b != ((OpenAlSound)music).source) && (music == null || b != ((OpenAlSound)music).Source) &&
((video == null) || b != ((OpenAlSound)video).source)); (video == null || b != ((OpenAlSound)video).Source);
}).ToList(); });
foreach (var s in sounds) foreach (var s in sounds)
{
Al.alSourcef(s, Al.AL_GAIN, volume); Al.alSourcef(s, Al.AL_GAIN, volume);
}
} }
public void StopSound(ISound sound) public void StopSound(ISound sound)
{ {
if (sound == null) return; if (sound == null)
return;
int key = ((OpenAlSound)sound).source; var key = ((OpenAlSound)sound).Source;
int state; int state;
Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state); Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state);
if (state == Al.AL_PLAYING || state == Al.AL_PAUSED) if (state == Al.AL_PLAYING || state == Al.AL_PAUSED)
@@ -626,7 +650,7 @@ namespace OpenRA
public void StopAllSounds() public void StopAllSounds()
{ {
foreach (int key in sourcePool.Keys) foreach (var key in sourcePool.Keys)
{ {
int state; int state;
Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state); Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state);
@@ -648,7 +672,7 @@ namespace OpenRA
class OpenAlSoundSource : ISoundSource class OpenAlSoundSource : ISoundSource
{ {
public readonly int buffer; public readonly int Buffer;
static int MakeALFormat(int channels, int bits) static int MakeALFormat(int channels, int bits)
{ {
@@ -660,22 +684,25 @@ namespace OpenRA
public OpenAlSoundSource(byte[] data, int channels, int sampleBits, int sampleRate) public OpenAlSoundSource(byte[] data, int channels, int sampleBits, int sampleRate)
{ {
Al.alGenBuffers(1, out buffer); Al.alGenBuffers(1, out Buffer);
Al.alBufferData(buffer, MakeALFormat(channels, sampleBits), data, data.Length, sampleRate); Al.alBufferData(Buffer, MakeALFormat(channels, sampleBits), data, data.Length, sampleRate);
} }
} }
class OpenAlSound : ISound class OpenAlSound : ISound
{ {
public readonly int source = -1; public readonly int Source = -1;
float volume = 1f; float volume = 1f;
public OpenAlSound(int source, int buffer, bool looping, bool relative, WPos pos, float volume) public OpenAlSound(int source, int buffer, bool looping, bool relative, WPos pos, float volume)
{ {
if (source == -1) return; if (source == -1)
this.source = source; return;
Al.alSourcef(source, Al.AL_PITCH, 1f);
Source = source;
Volume = volume; Volume = volume;
Al.alSourcef(source, Al.AL_PITCH, 1f);
Al.alSource3f(source, Al.AL_POSITION, pos.X, pos.Y, pos.Z); Al.alSource3f(source, Al.AL_POSITION, pos.X, pos.Y, pos.Z);
Al.alSource3f(source, Al.AL_VELOCITY, 0f, 0f, 0f); Al.alSource3f(source, Al.AL_VELOCITY, 0f, 0f, 0f);
Al.alSourcei(source, Al.AL_BUFFER, buffer); Al.alSourcei(source, Al.AL_BUFFER, buffer);
@@ -689,11 +716,15 @@ namespace OpenRA
public float Volume public float Volume
{ {
get { return volume; } get
{
return volume;
}
set set
{ {
if (source != -1) if (Source != -1)
Al.alSourcef(source, Al.AL_GAIN, volume = value); Al.alSourcef(Source, Al.AL_GAIN, volume = value);
} }
} }
@@ -702,7 +733,7 @@ namespace OpenRA
get get
{ {
float pos; float pos;
Al.alGetSourcef(source, Al.AL_SAMPLE_OFFSET, out pos); Al.alGetSourcef(Source, Al.AL_SAMPLE_OFFSET, out pos);
return pos / 22050f; return pos / 22050f;
} }
} }
@@ -712,7 +743,7 @@ namespace OpenRA
get get
{ {
int state; int state;
Al.alGetSourcei(source, Al.AL_SOURCE_STATE, out state); Al.alGetSourcei(Source, Al.AL_SOURCE_STATE, out state);
return state == Al.AL_PLAYING; return state == Al.AL_PLAYING;
} }
} }
@@ -735,17 +766,17 @@ namespace OpenRA
return new NullSound(); return new NullSound();
} }
public void PauseSound(ISound sound, bool paused) {} public void PauseSound(ISound sound, bool paused) { }
public void StopSound(ISound sound) {} public void StopSound(ISound sound) { }
public void SetAllSoundsPaused(bool paused) {} public void SetAllSoundsPaused(bool paused) { }
public void StopAllSounds() {} public void StopAllSounds() { }
public void SetListenerPosition(WPos position) {} public void SetListenerPosition(WPos position) { }
public void SetSoundVolume(float volume, ISound music, ISound video) {} public void SetSoundVolume(float volume, ISound music, ISound video) { }
public float Volume { get; set; } public float Volume { get; set; }
} }
class NullSoundSource : ISoundSource {} class NullSoundSource : ISoundSource { }
class NullSound : ISound class NullSound : ISound
{ {

View File

@@ -61,7 +61,7 @@ namespace OpenRA.Traits
void Invalidate() void Invalidate()
{ {
Hash = Sync.hash_player(self.Owner) + self.World.FrameNumber * 3; Hash = Sync.hash_player(self.Owner) + self.World.WorldTick * 3;
} }
static IEnumerable<CPos> FindVisibleTiles(World world, CPos position, WRange radius) static IEnumerable<CPos> FindVisibleTiles(World world, CPos position, WRange radius)

View File

@@ -1,36 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2013 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. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Drawing;
using OpenRA.FileFormats;
using OpenRA.Graphics;
namespace OpenRA.Widgets
{
public class TimerWidget : LabelWidget
{
public override void Draw()
{
var font = Game.Renderer.Fonts[Font];
var rb = RenderBounds;
var color = GetColor();
var contrast = GetContrastColor();
var s = WidgetUtils.FormatTime(Game.LocalTick) + (Game.orderManager.world.Paused?" (paused)":"");
var pos = new float2(rb.Left - font.Measure(s).X / 2, rb.Top);
if (Contrast)
font.DrawTextWithContrast(s, pos, color, contrast, 1);
else
font.DrawText(s, pos, color);
}
}
}

View File

@@ -30,7 +30,7 @@ namespace OpenRA
List<IEffect> effects = new List<IEffect>(); List<IEffect> effects = new List<IEffect>();
Queue<Action<World>> frameEndActions = new Queue<Action<World>>(); Queue<Action<World>> frameEndActions = new Queue<Action<World>>();
public int FrameNumber { get { return orderManager.LocalFrameNumber; } } public int Timestep;
internal readonly OrderManager orderManager; internal readonly OrderManager orderManager;
public Session LobbyInfo { get { return orderManager.LobbyInfo; } } public Session LobbyInfo { get { return orderManager.LobbyInfo; } }
@@ -190,6 +190,7 @@ namespace OpenRA
public bool PredictedPaused { get; internal set; } public bool PredictedPaused { get; internal set; }
public bool PauseStateLocked { get; set; } public bool PauseStateLocked { get; set; }
public bool IsShellmap = false; public bool IsShellmap = false;
public int WorldTick { get; private set; }
public void SetPauseState(bool paused) public void SetPauseState(bool paused)
{ {
@@ -209,6 +210,8 @@ namespace OpenRA
{ {
if (!Paused && (!IsShellmap || Game.Settings.Game.ShowShellmap)) if (!Paused && (!IsShellmap || Game.Settings.Game.ShowShellmap))
{ {
WorldTick++;
using (new PerfSample("tick_idle")) using (new PerfSample("tick_idle"))
foreach (var ni in ActorsWithTrait<INotifyIdle>()) foreach (var ni in ActorsWithTrait<INotifyIdle>())
if (ni.Actor.IsIdle) if (ni.Actor.IsIdle)

View File

@@ -21,7 +21,7 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
{ {
var shellmapDecorations = widget.Get("SHELLMAP_DECORATIONS"); var shellmapDecorations = widget.Get("SHELLMAP_DECORATIONS");
shellmapDecorations.IsVisible = () => menuType != MenuType.None && Game.Settings.Game.ShowShellmap; shellmapDecorations.IsVisible = () => menuType != MenuType.None && Game.Settings.Game.ShowShellmap;
shellmapDecorations.Get<ImageWidget>("RECBLOCK").IsVisible = () => world.FrameNumber / 25 % 2 == 0; shellmapDecorations.Get<ImageWidget>("RECBLOCK").IsVisible = () => world.WorldTick / 25 % 2 == 0;
var shellmapDisabledDecorations = widget.Get("SHELLMAP_DISABLED_DECORATIONS"); var shellmapDisabledDecorations = widget.Get("SHELLMAP_DISABLED_DECORATIONS");
shellmapDisabledDecorations.IsVisible = () => !Game.Settings.Game.ShowShellmap; shellmapDisabledDecorations.IsVisible = () => !Game.Settings.Game.ShowShellmap;

View File

@@ -34,10 +34,10 @@ namespace OpenRA.Mods.RA.Activities
{ {
// Maybe we lost the owner-linked refinery: // Maybe we lost the owner-linked refinery:
harv.OwnerLinkedProc = null; harv.OwnerLinkedProc = null;
if (self.World.FrameNumber - chosenTicks > NextChooseTime) if (self.World.WorldTick - chosenTicks > NextChooseTime)
{ {
harv.ChooseNewProc(self, null); harv.ChooseNewProc(self, null);
chosenTicks = self.World.FrameNumber; chosenTicks = self.World.WorldTick;
} }
} }
else else

View File

@@ -49,8 +49,8 @@ namespace OpenRA.Mods.RA.Move
var cached = CachedPaths.FirstOrDefault(p => p.from == from && p.to == target && p.actor == self); var cached = CachedPaths.FirstOrDefault(p => p.from == from && p.to == target && p.actor == self);
if (cached != null) if (cached != null)
{ {
Log.Write("debug", "Actor {0} asked for a path from {1} tick(s) ago", self.ActorID, world.FrameNumber - cached.tick); Log.Write("debug", "Actor {0} asked for a path from {1} tick(s) ago", self.ActorID, world.WorldTick - cached.tick);
if (world.FrameNumber - cached.tick > MaxPathAge) if (world.WorldTick - cached.tick > MaxPathAge)
CachedPaths.Remove(cached); CachedPaths.Remove(cached);
return new List<CPos>(cached.result); return new List<CPos>(cached.result);
} }
@@ -73,8 +73,8 @@ namespace OpenRA.Mods.RA.Move
CheckSanePath2(pb, from, target); CheckSanePath2(pb, from, target);
CachedPaths.RemoveAll(p => world.FrameNumber - p.tick > MaxPathAge); CachedPaths.RemoveAll(p => world.WorldTick - p.tick > MaxPathAge);
CachedPaths.Add(new CachedPath { from = from, to = target, actor = self, result = pb, tick = world.FrameNumber }); CachedPaths.Add(new CachedPath { from = from, to = target, actor = self, result = pb, tick = world.WorldTick });
return new List<CPos>(pb); return new List<CPos>(pb);
} }
} }

View File

@@ -479,6 +479,8 @@
<Compile Include="Widgets\Logic\DisconnectWatcherLogic.cs" /> <Compile Include="Widgets\Logic\DisconnectWatcherLogic.cs" />
<Compile Include="Activities\FlyFollow.cs" /> <Compile Include="Activities\FlyFollow.cs" />
<Compile Include="Modifiers\DisabledOverlay.cs" /> <Compile Include="Modifiers\DisabledOverlay.cs" />
<Compile Include="Widgets\Logic\ReplayControlBarLogic.cs" />
<Compile Include="Widgets\Logic\GameTimerLogic.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj"> <ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">

View File

@@ -52,7 +52,7 @@ namespace OpenRA.Mods.RA
if (e.Attacker.Owner.IsAlliedWith(self.Owner) && e.Damage <= 0) if (e.Attacker.Owner.IsAlliedWith(self.Owner) && e.Damage <= 0)
return; return;
if (self.World.FrameNumber - lastAttackTime > info.NotifyInterval * 25) if (self.World.WorldTick - lastAttackTime > info.NotifyInterval * 25)
{ {
Sound.PlayNotification(self.Owner, "Speech", "BaseAttack", self.Owner.Country.Race); Sound.PlayNotification(self.Owner, "Speech", "BaseAttack", self.Owner.Country.Race);
@@ -60,7 +60,7 @@ namespace OpenRA.Mods.RA
radarPings.Add(() => self.Owner == self.World.LocalPlayer, self.CenterPosition, info.RadarPingColor, info.RadarPingDuration); radarPings.Add(() => self.Owner == self.World.LocalPlayer, self.CenterPosition, info.RadarPingColor, info.RadarPingDuration);
} }
lastAttackTime = self.World.FrameNumber; lastAttackTime = self.World.WorldTick;
} }
} }
} }

View File

@@ -46,7 +46,7 @@ namespace OpenRA.Mods.RA
if (e.Attacker != null && e.Attacker.Owner == self.Owner) if (e.Attacker != null && e.Attacker.Owner == self.Owner)
return; return;
if (self.World.FrameNumber - lastAttackTime > info.NotifyInterval * 25) if (self.World.WorldTick - lastAttackTime > info.NotifyInterval * 25)
{ {
Sound.PlayNotification(self.Owner, "Speech", "HarvesterAttack", self.Owner.Country.Race); Sound.PlayNotification(self.Owner, "Speech", "HarvesterAttack", self.Owner.Country.Race);
@@ -54,7 +54,7 @@ namespace OpenRA.Mods.RA
radarPings.Add(() => self.Owner == self.World.LocalPlayer, self.CenterPosition, info.RadarPingColor, info.RadarPingDuration); radarPings.Add(() => self.Owner == self.World.LocalPlayer, self.CenterPosition, info.RadarPingColor, info.RadarPingDuration);
} }
lastAttackTime = self.World.FrameNumber; lastAttackTime = self.World.WorldTick;
} }
} }
} }

View File

@@ -73,9 +73,9 @@ namespace OpenRA.Mods.RA
public void Tick(Actor self) public void Tick(Actor self)
{ {
if (self.World.FrameNumber % 1500 == 1) if (self.World.WorldTick % 1500 == 1)
UpdateEarnedThisMinute(); UpdateEarnedThisMinute();
if (self.World.FrameNumber % 250 == 0) if (self.World.WorldTick % 250 == 0)
UpdateMapControl(); UpdateMapControl();
} }

View File

@@ -40,14 +40,14 @@ namespace OpenRA.Mods.RA
{ {
if (!Panicking) if (!Panicking)
Self.CancelActivity(); Self.CancelActivity();
PanicStartedTick = Self.World.FrameNumber; PanicStartedTick = Self.World.WorldTick;
} }
public void Tick(Actor self) public void Tick(Actor self)
{ {
if (!Panicking) return; if (!Panicking) return;
if (self.World.FrameNumber >= PanicStartedTick + Info.PanicLength) if (self.World.WorldTick >= PanicStartedTick + Info.PanicLength)
{ {
self.CancelActivity(); self.CancelActivity();
PanicStartedTick = 0; PanicStartedTick = 0;

View File

@@ -0,0 +1,46 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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. For more information,
* see COPYING.
*/
#endregion
using System;
using OpenRA.Network;
using OpenRA.Widgets;
namespace OpenRA.Mods.RA.Widgets.Logic
{
public class GameTimerLogic
{
[ObjectCreator.UseCtor]
public GameTimerLogic(Widget widget, OrderManager orderManager, World world)
{
var timer = widget.GetOrNull<LabelWidget>("GAME_TIMER");
if (timer != null)
timer.GetText = () => WidgetUtils.FormatTime(world.WorldTick);
var status = widget.GetOrNull<LabelWidget>("GAME_TIMER_STATUS");
if (status != null)
{
// Blink the status line
status.IsVisible = () => (world.Paused || world.Timestep != Game.Timestep)
&& orderManager.LocalFrameNumber / 25 % 2 == 0;
status.GetText = () =>
{
if (world.Paused || world.Timestep == 0)
return "Paused";
if (world.Timestep == 1)
return "Max Speed";
return "{0:F1}x Speed".F(Game.Timestep * 1f / world.Timestep);
};
}
}
}
}

View File

@@ -291,7 +291,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
{ {
statusCheckbox.IsHighlighted = () => !statusCheckbox.IsChecked() && statusCheckbox.IsHighlighted = () => !statusCheckbox.IsChecked() &&
orderManager.LobbyInfo.FirstEmptySlot() == null && orderManager.LobbyInfo.FirstEmptySlot() == null &&
world.FrameNumber / 25 % 2 == 0; orderManager.LocalFrameNumber / 25 % 2 == 0;
} }
// Options panel // Options panel

View File

@@ -285,12 +285,12 @@ namespace OpenRA.Mods.RA.Widgets.Logic
string AverageOrdersPerMinute(double orders) string AverageOrdersPerMinute(double orders)
{ {
return (world.FrameNumber == 0 ? 0 : orders / (world.FrameNumber / 1500.0)).ToString("F1"); return (world.WorldTick == 0 ? 0 : orders / (world.WorldTick / 1500.0)).ToString("F1");
} }
string AverageEarnedPerMinute(double earned) string AverageEarnedPerMinute(double earned)
{ {
return "$" + (world.FrameNumber == 0 ? 0 : earned / (world.FrameNumber / 1500.0)).ToString("F2"); return "$" + (world.WorldTick == 0 ? 0 : earned / (world.WorldTick / 1500.0)).ToString("F2");
} }
static Color GetPowerColor(PowerState state) static Color GetPowerColor(PowerState state)

View File

@@ -56,8 +56,8 @@ namespace OpenRA.Mods.RA
return; return;
var qr = Game.Renderer.WorldQuadRenderer; var qr = Game.Renderer.WorldQuadRenderer;
var doDim = refreshTick - world.FrameNumber <= 0; var doDim = refreshTick - world.WorldTick <= 0;
if (doDim) refreshTick = world.FrameNumber + 20; if (doDim) refreshTick = world.WorldTick + 20;
var viewBounds = wr.Viewport.CellBounds; var viewBounds = wr.Viewport.CellBounds;
foreach (var pair in layers) foreach (var pair in layers)

View File

@@ -3,11 +3,25 @@ Container@INGAME_ROOT:
Children: Children:
LogicTicker@DISCONNECT_WATCHER: LogicTicker@DISCONNECT_WATCHER:
Logic:DisconnectWatcherLogic Logic:DisconnectWatcherLogic
Timer@GAME_TIMER: Container@GAME_TIMER_BLOCK:
X: WINDOW_RIGHT/2 Logic:GameTimerLogic
Y: 0 X:WINDOW_RIGHT/2 - WIDTH
Font: Title Width:100
Contrast: true Height:55
Children:
Label@GAME_TIMER:
Width:PARENT_RIGHT
Height:30
Align:Center
Font:Title
Contrast:true
Label@GAME_TIMER_STATUS:
Y:35
Width:PARENT_RIGHT
Height:15
Align:Center
Font:Bold
Contrast:true
StrategicProgress@STRATEGIC_PROGRESS: StrategicProgress@STRATEGIC_PROGRESS:
X: WINDOW_RIGHT/2 X: WINDOW_RIGHT/2
Y: 40 Y: 40

View File

@@ -19,11 +19,25 @@ Container@INGAME_ROOT:
Y:0 Y:0
Width:WINDOW_RIGHT Width:WINDOW_RIGHT
Height:WINDOW_BOTTOM Height:WINDOW_BOTTOM
Timer@GAME_TIMER: Container@GAME_TIMER_BLOCK:
X: WINDOW_RIGHT/2 Logic:GameTimerLogic
Y: 0 X:WINDOW_RIGHT/2 - WIDTH
Font: Title Width:100
Contrast: true Height:55
Children:
Label@GAME_TIMER:
Width:PARENT_RIGHT
Height:30
Align:Center
Font:Title
Contrast:true
Label@GAME_TIMER_STATUS:
Y:32
Width:PARENT_RIGHT
Height:15
Align:Center
Font:Bold
Contrast:true
StrategicProgress@STRATEGIC_PROGRESS: StrategicProgress@STRATEGIC_PROGRESS:
X: WINDOW_RIGHT/2 X: WINDOW_RIGHT/2
Y: 40 Y: 40

View File

@@ -19,11 +19,25 @@ Container@INGAME_ROOT:
Y:0 Y:0
Width:WINDOW_RIGHT Width:WINDOW_RIGHT
Height:WINDOW_BOTTOM Height:WINDOW_BOTTOM
Timer@GAME_TIMER: Container@GAME_TIMER_BLOCK:
X: WINDOW_RIGHT/2 Logic:GameTimerLogic
Y: 0-10 X:WINDOW_RIGHT/2 - WIDTH
Font: Title Width:100
Contrast: true Height:55
Children:
Label@GAME_TIMER:
Width:PARENT_RIGHT
Height:15
Align:Center
Font:Title
Contrast:true
Label@GAME_TIMER_STATUS:
Y:35
Width:PARENT_RIGHT
Height:15
Align:Center
Font:Bold
Contrast:true
StrategicProgress@STRATEGIC_PROGRESS: StrategicProgress@STRATEGIC_PROGRESS:
X: WINDOW_RIGHT/2 X: WINDOW_RIGHT/2
Y: 40 Y: 40