Skip to content

Commit

Permalink
first major work for SCE done. A couple TODO's remain, but I have to …
Browse files Browse the repository at this point in the history
…do my homework sometime... I feel sure that I am missing piles of hidden errors...
  • Loading branch information
admalledd committed Feb 28, 2013
1 parent 6f81849 commit 0b65df4
Show file tree
Hide file tree
Showing 14 changed files with 357 additions and 4 deletions.
1 change: 1 addition & 0 deletions SimpleCronClone/examples/events/playerFirstJoin.sce
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
do say $0:::$1
1 change: 1 addition & 0 deletions SimpleCronClone/examples/events/playerJoin.sce
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
do say $0:::$1
1 change: 1 addition & 0 deletions SimpleCronClone/examples/events/playerQuit.sce
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
do say $0:::$1
1 change: 1 addition & 0 deletions SimpleCronClone/examples/events/playerTeleportWorld.sce
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
do say $0:::$1::$2::$3
1 change: 1 addition & 0 deletions SimpleCronClone/examples/events/serverEmpty.sce
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
do say $0:::$1
1 change: 1 addition & 0 deletions SimpleCronClone/examples/events/serverNotEmpty.sce
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
do say $0:::$1
1 change: 1 addition & 0 deletions SimpleCronClone/examples/events/worldEmpty.sce
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
do say $0:::$1::$2
1 change: 1 addition & 0 deletions SimpleCronClone/examples/events/worldNotEmpty.sce
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
do say $0:::$1::$2
20 changes: 20 additions & 0 deletions SimpleCronClone/examples/tab.sce
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#list of event then file to run when that event occurs
#PS: spaces in the file name are a bad idea mmkay?

playerJoin events/playerJoin.sce

playerFirstJoin events/playerFirstJoin.sce

playerQuit events/playerQuit.sce


serverEmpty events/serverEmpty.sce

serverNotEmpty events/serverNotEmpty.sce


playerTeleportWorld events/playerTeleportWorld.sce

worldEmpty events/worldEmpty.sce

worldNotEmpty events/worldNotEmpty.sce
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,9 @@
package org.bonsaimind.bukkitplugins.simplecronclone;

import it.sauronsoftware.cron4j.Scheduler;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.logging.Level;
import java.util.logging.Logger;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
/*
* This file is part of SimpleCronClone.
*
* SimpleCronClone is free software: you can redistribute it and/or modify
* it 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.
*
* SimpleCronClone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SimpleCronClone. If not, see <http://www.gnu.org/licenses/>.
*/
package org.bonsaimind.bukkitplugins.simplecronclone;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.bukkit.Server;

/**
* This is the engine which does the heavy lifting and interfacing
*/
public final class EventEngine {

private static final String COMMENT_START = "#";

private File workingDir;
private Server server;
private Plugin plugin;
private Logger logger;


//strings of the filePaths to the .sce files
private ArrayList<String> eventJoin;
private ArrayList<String> eventFirstJoin;
private ArrayList<String> eventQuit;

private ArrayList<String> eventServerEmpty;
private ArrayList<String> eventServerNotEmpty;

private ArrayList<String> eventPlayerWorldMove;

private ArrayList<String> eventWorldEmpty;
private ArrayList<String> eventWorldNotEmpty;


private static final String EVENT_JOIN = "playerJoin";

This comment has been minimized.

Copy link
@RobertZenz

RobertZenz Feb 28, 2013

Owner

I have a abstract structure in my head which I can't pinpoint right now...maybe you have an idea to this.

It would be good if we could keep those events in a list of some sort, easier extendable. I thought about something like a HashMap<String, List<String>>. First parameter is the name of the event, the second is the list of the assigned scripts. That would allow the events (and the parser) to directly work into this HashMap...something like this (pseudo):

// In the parser
if(events.containsKey(event)) {
    events.get(event).add(script);
} else {
    // No can do!
}

// In the Event-Listener
eventEngine.runScriptsFor("PlayerJoinedEvent");

// Back in the engine
for(String script : events.get(eventName)) {
    ScriptParser.executeScript(script);
}
private static final String EVENT_QUIT = "playerQuit";
private static final String EVENT_FIRST_JOIN = "playerFirstJoin";
private static final String EVENT_SERVER_EMPTY = "serverEmpty";
private static final String EVENT_SERVER_NOT_EMPTY = "serverNotEmpty";
private static final String EVENT_PLAYER_WORLD_MOVE = "playerTeleportWorld";
private static final String EVENT_WORLD_EMPTY = "worldEmpty";
private static final String EVENT_WORLD_NOT_EMPTY = "worldNotEmpty";

public EventEngine (Plugin _plugin, Server server, File workingDir) {
this.server = server;
this.workingDir = workingDir;
this.plugin = _plugin;
this.logger = plugin.getLogger();
}

public void start() {
// clear all the old stuff away
stop();
readTab();//TODO: when does this fail? what do we do if it does?


}

public void stop() {
eventJoin = new ArrayList<String>();

eventFirstJoin = new ArrayList<String>();
eventQuit = new ArrayList<String>();

eventServerEmpty = new ArrayList<String>();
eventServerNotEmpty = new ArrayList<String>();

eventPlayerWorldMove = new ArrayList<String>();

eventWorldEmpty = new ArrayList<String>();
eventWorldNotEmpty = new ArrayList<String>();
}


/**
* Reads the tab.sce (from the default location) and parses it.
* @return Returns true if reading and parsing was without incident.
*/
protected boolean readTab() {
File tab = new File(workingDir, "tab.sce");

if (!tab.exists() || !tab.canRead()) {
logger.log(Level.WARNING, "{0} does not exist or is not accessible.", tab.getPath());
return false;
}

try {
for (String line : ScriptParser.getLines(tab)) {
if (!line.isEmpty() && !line.trim().startsWith(COMMENT_START) && line.trim().endsWith(".sce")) {
parseTabLine(line);
}
}

return true;
} catch (FileNotFoundException ex) {
logger.log(Level.WARNING, "tab.sce does not exists!");
} catch (IOException ex) {
logger.log(Level.WARNING, "Failed to read tab.sce:\n{0}", ex.getMessage());
}

return false;
}

/**
* Parse the given line and add it to the event runner.
* @param line The line form the tab.sce.
*/
protected void parseTabLine(String line) {
line = line.trim();

String eventPart = line.substring(0, line.lastIndexOf(" ")).trim();
final String commandPart = line.substring(line.lastIndexOf(" ") + 1).trim();

if (eventPart.equalsIgnoreCase(EVENT_JOIN)){
eventJoin.add(commandPart);
}else if(eventPart.equalsIgnoreCase(EVENT_FIRST_JOIN)){
eventFirstJoin.add(commandPart);
}else if(eventPart.equalsIgnoreCase(EVENT_QUIT)){
eventQuit.add(commandPart);
}else if(eventPart.equalsIgnoreCase(EVENT_SERVER_EMPTY)){
eventServerEmpty.add(commandPart);
}else if(eventPart.equalsIgnoreCase(EVENT_SERVER_NOT_EMPTY)){
eventServerNotEmpty.add(commandPart);
}else if(eventPart.equalsIgnoreCase(EVENT_PLAYER_WORLD_MOVE)){
eventPlayerWorldMove.add(commandPart);
}else if(eventPart.equalsIgnoreCase(EVENT_WORLD_EMPTY)){
eventWorldEmpty.add(commandPart);
}else if(eventPart.equalsIgnoreCase(EVENT_WORLD_NOT_EMPTY)){
eventWorldNotEmpty.add(commandPart);
}else{
//TODO: do we want to raise an exception if the line fails parsing?

This comment has been minimized.

Copy link
@RobertZenz

RobertZenz Feb 28, 2013

Owner

I'd say no. We should log the warning that it failed to parse the line but otherwise continue. That's basically how the real cron works, too.

logger.warning(String.format("line failed parsing:'%s':eventPart:'%s':commandPart:'%s'",line,eventPart,commandPart));
return; //bypasses the next logging. Already logged that we failed this line.
}
//TODO: better name this logging output?
logger.info(String.format("SCE waiting: %s:::%s", eventPart,commandPart));
}
private void runEvents(ArrayList<String> filesToCall,final String[] args){
for (final String filePath : filesToCall){
Thread t = new Thread(new Runnable() {
@Override
public void run(){
ScriptParser.executeScript(server,logger,new File(workingDir,filePath),args);
}
});
t.start();
}
}
public void eventPlayerJoin(final String player){
final String[] args = {EVENT_JOIN,player};
runEvents(eventJoin, args);
}
public void eventFirstJoin(String player) {
final String[] args = {EVENT_FIRST_JOIN,player};
runEvents(eventFirstJoin, args);
}

public void eventPlayerQuit(String player) {
final String[] args = {EVENT_QUIT,player};
runEvents(eventQuit, args);
}

public void eventPlayerWorldMove(String player, String from, String to) {
final String[] args = {EVENT_PLAYER_WORLD_MOVE,player,from,to};
runEvents(eventPlayerWorldMove, args);
}

public void eventWorldEmpty(String player, String world) {
final String[] args = {EVENT_WORLD_EMPTY,player,world};
runEvents(eventWorldEmpty, args);
}

public void eventWorldNotEmpty(String player, String world) {
final String[] args = {EVENT_WORLD_NOT_EMPTY,player,world};
runEvents(eventWorldNotEmpty, args);
}

public void eventServerNotEmpty(String player) {
final String[] args = {EVENT_SERVER_NOT_EMPTY,player};
runEvents(eventServerNotEmpty, args);
}

public void eventServerEmpty(String player) {
final String[] args = {EVENT_SERVER_EMPTY,player};
runEvents(eventServerEmpty, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package org.bonsaimind.bukkitplugins.simplecronclone;


import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerChangedWorldEvent;

public class EventListener implements Listener {
private Plugin sccMain;

public EventListener(Plugin plugin) {
sccMain = plugin;
}

@EventHandler
public void onPlayerJoin(PlayerJoinEvent event){
//eventJoin
sccMain.eventEngine.eventPlayerJoin(event.getPlayer().getName());
if (!event.getPlayer().hasPlayedBefore()){
//eventFirstJoin
//TODO: this seems not to be reliable?

This comment has been minimized.

Copy link
@RobertZenz

RobertZenz Feb 28, 2013

Owner

Could be. If I see this right that method is only implemented in CraftBukkit, and it only gets set when the extra data for the player is read (whatever that is), and that only happens when a is called...what the...

So on the first look I'd say it should be reliable as long as no one is messing with the map or the player files. ... That's an educated guess, btw.

This comment has been minimized.

Copy link
@admalledd

admalledd Feb 28, 2013

Author Collaborator

yea... I may have given up on trying to figure that one out when I was working on the rest of the stuff... just going to leave it as a TODO for now until we get other things kinked out...

sccMain.eventEngine.eventFirstJoin(event.getPlayer().getName());
}
if (sccMain.getServer().getOnlinePlayers().length == 1){
//only user logged in means that we were just empty.
sccMain.eventEngine.eventServerNotEmpty(event.getPlayer().getName());
}
}

@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
//eventQuit
sccMain.eventEngine.eventPlayerQuit(event.getPlayer().getName());
if (sccMain.getServer().getOnlinePlayers().length == 0){
//no users logged in, means last player just quit.
sccMain.eventEngine.eventServerEmpty(event.getPlayer().getName());
}
}

@EventHandler
public void onPlayerChangedWorld(PlayerChangedWorldEvent event){
//eventPlayerWorldMove
sccMain.eventEngine.eventPlayerWorldMove(event.getPlayer().getName(),event.getFrom().getName(),event.getPlayer().getWorld().getName());

if(event.getFrom().getPlayers().size()==0){
//eventWorldEmpty
sccMain.eventEngine.eventWorldEmpty(event.getPlayer().getName(),event.getFrom().getName());
}
if(event.getPlayer().getWorld().getPlayers().size() == 1){
//eventWorldNotEmpty (if one player, that must means its ours that just moved)
sccMain.eventEngine.eventWorldNotEmpty(event.getPlayer().getName(),event.getPlayer().getWorld().getName());
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,18 @@ public class Plugin extends JavaPlugin {

private Server server;
private CronEngine engine;
private EventListener eventListener;

//public so that eventListener calls into it via this.plugin.scriptEngine.$EVENT_NAME()
public EventEngine eventEngine;

@Override
public void onDisable() {
engine.stop();
engine = null;
eventListener = null;
eventEngine.stop();
eventEngine = null;
}

@Override
Expand All @@ -52,6 +59,12 @@ public void onEnable() {
engine = new CronEngine(server, getLogger(), new File("plugins/SimpleCronClone/"));
engine.start();

eventEngine = new EventEngine(this, server, new File("plugins/SimpleCronClone"));
eventEngine.start();

eventListener = new EventListener(this);
server.getPluginManager().registerEvents(eventListener, this);

setCommands();

try {
Expand Down

0 comments on commit 0b65df4

Please sign in to comment.