Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add general world timer events #1324

Merged
merged 4 commits into from
Nov 1, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2014 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.terasology.world.time;

import junit.framework.Assert;

import org.junit.Test;

/**
* Tests the world-time related classes
* @author Martin Steiger
*/
public class WorldTimeTest {

@Test
public void testEventMatchesDaily() {

float[] fracs = new float[] { 0.40f, 0.405f, 0.395f, 0.11111f, 0.3950001f, 0.400001f };
int[] hits = new int[fracs.length];

long days = 3;

for (int tick = 0; tick < WorldTime.TICK_EVENTS_PER_DAY * days; tick++) {
WorldTimeEvent event = new WorldTimeEvent(tick * WorldTime.TICK_EVENT_RATE);

for (int i = 0; i < fracs.length; i++) {
if (event.matchesDaily(fracs[i])) {
hits[i]++;
}
}
}

for (int i = 0; i < fracs.length; i++) {
Assert.assertEquals("Fraction " + fracs[i] + " was hits " + hits[i] + " times", days, hits[i]);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
*
* @author Immortius
*/
public class OnDawnEvent extends WorldTimeEvent {
public class OnDawnEvent extends TimeEventBase {

public OnDawnEvent(float worldTime, long worldTimeMS) {
super(worldTime, worldTimeMS);
public OnDawnEvent(long worldTimeMS) {
super(worldTimeMS);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
*
* @author Immortius
*/
public class OnDuskEvent extends WorldTimeEvent {
public class OnDuskEvent extends TimeEventBase {

public OnDuskEvent(float worldTime, long worldTimeMS) {
super(worldTime, worldTimeMS);
public OnDuskEvent(long worldTimeMS) {
super(worldTimeMS);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
*
* @author Immortius
*/
public class OnMiddayEvent extends WorldTimeEvent {
public class OnMiddayEvent extends TimeEventBase {

public OnMiddayEvent(float worldTime, long worldTimeMS) {
super(worldTime, worldTimeMS);
public OnMiddayEvent(long worldTimeMS) {
super(worldTimeMS);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
*
* @author Immortius
*/
public class OnMidnightEvent extends WorldTimeEvent {
public class OnMidnightEvent extends TimeEventBase {

public OnMidnightEvent(float worldTime, long worldTimeMS) {
super(worldTime, worldTimeMS);
public OnMidnightEvent(long worldTimeMS) {
super(worldTimeMS);
}
}
64 changes: 64 additions & 0 deletions engine/src/main/java/org/terasology/world/time/TimeEventBase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2014 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.terasology.world.time;

import org.terasology.entitySystem.event.Event;

import com.google.common.math.LongMath;

/**
* A base class for different timer events
* @author Martin Steiger
*/
public abstract class TimeEventBase implements Event {

private long worldTimeMS;
private long timeInDay;

public TimeEventBase(long worldTimeMS) {
this.worldTimeMS = worldTimeMS;
this.timeInDay = LongMath.mod(worldTimeMS, WorldTime.DAY_LENGTH);
}

/**
* @return the time of day as a fraction
*/
public float getDayTime() {
return timeInDay / (float) WorldTime.DAY_LENGTH;
}

/**
* @return the time of day in milli secs
*/
public long getDayTimeInMs() {
return timeInDay;
}

/**
* @return the world time in days
*/
public float getWorldTime() {
return worldTimeMS / (float) WorldTime.DAY_LENGTH;
}

/**
* @return the world time in milli secs
*/
public long getWorldTimeInMs() {
return worldTimeMS;
}
}
17 changes: 16 additions & 1 deletion engine/src/main/java/org/terasology/world/time/WorldTime.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,22 @@
*/
public interface WorldTime extends ComponentSystem {

int DAY_LENGTH = 1000 * 60 * 60 * 24;
/**
* The length of a day in milli-seconds
*/
long DAY_LENGTH = 1000 * 60 * 60 * 24;

long MIDDAY_TIME = DAY_LENGTH / 4;
long MIDNIGHT_TIME = 3 * DAY_LENGTH / 4;

/**
* The number of timer tick events per day.
* This must be a divisor of {@link #DAY_LENGTH} to avoid rounding issues.
*/
long TICK_EVENTS_PER_DAY = 100;

long TICK_EVENT_RATE = DAY_LENGTH / TICK_EVENTS_PER_DAY;


/**
* @return World time in milliseconds.
Expand Down
30 changes: 19 additions & 11 deletions engine/src/main/java/org/terasology/world/time/WorldTimeEvent.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,33 @@
*/
package org.terasology.world.time;

import org.terasology.entitySystem.event.Event;
import java.math.RoundingMode;

import com.google.common.base.Preconditions;
import com.google.common.math.DoubleMath;

/**
* A timer event that represents a (world-based) time instant
* @author Immortius
* @author Martin Steiger
*/
public class WorldTimeEvent implements Event {
private float worldTime;
private long worldTimeMS;
public class WorldTimeEvent extends TimeEventBase {

public WorldTimeEvent(float worldTime, long worldTimeMS) {
this.worldTimeMS = worldTimeMS;
this.worldTime = worldTime;
public WorldTimeEvent(long worldTimeMS) {
super(worldTimeMS);
}

public long getWorldTimeMS() {
return worldTimeMS;
public boolean matchesDaily(float fraction) {
Preconditions.checkArgument(fraction >= 0 && fraction <= 1, "fraction must be in [0..1]");

long fracInMs = DoubleMath.roundToLong(fraction * WorldTime.DAY_LENGTH, RoundingMode.HALF_UP);
long diff = getDayTimeInMs() - fracInMs;

return 2 * diff < WorldTime.TICK_EVENT_RATE && 2 * diff >= -WorldTime.TICK_EVENT_RATE;
}

public float getWorldTime() {
return worldTime;
@Override
public String toString() {
return String.format("WorldTimeEvent [%s ms -> %.2f days]", getWorldTimeInMs(), getWorldTime());
}
}
63 changes: 36 additions & 27 deletions engine/src/main/java/org/terasology/world/time/WorldTimeImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,19 @@
import org.terasology.registry.In;
import org.terasology.world.WorldComponent;

import com.google.common.math.LongMath;

import java.math.RoundingMode;
import java.util.concurrent.atomic.AtomicLong;

/**
* @author Immortius
*/
public class WorldTimeImpl extends BaseComponentSystem implements WorldTime, UpdateSubscriberSystem {
public static final long DAYS_TO_MS = (DAY_LENGTH);
public static final float MS_TO_DAYS = 1.f / (DAYS_TO_MS);

public static final long DAWN_TIME = DAY_LENGTH;
public static final long MIDDAY_TIME = DAY_LENGTH / 4;
public static final long DUSK_TIME = DAY_LENGTH / 2;
public static final long MIDNIGHT_TIME = 3 * DAY_LENGTH / 4;
private static final long DAWN_TIME = DAY_LENGTH;
private static final long DUSK_TIME = DAY_LENGTH / 2;

private static final float WORLD_TIME_MULTIPLIER = 48f;

private AtomicLong worldTime = new AtomicLong(0);
Expand All @@ -58,7 +58,7 @@ public float getSeconds() {

@Override
public float getDays() {
return MS_TO_DAYS * worldTime.get();
return worldTime.get() / (float) DAY_LENGTH;
}

@Override
Expand All @@ -74,7 +74,7 @@ public void setMilliseconds(long newWorldTime) {

@Override
public void setDays(float timeInDays) {
setMilliseconds((long) ((double) timeInDays * DAYS_TO_MS));
setMilliseconds((long) ((double) timeInDays * DAY_LENGTH));
}

@Override
Expand All @@ -84,26 +84,35 @@ public void update(float delta) {
deltaMs = (long) (deltaMs * WORLD_TIME_MULTIPLIER);
long startTime = worldTime.getAndAdd(deltaMs);
long endTime = startTime + deltaMs;
long timeInDay = startTime % DAY_LENGTH;
if (timeInDay < 0) {
timeInDay = DAY_LENGTH + timeInDay;
long timeInDay = LongMath.mod(startTime, DAY_LENGTH);
long day = LongMath.divide(startTime, DAY_LENGTH, RoundingMode.FLOOR);

long startTick = startTime / TICK_EVENT_RATE;
long endTick = (endTime) / TICK_EVENT_RATE;

if (startTick != endTick) {
long tick = endTime - endTime % TICK_EVENT_RATE;
getWorldEntity().send(new WorldTimeEvent(tick));
}

if (timeInDay < MIDDAY_TIME && timeInDay + deltaMs >= MIDDAY_TIME) {
long tick = day * DAY_LENGTH + MIDDAY_TIME;
getWorldEntity().send(new OnMiddayEvent(tick));
}
if (timeInDay < MIDDAY_TIME) {
if (timeInDay + deltaMs >= MIDDAY_TIME) {
getWorldEntity().send(new OnMiddayEvent(MS_TO_DAYS * endTime, endTime));
}
} else if (timeInDay < DUSK_TIME) {
if (timeInDay + deltaMs >= DUSK_TIME) {
getWorldEntity().send(new OnDuskEvent(MS_TO_DAYS * endTime, endTime));
}
} else if (timeInDay < MIDNIGHT_TIME) {
if (timeInDay + deltaMs >= MIDNIGHT_TIME) {
getWorldEntity().send(new OnMidnightEvent(MS_TO_DAYS * endTime, endTime));
}
} else if (timeInDay < DAWN_TIME) {
if (timeInDay + deltaMs >= DAWN_TIME) {
getWorldEntity().send(new OnDawnEvent(MS_TO_DAYS * endTime, endTime));
}

if (timeInDay < DUSK_TIME && timeInDay + deltaMs >= DUSK_TIME) {
long tick = day * DAY_LENGTH + DUSK_TIME;
getWorldEntity().send(new OnDuskEvent(tick));
}

if (timeInDay < MIDNIGHT_TIME && timeInDay + deltaMs >= MIDNIGHT_TIME) {
long tick = day * DAY_LENGTH + MIDNIGHT_TIME;
getWorldEntity().send(new OnMidnightEvent(tick));
}

if (timeInDay < DAWN_TIME && timeInDay + deltaMs >= DAWN_TIME) {
long tick = day * DAY_LENGTH + DAWN_TIME;
getWorldEntity().send(new OnDawnEvent(tick));
}
}
}
Expand Down