Skip to content

Commit

Permalink
Merge pull request #130 from Column01/py3-port
Browse files Browse the repository at this point in the history
Ported mark2 to Python 3
  • Loading branch information
gsand committed Jul 26, 2021
2 parents dadb16e + 61bb6ba commit 4b151cd
Show file tree
Hide file tree
Showing 33 changed files with 337 additions and 319 deletions.
37 changes: 9 additions & 28 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
## requirements

* UNIX-like operating system (Linux, Mac OS X, BSD)
* python 2.6/2.7 (+ dev package for psutil installation)
* python 3.0+ (+ dev package for psutil installation)
* psutil
* urwid 1.x
* urwid
* twisted
* twisted-web
* twisted-words (for IRC support)
Expand All @@ -14,41 +14,22 @@

### debian/ubuntu

This should suffice:
$ sudo apt-get install git libssl-dev python3-dev python3-pip
$ sudo pip3 install -r requirements.txt

$ sudo apt-get install git libssl-dev python-dev python-pip
$ sudo pip install -r requirements.txt

### arch

# pacman -S --needed python2 python2-psutil python2-urwid python2-twisted python2-service-identity python2-feedparser python2-pyopenssl
# pacman -S --needed python python-psutil python-urwid python-twisted python-service-identity python-feedparser python-pyopenssl

The `--needed` flag will skip packages already installed.

### centos

CentOS and some other distros ship an older version of python. First check you have python 2.6 or 2.7:

$ python2.6 -V
$ python2.7 -V

If at least one of them works, you should be able to do:

$ sudo yum install python-devel
$ sudo easy_install pip
$ sudo pip install -r requirements.txt

Otherwise, you need to install python 2.7. A decent guide for centos is
[located here](http://toomuchdata.com/2012/06/25/how-to-install-python-2-7-3-on-centos-6-2/). Be sure to follow the
instructions for installing distribute also.

Next, install twisted from the package on [their website](http://twistedmatrix.com/). Don't use easy_install - you
won't get the binaries that ship with twisted.

easy_install for python 2.7 is probably in `/usr/local/bin/easy_install-2.7`. You should use it to install the remaining
mark2 dependencies:

$ sudo /usr/local/bin/easy_install-2.7 psutil urwid feedparser
$ sudo yum install python3-devel
$ sudo yum install python3-pip
$ sudo pip3 install -r requirements.txt

## installation

Expand Down
32 changes: 28 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,18 @@
mark2 is a minecraft server wrapper, written in python and twisted. It aims to be *the* definitive wrapper, providing a
rich feature-set and a powerful plugin interface. It has no requirement on craftbukkit.

see [INSTALL.md](INSTALL.md) for requirements and installation instructions
See [INSTALL.md](INSTALL.md) for requirements and installation instructions

see [USAGE.md](USAGE.md) for details on how to use mark2
See [USAGE.md](USAGE.md) for details on how to use mark2

## features
## Features

* Your server runs in the background
* Multiple users can attach at once, with their own local prompt and command buffer
* Built in monitoring using cpu, memory, players and connectivity
* Rich screen/tmux-like client with built-in monitoring, tab-complete, command history, etc

## plugins
## Plugins

* Powerful scheduling plugin, with a cron-like syntax. You can hook onto events like `@serverstopped` to run a
cartograph, or run `save` on an interval
Expand All @@ -45,3 +45,27 @@ see [USAGE.md](USAGE.md) for details on how to use mark2
* Back up your map and server log when the server stops
* Print a random message at an interval, e.g. '[SERVER] Lock your chests with /lock'
* Respond to user commands, e.g. '<Notch> !teamspeak' could `msg Notch Join our teamspeak server at xyz.com`

## Common Issues

### `ServerStarted` event does not run scripts properly.

This can happen due to the done message in the prompt from starting the server not being caught. Edit the `mark2.properties` in the server directory and add a line like the following that matches the "Done" message for when the server fully starts.

A typical done message regex looks like this: `mark2.service.process.done-pattern=\\[(.*?)\\]: Done \\(([0-9]*\.?[0-9]*)s\\)\\!.*`

### mark2 says server may have crashed or is not responding
The regex for the unknown command message is broken. In order to set it for that server, edit the `mark2.properties` in the server directory and add a line like the following that matches the unknown command message:

`plugin.monitor.crash-unknown-cmd-message=\\[(.*?)\\]: Unknown command.*`

### Player list on the right hand side is empty
This happens when the join/quit regexes are not set properly for that server. Edit the `mark2.properties` in the server directory and add a line like the following that matches the join/quit messages in the console:

Typical join regex: `mark2.regex.join=\\[(.*)\\]: (?P<username>[A-Za-z0-9_]{1,16}).*\\[\/(?P<ip>[0-9.:%]*)\\] logged in with entity id .+`

Typical leave regex: `mark2.regex.quit=\\[(.*)\\]: (?P<username>[A-Za-z0-9_]{1,16}) lost connection: (?P<reason>.+)`

### Missing process information in the right side panel

This usually happens when the `psutils` module is installed incorrectly or for the wrong python version. You should double check you installed it properly using `pip install psutil` on ubunutu or install it manually in the python 2 environment
2 changes: 1 addition & 1 deletion mark2
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python2
#!/usr/bin/env python3
import sys
from mk2.launcher import main

Expand Down
53 changes: 26 additions & 27 deletions mk2/events/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
import itertools
import sys
import time
import json

from twisted.internet import reactor, task
from twisted.internet.defer import succeed, maybeDeferred


class _EventArg(object):
class _EventArg:
def __init__(self, default=None, required=False):
self.default = default
self.required = required
Expand All @@ -29,9 +30,7 @@ def __init__(cls, name, bases, dict_):
return type.__init__(cls, name, bases, dict)


class Event(object):
__metaclass__ = EventMetaclass

class Event(metaclass=EventMetaclass):
Arg = _EventArg

EAT = 1
Expand All @@ -43,15 +42,15 @@ def __init__(self, d={}, **args):
args.update(d)
self._args = {}

missing = set(self._requires) - set(args.iterkeys())
excess = set(args.iterkeys()) - set(self._contains)
missing = set(self._requires) - set(args.keys())
excess = set(args.keys()) - set(self._contains)
if missing:
raise Exception("Event type {0} missing argument(s): {1}".
format(self.__class__.__name__, ", ".join(missing)))
raise Exception("Event type {} missing argument(s): {}"
.format(self.__class__.__name__, ", ".join(missing)))
elif excess:
raise Exception("Event type {0} got extraneous argument(s): {1}".
format(self.__class__.__name__, ", ".join(excess)))
for k, v in args.iteritems():
raise Exception("Event type {} got extraneous argument(s): {}"
.format(self.__class__.__name__, ", ".join(excess)))
for k, v in args.items():
setattr(self, k, v)

self.setup()
Expand All @@ -66,16 +65,16 @@ def __getitem__(self, item):
def _prefilter_argcheck(cls, args):
spec = inspect.getargspec(cls.prefilter)

args = set(args.iterkeys())
args = set(args.keys())
required_args = set(spec.args[1:-len(spec.defaults or [])])

if required_args - args:
return (False, "missing arguments for prefilter: {0}".format(
return (False, "missing arguments for prefilter: {}".format(
", ".join(required_args - args)))
if spec.keywords is None:
allowed_args = set(spec.args[1:])
if args - allowed_args:
return (False, "excess arguments for prefilter: {0}".format(
return (False, "excess arguments for prefilter: {}".format(
", ".join(args - allowed_args)))
return (True, "")

Expand All @@ -86,20 +85,20 @@ def setup(self):
pass

def serialize(self):
data = dict((k, getattr(self, k)) for k in self._contains)
data = {k: getattr(self, k) for k in self._contains}
data['class_name'] = self.__class__.__name__
return data

def __repr__(self):
return "{0}({1})".format(self.__class__.__name__, self.serialize())
return "{}({})".format(self.__class__.__name__, self.serialize())


class EventPriority:
def __init__(self, priority=None, monitor=False):
self.priority, self.monitor = priority, monitor

def __str__(self):
return "P{0}".format(self.priority)
return "P{}".format(self.priority)

def __repr__(self):
return str(self)
Expand Down Expand Up @@ -131,7 +130,7 @@ def _invalidate(self):
def _build_cache(self):
def key(i):
return i[1][0].priority
handlers = itertools.groupby(sorted(self._handlers.iteritems(),
handlers = itertools.groupby(sorted(self._handlers.items(),
key=key,
reverse=True), key)
handlers = (l for group, l in handlers)
Expand Down Expand Up @@ -164,7 +163,7 @@ def add_handler(self, priority, *a):
return i

def remove_handler(self, id_):
assert id_ in self._handlers, "{0} is not registered".format(id_)
assert id_ in self._handlers, "{} is not registered".format(id_)
self._invalidate()
del self._handlers[id_]
self._istack.append(id_)
Expand Down Expand Up @@ -210,7 +209,7 @@ def unregister(self, id_):
def _next_event(self, event, iter_, handled=False):
while True:
try:
id_, callback, args = iter_.next()
id_, callback, args = next(iter_)
except StopIteration:
return succeed(handled)
if event.prefilter(**args):
Expand Down Expand Up @@ -276,10 +275,10 @@ def from_json(data):
data = json.loads(data)
return get_by_name(data['name'])(**data['data'])

from console import *
from error import *
from hook import *
from player import *
from server import *
from stat import *
from user import *
from .console import *
from .error import *
from .hook import *
from .player import *
from .server import *
from .stat import *
from .user import *
2 changes: 1 addition & 1 deletion mk2/events/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class PlayerDeath(PlayerEvent):
format = Event.Arg(default="{username} died")

def get_text(self, **kw):
d = dict(((k, getattr(self, k)) for k in ('username', 'killer', 'weapon')))
d = {k: getattr(self, k) for k in ('username', 'killer', 'weapon')}
d.update(kw)
return self.format.format(**d)

Expand Down
Loading

0 comments on commit 4b151cd

Please sign in to comment.