mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2024-06-25 22:53:22 +00:00
![SquidDev](/assets/img/avatar_default.png)
ILuaAPI has been moved to dan200.computercraft.api.lua. One creates a new API by registering an instance of ILuaAPIFactory. This takes an instance of IComputerSystem and returns such an API. IComputerSystem is an extension of IComputerAccess, with methods to access additional information about the the computer, such as its label and filesystem.
439 lines
13 KiB
Java
439 lines
13 KiB
Java
/*
|
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
|
* Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
|
|
* Send enquiries to dratcliffe@gmail.com
|
|
*/
|
|
|
|
package dan200.computercraft.core.apis;
|
|
|
|
import dan200.computercraft.api.lua.ILuaAPI;
|
|
import dan200.computercraft.api.lua.ILuaContext;
|
|
import dan200.computercraft.api.lua.LuaException;
|
|
import dan200.computercraft.shared.util.StringUtil;
|
|
|
|
import javax.annotation.Nonnull;
|
|
import java.util.*;
|
|
|
|
import static dan200.computercraft.core.apis.ArgumentHelper.*;
|
|
|
|
public class OSAPI implements ILuaAPI
|
|
{
|
|
private IAPIEnvironment m_apiEnvironment;
|
|
|
|
private final Map<Integer, Timer> m_timers;
|
|
private final Map<Integer, Alarm> m_alarms;
|
|
private int m_clock;
|
|
private double m_time;
|
|
private int m_day;
|
|
|
|
private int m_nextTimerToken;
|
|
private int m_nextAlarmToken;
|
|
|
|
private static class Timer
|
|
{
|
|
public int m_ticksLeft;
|
|
|
|
public Timer( int ticksLeft )
|
|
{
|
|
m_ticksLeft = ticksLeft;
|
|
}
|
|
}
|
|
|
|
private class Alarm implements Comparable<Alarm>
|
|
{
|
|
public final double m_time;
|
|
public final int m_day;
|
|
|
|
public Alarm( double time, int day )
|
|
{
|
|
m_time = time;
|
|
m_day = day;
|
|
}
|
|
|
|
@Override
|
|
public int compareTo( @Nonnull Alarm o )
|
|
{
|
|
double t = (double)m_day * 24.0 + m_time;
|
|
double ot = (double)m_day * 24.0 + m_time;
|
|
if( t < ot ) {
|
|
return -1;
|
|
} else if( t > ot ) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
public OSAPI( IAPIEnvironment environment )
|
|
{
|
|
m_apiEnvironment = environment;
|
|
m_nextTimerToken = 0;
|
|
m_nextAlarmToken = 0;
|
|
m_timers = new HashMap<>();
|
|
m_alarms = new HashMap<>();
|
|
}
|
|
|
|
// ILuaAPI implementation
|
|
|
|
@Override
|
|
public String[] getNames()
|
|
{
|
|
return new String[] {
|
|
"os"
|
|
};
|
|
}
|
|
|
|
@Override
|
|
public void startup()
|
|
{
|
|
m_time = m_apiEnvironment.getComputerEnvironment().getTimeOfDay();
|
|
m_day = m_apiEnvironment.getComputerEnvironment().getDay();
|
|
m_clock = 0;
|
|
|
|
synchronized( m_timers )
|
|
{
|
|
m_timers.clear();
|
|
}
|
|
|
|
synchronized( m_alarms )
|
|
{
|
|
m_alarms.clear();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void update()
|
|
{
|
|
synchronized( m_timers )
|
|
{
|
|
// Update the clock
|
|
m_clock++;
|
|
|
|
// Countdown all of our active timers
|
|
Iterator<Map.Entry<Integer, Timer>> it = m_timers.entrySet().iterator();
|
|
while( it.hasNext() )
|
|
{
|
|
Map.Entry<Integer, Timer> entry = it.next();
|
|
Timer timer = entry.getValue();
|
|
timer.m_ticksLeft = timer.m_ticksLeft - 1;
|
|
if( timer.m_ticksLeft <= 0 )
|
|
{
|
|
// Queue the "timer" event
|
|
queueLuaEvent( "timer", new Object[] { entry.getKey() } );
|
|
it.remove();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Wait for all of our alarms
|
|
synchronized( m_alarms )
|
|
{
|
|
double previousTime = m_time;
|
|
int previousDay = m_day;
|
|
double time = m_apiEnvironment.getComputerEnvironment().getTimeOfDay();
|
|
int day = m_apiEnvironment.getComputerEnvironment().getDay();
|
|
|
|
if( time > previousTime || day > previousDay )
|
|
{
|
|
double now = (double)m_day * 24.0 + m_time;
|
|
Iterator<Map.Entry<Integer, Alarm>> it = m_alarms.entrySet().iterator();
|
|
while( it.hasNext() )
|
|
{
|
|
Map.Entry<Integer, Alarm> entry = it.next();
|
|
Alarm alarm = entry.getValue();
|
|
double t = (double)alarm.m_day * 24.0 + alarm.m_time;
|
|
if( now >= t )
|
|
{
|
|
queueLuaEvent( "alarm", new Object[]{ entry.getKey() } );
|
|
it.remove();
|
|
}
|
|
}
|
|
}
|
|
|
|
m_time = time;
|
|
m_day = day;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void shutdown( )
|
|
{
|
|
synchronized( m_timers )
|
|
{
|
|
m_timers.clear();
|
|
}
|
|
|
|
synchronized( m_alarms )
|
|
{
|
|
m_alarms.clear();
|
|
}
|
|
}
|
|
|
|
@Nonnull
|
|
@Override
|
|
public String[] getMethodNames()
|
|
{
|
|
return new String[] {
|
|
"queueEvent",
|
|
"startTimer",
|
|
"setAlarm",
|
|
"shutdown",
|
|
"reboot",
|
|
"computerID",
|
|
"getComputerID",
|
|
"setComputerLabel",
|
|
"computerLabel",
|
|
"getComputerLabel",
|
|
"clock",
|
|
"time",
|
|
"day",
|
|
"cancelTimer",
|
|
"cancelAlarm",
|
|
"epoch"
|
|
};
|
|
}
|
|
|
|
private float getTimeForCalendar(Calendar c)
|
|
{
|
|
float time = c.get(Calendar.HOUR_OF_DAY);
|
|
time += (float)c.get(Calendar.MINUTE) / 60.0f;
|
|
time += (float)c.get(Calendar.SECOND) / (60.0f * 60.0f);
|
|
return time;
|
|
}
|
|
|
|
private int getDayForCalendar(Calendar c)
|
|
{
|
|
GregorianCalendar g = (c instanceof GregorianCalendar) ? (GregorianCalendar)c : new GregorianCalendar();
|
|
int year = c.get(Calendar.YEAR);
|
|
int day = 0;
|
|
for( int y=1970; y<year; ++y )
|
|
{
|
|
day += g.isLeapYear(y) ? 366 : 365;
|
|
}
|
|
day += c.get(Calendar.DAY_OF_YEAR);
|
|
return day;
|
|
}
|
|
|
|
private long getEpochForCalendar(Calendar c)
|
|
{
|
|
return c.getTime().getTime();
|
|
}
|
|
|
|
@Override
|
|
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
|
|
{
|
|
switch( method )
|
|
{
|
|
case 0:
|
|
{
|
|
// queueEvent
|
|
queueLuaEvent( getString( args, 0 ), trimArray( args, 1 ) );
|
|
return null;
|
|
}
|
|
case 1:
|
|
{
|
|
// startTimer
|
|
double timer = getReal( args, 0 );
|
|
synchronized( m_timers )
|
|
{
|
|
m_timers.put( m_nextTimerToken, new Timer( (int)Math.round( timer / 0.05 ) ) );
|
|
return new Object[] { m_nextTimerToken++ };
|
|
}
|
|
}
|
|
case 2:
|
|
{
|
|
// setAlarm
|
|
double time = getReal( args, 0 );
|
|
if( time < 0.0 || time >= 24.0 )
|
|
{
|
|
throw new LuaException( "Number out of range" );
|
|
}
|
|
synchronized( m_alarms )
|
|
{
|
|
int day = (time > m_time) ? m_day : (m_day + 1);
|
|
m_alarms.put( m_nextAlarmToken, new Alarm( time, day ) );
|
|
return new Object[] { m_nextAlarmToken++ };
|
|
}
|
|
}
|
|
case 3:
|
|
{
|
|
// shutdown
|
|
m_apiEnvironment.shutdown();
|
|
return null;
|
|
}
|
|
case 4:
|
|
{
|
|
// reboot
|
|
m_apiEnvironment.reboot();
|
|
return null;
|
|
}
|
|
case 5:
|
|
case 6:
|
|
{
|
|
// computerID/getComputerID
|
|
return new Object[] { getComputerID() };
|
|
}
|
|
case 7:
|
|
{
|
|
// setComputerLabel
|
|
String label = optString( args, 0, null );
|
|
m_apiEnvironment.setLabel( StringUtil.normaliseLabel( label ) );
|
|
return null;
|
|
}
|
|
case 8:
|
|
case 9:
|
|
{
|
|
// computerLabel/getComputerLabel
|
|
String label = m_apiEnvironment.getLabel();
|
|
if( label != null )
|
|
{
|
|
return new Object[] { label };
|
|
}
|
|
return null;
|
|
}
|
|
case 10:
|
|
{
|
|
// clock
|
|
synchronized( m_timers )
|
|
{
|
|
return new Object[] { (double)m_clock * 0.05 };
|
|
}
|
|
}
|
|
case 11:
|
|
{
|
|
// time
|
|
String param = optString( args, 0, "ingame" );
|
|
switch( param )
|
|
{
|
|
case "utc":
|
|
{
|
|
// Get Hour of day (UTC)
|
|
Calendar c = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) );
|
|
return new Object[] { getTimeForCalendar( c ) };
|
|
}
|
|
case "local":
|
|
{
|
|
// Get Hour of day (local time)
|
|
Calendar c = Calendar.getInstance();
|
|
return new Object[] { getTimeForCalendar( c ) };
|
|
}
|
|
case "ingame":
|
|
// Get ingame hour
|
|
synchronized( m_alarms )
|
|
{
|
|
return new Object[] { m_time };
|
|
}
|
|
default:
|
|
throw new LuaException( "Unsupported operation" );
|
|
}
|
|
}
|
|
case 12:
|
|
{
|
|
// day
|
|
String param = optString( args, 0, "ingame" );
|
|
switch( param )
|
|
{
|
|
case "utc":
|
|
{
|
|
// Get numbers of days since 1970-01-01 (utc)
|
|
Calendar c = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) );
|
|
return new Object[] { getDayForCalendar( c ) };
|
|
}
|
|
case "local":
|
|
{
|
|
// Get numbers of days since 1970-01-01 (local time)
|
|
Calendar c = Calendar.getInstance();
|
|
return new Object[] { getDayForCalendar( c ) };
|
|
}
|
|
case "ingame":
|
|
// Get game day
|
|
synchronized( m_alarms )
|
|
{
|
|
return new Object[] { m_day };
|
|
}
|
|
default:
|
|
throw new LuaException( "Unsupported operation" );
|
|
}
|
|
}
|
|
case 13:
|
|
{
|
|
// cancelTimer
|
|
int token = getInt( args, 0 );
|
|
synchronized( m_timers )
|
|
{
|
|
if( m_timers.containsKey( token ) )
|
|
{
|
|
m_timers.remove( token );
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
case 14:
|
|
{
|
|
// cancelAlarm
|
|
int token = getInt( args, 0 );
|
|
synchronized( m_alarms )
|
|
{
|
|
if( m_alarms.containsKey( token ) )
|
|
{
|
|
m_alarms.remove( token );
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
case 15:
|
|
{
|
|
// epoch
|
|
String param = optString( args, 0, "ingame" );
|
|
switch( param )
|
|
{
|
|
case "utc":
|
|
{
|
|
// Get utc epoch
|
|
Calendar c = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) );
|
|
return new Object[] { getEpochForCalendar( c ) };
|
|
}
|
|
case "local":
|
|
{
|
|
// Get local epoch
|
|
Calendar c = Calendar.getInstance();
|
|
return new Object[] { getEpochForCalendar( c ) };
|
|
}
|
|
case "ingame":
|
|
// Get in-game epoch
|
|
synchronized( m_alarms )
|
|
{
|
|
return new Object[] {
|
|
m_day * 86400000 + (int) (m_time * 3600000.0f)
|
|
};
|
|
}
|
|
default:
|
|
throw new LuaException( "Unsupported operation" );
|
|
}
|
|
}
|
|
default:
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Private methods
|
|
|
|
private void queueLuaEvent( String event, Object[] args )
|
|
{
|
|
m_apiEnvironment.queueEvent( event, args );
|
|
}
|
|
|
|
private Object[] trimArray( Object[] array, int skip )
|
|
{
|
|
return Arrays.copyOfRange( array, skip, array.length );
|
|
}
|
|
|
|
private int getComputerID()
|
|
{
|
|
return m_apiEnvironment.getComputerID();
|
|
}
|
|
}
|