mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-13 01:10:19 -04:00
fixed timers firing continuously after setting the time to a future date; fixed date stuff after realizing /time set sets world time absolutely (too used to nei by far...); added proper os.date implementation;
This commit is contained in:
parent
eb3a8e1ff8
commit
2a48cb28d9
@ -214,7 +214,11 @@ sandbox = {
|
||||
|
||||
os = {
|
||||
clock = os.clock,
|
||||
date = os.date,
|
||||
date = function(format, time)
|
||||
checkArg(1, format, "string", "nil")
|
||||
checkArg(2, time, "number", "nil")
|
||||
return os.date(format, time)
|
||||
end,
|
||||
difftime = function(t2, t1)
|
||||
return t2 - t1
|
||||
end,
|
||||
|
1
assets/opencomputers/lua/rom/bin/time.lua
Normal file
1
assets/opencomputers/lua/rom/bin/time.lua
Normal file
@ -0,0 +1 @@
|
||||
print(os.date("%F %T"))
|
@ -45,7 +45,7 @@ local function tick()
|
||||
if timer.times <= 0 then
|
||||
timers[id] = nil
|
||||
else
|
||||
timer.after = timer.after + timer.interval
|
||||
timer.after = os.uptime() + timer.interval
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -72,6 +72,7 @@ class Computer(isClient: Boolean) extends Rotatable with ComputerEnvironment wit
|
||||
super.updateEntity()
|
||||
if (node != null && node.network == null) {
|
||||
Network.joinOrCreateNetwork(worldObj, xCoord, yCoord, zCoord)
|
||||
this.synchronized(powerConsumed = 0.0)
|
||||
}
|
||||
else if (!worldObj.isRemote) {
|
||||
// If we just joined a network we were just loaded from disk. We skip the
|
||||
|
@ -13,7 +13,7 @@ import li.cil.oc.api.network._
|
||||
import li.cil.oc.common.tileentity
|
||||
import li.cil.oc.server
|
||||
import li.cil.oc.util.ExtendedLuaState.extendLuaState
|
||||
import li.cil.oc.util.LuaStateFactory
|
||||
import li.cil.oc.util.{GameTimeFormatter, LuaStateFactory}
|
||||
import li.cil.oc.{OpenComputers, Config}
|
||||
import net.minecraft.nbt._
|
||||
import net.minecraft.tileentity.TileEntity
|
||||
@ -112,7 +112,7 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
|
||||
switchTo(Computer.State.Starting)
|
||||
|
||||
// Remember when we started, for os.clock().
|
||||
timeStarted = owner.world.getWorldInfo.getWorldTotalTime
|
||||
timeStarted = owner.world.getWorldTime
|
||||
|
||||
// Mark state change in owner, to send it to clients.
|
||||
owner.markAsChanged(8) // Initial power required to start.
|
||||
@ -214,12 +214,12 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
|
||||
// pause.
|
||||
lastUpdate = System.currentTimeMillis
|
||||
|
||||
// TODO This seems to be the "run time", not the elapsed ingame time. For example, when doing /time set 0 the game
|
||||
// should jump to the next day, but this value does not jump. Is this just Forge or do we have to find some other
|
||||
// way around this? CC seems to use getWorldTime, which is really odd, since that should be only within the range
|
||||
// of a single day (0 to 24000), which it *is*... perhaps vanilla Minecraft (not re-compiled) behaves different?
|
||||
// Update world time for computer threads.
|
||||
worldTime = owner.world.getWorldInfo.getWorldTotalTime
|
||||
// Update world time for time().
|
||||
worldTime = owner.world.getWorldTime
|
||||
if (isRunning) {
|
||||
// We can have rollbacks from '/time set'. Avoid getting negative uptimes.
|
||||
timeStarted = timeStarted min worldTime
|
||||
}
|
||||
|
||||
// Check if we should switch states.
|
||||
state.synchronized(state.top match {
|
||||
@ -231,7 +231,6 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
|
||||
// Resuming after being loaded.
|
||||
case Computer.State.Resuming if System.currentTimeMillis() >= sleepUntil => {
|
||||
verifyComponents()
|
||||
owner.markAsChanged(Double.NegativeInfinity)
|
||||
state.pop()
|
||||
switchTo(state.top) // Trigger execution if necessary.
|
||||
}
|
||||
@ -622,13 +621,57 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
|
||||
})
|
||||
lua.setField(-2, "clock")
|
||||
|
||||
// Date formatting function.
|
||||
lua.pushScalaFunction(lua => {
|
||||
val format =
|
||||
if (lua.getTop > 0 && lua.isString(1)) lua.toString(1)
|
||||
else "%d/%m/%y %H:%M:%S"
|
||||
val time =
|
||||
if (lua.getTop > 1 && lua.isNumber(2)) lua.toNumber(2) * 1000 / 60 / 60
|
||||
else worldTime + 6000
|
||||
|
||||
val dt = GameTimeFormatter.parse(time)
|
||||
def fmt(format: String) {
|
||||
if (format == "*t") {
|
||||
lua.newTable(0, 8)
|
||||
lua.pushInteger(dt.year)
|
||||
lua.setField(-2, "year")
|
||||
lua.pushInteger(dt.month)
|
||||
lua.setField(-2, "month")
|
||||
lua.pushInteger(dt.day)
|
||||
lua.setField(-2, "day")
|
||||
lua.pushInteger(dt.hour)
|
||||
lua.setField(-2, "hour")
|
||||
lua.pushInteger(dt.minute)
|
||||
lua.setField(-2, "min")
|
||||
lua.pushInteger(dt.second)
|
||||
lua.setField(-2, "sec")
|
||||
lua.pushInteger(dt.weekDay)
|
||||
lua.setField(-2, "wday")
|
||||
lua.pushInteger(dt.yearDay)
|
||||
lua.setField(-2, "yday")
|
||||
}
|
||||
else {
|
||||
lua.pushString(GameTimeFormatter.format(format, dt))
|
||||
}
|
||||
}
|
||||
|
||||
// Just ignore the allowed leading '!', Minecraft has no time zones...
|
||||
if (format.startsWith("!"))
|
||||
fmt(format.substring(1))
|
||||
else
|
||||
fmt(format)
|
||||
1
|
||||
})
|
||||
lua.setField(-2, "date")
|
||||
|
||||
// Return ingame time for os.time().
|
||||
lua.pushScalaFunction(lua => {
|
||||
// Game time is in ticks, so that each day has 24000 ticks, meaning
|
||||
// one hour is game time divided by one thousand. Also, Minecraft
|
||||
// starts days at 6 o'clock, so we add those six hours. Thus:
|
||||
// timestamp = (time + 6000) / 1000[h] * 60[m] * 60[s] * 1000[ms]
|
||||
lua.pushNumber((worldTime + 6000) * 60 * 60)
|
||||
// timestamp = (time + 6000) * 60[kh] * 60[km] / 1000[s]
|
||||
lua.pushNumber((worldTime + 6000) * 60 * 60 / 1000)
|
||||
1
|
||||
})
|
||||
lua.setField(-2, "time")
|
||||
|
@ -33,7 +33,7 @@ class RedstoneCard extends ManagedComponent {
|
||||
@LuaCallback("setOutput")
|
||||
def setOutput(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val side = checkSide(args, 0)
|
||||
val value = args.checkInteger(1) max 0 min 15
|
||||
val value = args.checkInteger(1) max 0 min 255
|
||||
node.network.node(context.address).host match {
|
||||
case redstone: Redstone =>
|
||||
redstone.output(ForgeDirection.getOrientation(side), value.toShort)
|
||||
|
100
li/cil/oc/util/GameTimeFormatter.scala
Normal file
100
li/cil/oc/util/GameTimeFormatter.scala
Normal file
@ -0,0 +1,100 @@
|
||||
package li.cil.oc.util
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
object GameTimeFormatter {
|
||||
// Locale? What locale? Seriously though, since this would depend on the
|
||||
// server's locale I think it makes more sense to keep it English always.
|
||||
private val weekDays = Array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")
|
||||
private val shortWeekDays = Array("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat")
|
||||
private val months = Array("January", "Febuary", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December")
|
||||
private val shortMonths = Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
|
||||
private val amPm = Array("AM", "PM")
|
||||
|
||||
class DateTime(val year: Int, val month: Int, val day: Int,
|
||||
val weekDay: Int, val yearDay: Int,
|
||||
val hour: Int, val minute: Int, val second: Int)
|
||||
|
||||
// See http://www.cplusplus.com/reference/ctime/strftime/
|
||||
private val specifiers: Map[Char, (DateTime) => String] = Map(
|
||||
'a' -> (t => shortWeekDays(t.weekDay)),
|
||||
'A' -> (t => weekDays(t.weekDay)),
|
||||
'b' -> (t => shortMonths(t.month)),
|
||||
'B' -> (t => months(t.month)),
|
||||
'c' -> (t => format("%a %b %d %H:%M:%S %Y", t)),
|
||||
'C' -> (t => "%02d".format(t.year / 100)),
|
||||
'd' -> (t => "%02d".format(t.day + 1)),
|
||||
'D' -> (t => format("%m/%d/%y", t)),
|
||||
'e' -> (t => "% 2d".format(t.day + 1)),
|
||||
'F' -> (t => format("%Y-%m-%d", t)),
|
||||
//'g' -> (t => ""),
|
||||
//'G' -> (t => ""),
|
||||
'h' -> (t => format("%b", t)),
|
||||
'H' -> (t => "%02d".format(t.hour)),
|
||||
'I' -> (t => "%02d".format(t.hour % 12 + 1)),
|
||||
'j' -> (t => "%03d".format(t.yearDay)),
|
||||
'm' -> (t => "%02d".format(t.month + 1)),
|
||||
'M' -> (t => "%02d".format(t.minute)),
|
||||
'n' -> (t => "\n"),
|
||||
'p' -> (t => amPm(if (t.hour < 12) 0 else 1)),
|
||||
'r' -> (t => format("%I:%M:%S %p", t)),
|
||||
'R' -> (t => format("%H:%M", t)),
|
||||
'S' -> (t => "%02d".format(t.second)),
|
||||
't' -> (t => "\t"),
|
||||
'T' -> (t => format("%H:%M:%S", t)),
|
||||
'u' -> (t => ""),
|
||||
//'U' -> (t => ""),
|
||||
//'V' -> (t => ""),
|
||||
'w' -> (t => "%d".format(t.weekDay)),
|
||||
//'W' -> (t => ""),
|
||||
'x' -> (t => format("%D", t)),
|
||||
'X' -> (t => format("%T", t)),
|
||||
'y' -> (t => "%02d".format(t.year % 100)),
|
||||
'Y' -> (t => "%04d".format(t.year)),
|
||||
//'z' -> (t => ""),
|
||||
//'Z' -> (t => ""),
|
||||
'%' -> (t => "%")
|
||||
)
|
||||
|
||||
def parse(time: Double) = {
|
||||
var day = (time / 24000).toLong
|
||||
val weekDay = ((4 + day) % 7).toInt
|
||||
val year = 1970 + (day / 365.2425).toInt
|
||||
val yearDay = (day % 365.2425).toInt
|
||||
day = yearDay
|
||||
val monthLengths =
|
||||
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
|
||||
Array(31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
|
||||
else
|
||||
Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
|
||||
var month = 0
|
||||
while (day > monthLengths(month)) {
|
||||
day = day - monthLengths(month)
|
||||
month = month + 1
|
||||
}
|
||||
|
||||
var seconds = ((time % 24000) * 60 * 60 / 1000).toInt
|
||||
var minutes = seconds / 60
|
||||
seconds = seconds % 60
|
||||
val hours = (minutes / 60) % 24
|
||||
minutes = minutes % 60
|
||||
|
||||
new DateTime(year, month, day.toInt, weekDay, yearDay, hours, minutes, seconds)
|
||||
}
|
||||
|
||||
def format(format: String, time: DateTime) = {
|
||||
val result = new mutable.StringBuilder()
|
||||
val iterator = format.iterator
|
||||
while (iterator.hasNext) {
|
||||
iterator.next() match {
|
||||
case '%' if iterator.hasNext =>
|
||||
specifiers.get(iterator.next()) match {
|
||||
case Some(specifier) => result.append(specifier(time))
|
||||
case _ =>
|
||||
}
|
||||
case c => result.append(c)
|
||||
}
|
||||
}
|
||||
result.toString()
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@ import com.naef.jnlua.{LuaState, NativeSupport}
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.nio.channels.Channels
|
||||
import java.util.{Locale, Calendar}
|
||||
import li.cil.oc.server.component.Computer
|
||||
import li.cil.oc.util.ExtendedLuaState._
|
||||
import li.cil.oc.{OpenComputers, Config}
|
||||
@ -154,15 +153,6 @@ object LuaStateFactory {
|
||||
})
|
||||
state.setField(-2, "realTime")
|
||||
|
||||
// Date-time formatting using Java's formatting capabilities.
|
||||
state.pushScalaFunction(lua => {
|
||||
val calendar = Calendar.getInstance(Locale.ENGLISH)
|
||||
calendar.setTimeInMillis(lua.checkInteger(1))
|
||||
// TODO
|
||||
1
|
||||
})
|
||||
state.setField(-2, "date")
|
||||
|
||||
// Pop the os table.
|
||||
state.pop(1)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user