diff --git a/CHANGELOG.md b/CHANGELOG.md
index d75ff5a8..06d8592f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,22 @@
#Changelog#
+
+
1.0.19 rc 28
+Bugfixes:
+- Bugfix commands.py line 784 where player message is used with no argument.
+- fix player to player teleport ValueError bug caused by trying to read coordinates
+ where only a player name was given ("[lukeeexd: Teleported lukeeexd to Nyaii]")
+- Fix Chat.py plugin (all player's were sharing the same chat configuration).
+- Fix Chat.py breaking on /reload.
+- bugfix message from offline wrapper that is a hub in mcserver.py.
+- changed deop to allow any vanilla level 4 OP to run it.
+- Explicitly `close()` sockets that were shutdown.
+- substitute 'localhost' for code occurences of '127.0.0.1'.
+New Plugin:
+- add Geode plugin that prints each player's IP and country code at login.
+
+1.0.17-18 rc 22-23
+-bugfix for non-proxy setups. See Dev changelogs (on development branch).
+
1.0.15 rc 20
Primary reasons for update:
- Regular update prior to further new Wrapper development
diff --git a/Wrapper.py b/Wrapper.py
index b391a46b..0fd85587 100644
Binary files a/Wrapper.py and b/Wrapper.py differ
diff --git a/build/CHANGELOG.DEV.md b/build/CHANGELOG.DEV.md
index 84f372f3..3e5b2038 100644
--- a/build/CHANGELOG.DEV.md
+++ b/build/CHANGELOG.DEV.md
@@ -1,4 +1,43 @@
+Build 28, 1.0.19 RC 28
+- Bugfix commands.py line 784 where player message is used with no argument.
+- Update Master branch
+
+Build 27
+- increment version to 1.0.18 RC 27
+- fix player to player teleport ValueError bug caused by trying to read coordinates
+ where only a player name was given ("[lukeeexd: Teleported lukeeexd to Nyaii]")
+- create PR to development.
+
+Build 26
+- Fix Chat.py plugin (all player's were sharing the same chat configuration).
+- Fix Chat.py breaking on /reload.
+- bugfix message from offline wrapper that is a hub in mcserver.py.
+- changed deop to allow any vanilla level 4 OP to run it.
+- add Geode plugin that prints each player's IP and country code at login.
+
+Build 25
+- Explicitly `close()` sockets that were shutdown.
+- substitute 'localhost' for code occurences of '127.0.0.1'.
+
+Build 24
+Version number bumps to match Master 1.0.17 RC 24
+
+Build 23
+- Bugfixes:
+ - at player logout (mcserver.py), server would attempt to run
+ proxy method removestaleclients(), even if proxy mode was not running.
+ - mcserver.py getplayer() not returning a player object in non-proxy mode.
+
+Build 22
+- Implement the proxy host as a ProcessPoolExecutor multiprocessor (only on Python3)
+
+Build 21 (In-process Dev build) [1.0.16 RC 21]
+- Refractor proxy and remove external "ServerVitals" class and integrate wrapper into proxy again.
+
+Build 21 [1.0.16 RC 21] (Patch to Master)
+- Bugfix - at player logout (mcserver.py), server would attempt to run
+ proxy method removestaleclients(), even if proxy mode was not running.
Starting with:
-Build 21 [1.0.15 RC 20] - Development branch update
+Build 20 [1.0.15 RC 20] - Development branch update
- includes first version of vanilla claims plugin.
diff --git a/build/Wrapper.py.md5 b/build/Wrapper.py.md5
index bf9613f9..d8379bcc 100644
--- a/build/Wrapper.py.md5
+++ b/build/Wrapper.py.md5
@@ -1 +1 @@
-d5eda047085fd61c6a705dbeb4ca6ec7
\ No newline at end of file
+d5aca2e96299c3d95a332fdf0b119b75
\ No newline at end of file
diff --git a/build/buildinfo.py b/build/buildinfo.py
index c6b6fc19..5d31059f 100644
--- a/build/buildinfo.py
+++ b/build/buildinfo.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Do not edit this file to bump versions; it is built automatically
-__version__ = [1, 0, 15, 'rc', 20]
+__version__ = [1, 0, 19, 'rc', 28]
__branch__ = 'stable'
diff --git a/build/version.json b/build/version.json
index 45fa2fe6..1dc4bc97 100644
--- a/build/version.json
+++ b/build/version.json
@@ -4,11 +4,11 @@
"__version__": [
1,
0,
- 15,
+ 19,
"rc",
- 20
+ 28
],
"build": 229,
- "release_time": 1526743791.661702,
+ "release_time": 1534692383.768469,
"repotype": "stable"
}
\ No newline at end of file
diff --git a/docs/Wrapper.py.md5 b/docs/Wrapper.py.md5
index bf9613f9..d8379bcc 100644
--- a/docs/Wrapper.py.md5
+++ b/docs/Wrapper.py.md5
@@ -1 +1 @@
-d5eda047085fd61c6a705dbeb4ca6ec7
\ No newline at end of file
+d5aca2e96299c3d95a332fdf0b119b75
\ No newline at end of file
diff --git a/documentation/player.rst b/documentation/player.rst
index d188d321..233a8993 100644
--- a/documentation/player.rst
+++ b/documentation/player.rst
@@ -85,7 +85,7 @@
..
-- connect(self, ip="127.0.0.1", port=25600)
+- connect(self, ip="localhost", port=25600)
Connect to another server. Upon calling, the client's current
server instance will be closed and a new server connection made
diff --git a/stable-plugins/Geode.py b/stable-plugins/Geode.py
new file mode 100644
index 00000000..0477ff71
--- /dev/null
+++ b/stable-plugins/Geode.py
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+
+# pip install --user pygeoip
+try:
+ import pygeoip
+except ImportError:
+ pygeoip = False
+ DEPENDENCIES = ["ImportError: could not import package pygeoip", ]
+
+NAME = "Geode"
+AUTHOR = "SurestTexas00"
+ID = "com.suresttexas00.plugins.geode"
+VERSION = (0, 1, 0)
+SUMMARY = "Lookup player's country based on ip."
+WEBSITE = ""
+DESCRIPTION = """
+Test plugin to lookup player's country using pygeoip.
+"""
+
+
+# noinspection PyPep8Naming,PyMethodMayBeStatic,PyUnusedLocal
+# noinspection PyClassicStyleClass,PyAttributeOutsideInit
+class Main:
+ def __init__(self, api, log):
+ self.api = api
+ self.minecraft = api.minecraft
+ self.log = log
+
+ def onEnable(self):
+ self.api.registerEvent("player.login", self.login)
+ self.data_storageobject = self.api.getStorage(
+ "geode", world=False, pickle=False
+ )
+ self.data = self.data_storageobject.Data
+ self.gi = pygeoip.GeoIP('/usr/share/GeoIP/GeoIP.dat',
+ flags=pygeoip.const.MMAP_CACHE)
+
+ def onDisable(self):
+ self.data_storageobject.close()
+
+ def login(self, payload):
+ playerObj = payload["player"]
+ print(playerObj.ipaddress)
+ x = self.gi.country_code_by_addr(playerObj.ipaddress)
+ self.log.info(
+ "%s logged on from an ip (%s) in country '%s'." % (
+ playerObj.username, playerObj.ipaddress, x)
+ )
diff --git a/stable-plugins/chat.py b/stable-plugins/chat.py
index a95eeacd..7372d49a 100644
--- a/stable-plugins/chat.py
+++ b/stable-plugins/chat.py
@@ -1,5 +1,6 @@
# coding=utf-8
+import copy
import sys
PY3 = sys.version_info[0] > 2
@@ -21,25 +22,25 @@
SECT = u'\xa7'
-# noinspection PyPep8Naming,PyCompatibility
+# noinspection PyPep8Naming,PyMethodMayBeStatic,PyUnusedLocal
+# noinspection PyClassicStyleClass,PyAttributeOutsideInit
class Main:
def __init__(self, api, log):
+
self.api = api
self.log = log
- self.ranks = {}
- self.player_ranks = {}
- self.default = {
- "trans": False,
- "isOp": False,
- "rank": None,
- "color": "f" # white
- }
def onEnable(self):
self.api.registerEvent("player.chatbox", self.playerChatBox)
- self.api.registerEvent("player.login", self.login)
self.api.registerEvent("player.logout", self.logout)
+ self.player_ranks = {}
+ self.default = {
+ "trans": False,
+ "isOp": False,
+ "rank": None,
+ "color": "f" # white
+ }
self.ranks = [ # from highest to lowest
# perm display rank display color
{"perm": "owner", "rank": "Owner", "color": "4"},
@@ -55,12 +56,11 @@ def onEnable(self):
def onDisable(self):
pass
- def login(self, payload):
- """ Obtain the player's rank when he logs in """
- player = payload["player"]
- uuid = player.uuid
- if uuid not in self.player_ranks:
- self.player_ranks[uuid] = self.default
+ def verify(self, player):
+ """ Obtain the player's rank """
+ if player.uuid not in self.player_ranks:
+ uuid = player.uuid
+ self.player_ranks[uuid] = copy.copy(self.default)
if player.isOp():
self.player_ranks[uuid]["isOp"] = True
@@ -85,8 +85,8 @@ def playerChatBox(self, payload):
""" We can modify the chat.
All the permissions legwork that could slow up the code
- is already done just once at login.. we have to keep this
- packet moving to prevent lag!
+ is done just once when player chat is first used..
+ we have to keep this packet moving to prevent lag!
{'translate': 'chat.type.text',
'with': [__[0]__{'clickEvent': {'action': 'suggest_command',
@@ -103,6 +103,7 @@ def playerChatBox(self, payload):
player = payload["player"]
data = payload["json"]
+ self.verify(player)
if "translate" in data: # special type of chat
@@ -124,7 +125,7 @@ def playerChatBox(self, payload):
# chatdisplayname[0]
insertionplayer = self.api.minecraft.getPlayer(insertionplayername) # noqa
-
+ self.verify(insertionplayer)
# permanently tag OP suffix
if self.player_ranks[insertionplayer.uuid]["isOp"]:
data["with"][0]["text"] = "%s §8[OP]§r" % chatdisplayname
diff --git a/stable-plugins/vanillaclaims.py b/stable-plugins/vanillaclaims.py
new file mode 100644
index 00000000..1eeb385d
--- /dev/null
+++ b/stable-plugins/vanillaclaims.py
@@ -0,0 +1,900 @@
+# -*- coding: utf-8 -*-
+
+import time
+import threading
+
+NAME = "VanillaClaims"
+AUTHOR = "SurestTexas00"
+ID = "com.suresttexas00.vanillaclaims"
+VERSION = (0, 9, 0)
+SUMMARY = "Simple player-friendly land claim system"
+WEBSITE = ""
+DESCRIPTION = "Uses regions.py as the backend for protecting player claims."
+DEPENDENCIES = ["regions.py", ]
+
+BEDROCK = 7
+GOLDBLOCK = 41
+DIAMONDBLOCK = 57
+LITREDSTONEORE = 74
+
+
+# The specific errors we need not worry about in the plugin API:
+# noinspection PyMethodMayBeStatic,PyUnusedLocal
+# noinspection PyPep8Naming,PyClassicStyleClass,PyAttributeOutsideInit
+class Main:
+ def __init__(self, api, log):
+ self.api = api
+ self.log = log
+
+ self.userperm = "vclaims.use" # change to None for anyone to access.
+
+ # claim blocks configuration
+ self.defaultclaimblocks = 2048 # the starting number of blocks
+ self.actionsperblock = 50 # - sets the rate of block accumulation
+ self.maxclaimblocks = 200000 # - determine max earned claim blocks
+ # These prevent claims abuse or spurious annoyance-type claims
+ self.maxclaims = 5 # - max claims per player
+ self.minclaimsize = 81 # - minimum claim size
+ self.minclaimwidth = 6 # - minimum claim width
+
+ # temporary run-time player data
+ self.player_dat = {}
+
+ def onEnable(self):
+ # get the regions plugin:
+ self.regions = self.api.getPluginContext("com.suresttexas00.regions")
+ if self.regions.version < 1.3:
+ self.log.error(
+ "Regions.py is out of date!, Vanilla Claims not enabled."
+ )
+ return False
+
+ # init storage data
+ self.data_storageobject = self.api.getStorage(
+ "claimdata", world=False, pickle=False)
+ self.data = self.data_storageobject.Data
+
+ self.api.registerEvent("player.place", self.action_place)
+ self.api.registerEvent("player.spawned", self.playerSpawned)
+ self.api.registerEvent("player.dig", self.action_dig)
+
+ user = self.userperm
+ admin = "vclaims.admin"
+
+ self.api.registerHelp(
+ "VanillaClaims", "Claim based grief prevention system.", [
+ ("/abandonclaim",
+ "Abandon the claim you are standing in.", user),
+ ("/abandonallclaims",
+ "Abandon all claims you own.", user),
+ ("/claimblocks",
+ "View your claims blocks information.", user),
+ ("/trust ",
+ "Allow player full access to your claim.", user),
+ ("/breaktrust ",
+ "Allow player to break blocks on your claim.", user),
+ ("/placetrust ",
+ "Allow player to place blocks / operate things.", user),
+ ("/accesstrust ",
+ "Allow player interaction (place lava, eat, throw pearls, etc)", # noqa
+ user),
+ ("/untrust ",
+ "remove a player from your claim.", user),
+ ("/trustlist",
+ "Display the claim's player information.", user),
+ ("/show",
+ "Show the claim you are standing in.", user),
+ ("/spade",
+ "Gives the land claim gold shovel", user),
+ ("/adjustclaimblocks ",
+ "Adjust player claim blocks.", admin),
+ ("/transferclaim ",
+ "re-creates the same claim in another's name",
+ admin),
+ ("/deleteclaim",
+ "Delete the claim you are standing in", admin),
+ ("/deleteallclaims ",
+ "Delete all a players claims.", admin)
+ ])
+
+ self.api.registerCommand(
+ "show", self._show_comm, user)
+ self.api.registerCommand(
+ ("spade", "wand", "shovel"), self._spade, user)
+ self.api.registerCommand(
+ ("abandonclaim", "abandonclaims"), self._abandonclaim_comm, user)
+ self.api.registerCommand(
+ "abandonallclaims", self._abandonallclaims_comm, user)
+ self.api.registerCommand(
+ "deleteclaim", self._deleteclaim_comm, admin)
+ self.api.registerCommand(
+ "deleteallclaims", self._deleteallclaims_comm, admin)
+ self.api.registerCommand(
+ "adjustclaimblocks", self._adjustclaimblocks_comm, admin)
+ self.api.registerCommand(
+ "transferclaim", self._transferclaim_comm, admin)
+ self.api.registerCommand(
+ ("claimblocks", "claimblock", "claimsblock", "claimsblocks"),
+ self._claimblocks_comm, user)
+ self.api.registerCommand(
+ "trust", self._trust_comm, user)
+ self.api.registerCommand(
+ "breaktrust", self._breaktrust_comm, user)
+ self.api.registerCommand(
+ "placetrust", self._placetrust_comm, user)
+ self.api.registerCommand(
+ "accesstrust", self._accesstrust_comm, user)
+ self.api.registerCommand(
+ "untrust", self._untrust_comm, user)
+ # self.api.registerCommand("trustlist", self._trustlist_comm, user)
+
+ self.run = True
+ self.action_queue = []
+ tr = threading.Thread(target=self._track_activity,
+ name="trackblocks", args=())
+ tr.daemon = True
+ tr.start()
+
+ def onDisable(self):
+ self.run = False
+ self.data_storageobject.close()
+
+ def get_claim_data(self, playerobj):
+ """
+ Get the player's claim data.
+
+ :param playerobj:
+ :returns: A dictionary of player claim data.
+
+ """
+ try:
+ return self.data[playerobj.uuid]
+ except KeyError:
+ self.data[playerobj.uuid] = {
+ "blocks": self.defaultclaimblocks,
+ "blocksused": 0,
+ "activity": 0,
+ "playername": playerobj.username,
+ "claimlist": [],
+ "claiminfo": {},
+ "laston": time.time(),
+ "admin": playerobj.hasPermission("vclaims.admin")
+ }
+ return self.data[playerobj.uuid]
+
+ def get_player_data(self, name):
+ """
+ Get the player's selection data. Selection data is not saved
+ between reboots.
+
+ :param name: player name.
+
+ :returns: A dictionary of player selection data.
+ {
+ "point1"
+ "point2"
+ "dim1"
+ "dim2"
+ "mode" # selection modes ...
+ "point" # which point is being selected
+ "proposed" # cubic tuple (a set of hi/low coords)
+ "rgedit" name of region being edited/resized
+ }
+ """
+ try:
+ return self.player_dat[name]
+ except KeyError:
+ self.player_dat[name] = {}
+ self._finishwithselectionmode(name)
+ return self.player_dat[name]
+
+ def _track_activity(self):
+ """
+ Each item is a playeruuid, player object entry.
+ """
+
+ while self.run:
+ time.sleep(.4)
+ self._on_timer()
+ time.sleep(.4)
+ self._on_timer()
+ while len(self.action_queue) > 0:
+ # grab next change
+ player = self.action_queue.pop(0)
+ p = self.get_claim_data(player)
+ # block increaser
+ p["activity"] += 1
+ activities = p["activity"]
+ if activities % self.actionsperblock is not 0:
+ continue
+ p["activity"] = 0
+ if p["blocks"] < self.maxclaimblocks:
+ p["blocks"] += 1
+
+ def _on_timer(self):
+ """
+ Puts each player in or out of claims mode.
+ Modes:
+ None: has no shovel
+ Idle: has shovel, no action taken yet
+
+ """
+ while self.run:
+ time.sleep(.5)
+ for players in self.api.minecraft.getPlayers():
+ player = self.api.minecraft.getPlayer(players)
+ try:
+ itemid = player.getHeldItem()["id"]
+ except AttributeError:
+ # probably a bad player object
+ continue
+
+ p = self.get_player_data(player.username)
+
+ # "mode" = selection mode
+ if itemid == 284 and p["mode"] is None:
+ player.message(
+ "&2Claims shovel active... Click an area to edit "
+ "or to claim."
+ )
+ p["mode"] = "idle"
+
+ if itemid != 284 and p["mode"]:
+ player.message(
+ "&2Shovel put away... Switching out of claims "
+ "mode"
+ )
+ self._finishwithselectionmode(player.username)
+
+ def playerSpawned(self, payload):
+ try:
+ player = payload["player"]
+ except AttributeError:
+ self.log.error("VanillaClaims player spawn not successful. "
+ "Payload: %s" % payload)
+ return
+ cl = self.get_claim_data(player)
+ cl["laston"] = time.time()
+ cl["admin"] = player.hasPermission("vclaims.admin")
+
+ def action_dig(self, payload):
+ try:
+ player = payload["player"]
+ action = payload["action"]
+ itemid = player.getHeldItem()["id"]
+ except AttributeError:
+ # probably a bad player object
+ return False
+ if itemid == 284:
+ if action == "begin_break":
+ try:
+ position = payload["position"]
+ dim = player.getDimension()
+ except AttributeError:
+ return False
+ self.wand_use(player, player.uuid, position, dim)
+ return False
+
+ # update activity
+ if action == "end_break":
+ self.action_queue.append(player)
+
+ def action_place(self, payload):
+ try:
+ player = payload["player"]
+ itemid = player.getHeldItem()["id"]
+ except AttributeError:
+ return False
+
+ if itemid == 284:
+ try:
+ dim = int(player.getDimension())
+ clickposition = payload["clickposition"]
+ except AttributeError:
+ return False
+ self.wand_use(player, player.uuid, clickposition, dim)
+ # never allow gold shovel use - reserved for claims
+ return False
+ self.action_queue.append(player)
+
+ def wand_use(self, player, playeruuid, position, dim):
+ """
+
+ :param player:
+ :param playeruuid:
+ :param position:
+ :param dim:
+ :return:
+ """
+
+ p = self.get_player_data(player.username)
+ cl = self.get_claim_data(player)
+
+ # point = self.data[playeruuid]["point"]
+ # mode = p["mode"]
+ anyregion = self.regions.regionname(position, dim)
+ if anyregion:
+ region_owner_uuid = self.regions.getregioninfo(
+ anyregion, "ownerUuid"
+ )
+ else:
+ region_owner_uuid = False
+
+ # find the selection mode
+ # first click point1 determines the selection mode
+ if p["point"] == "point1":
+ # If not your claim, draw it and go back to idle mode
+ if region_owner_uuid and region_owner_uuid != playeruuid:
+ # TODO draw the claim you are in, message with "not your claim"
+ otheruuid = self.regions.getregioninfo(
+ anyregion, "ownerUuid"
+ )
+ othername = self.api.minecraft.lookupbyUUID(otheruuid)
+ player.message("&cThis area is claimed by %s..." % othername)
+ point1 = self.regions.getregioninfo(
+ anyregion, "pos1"
+ )
+ point2 = self.regions.getregioninfo(
+ anyregion, "pos2"
+ )
+ x = int(position[0])
+ y = int(position[1]) - 1
+ z = int(position[2])
+ self._show(player, (x, y, z), point1, point2)
+ self._reset_selections(playeruuid)
+ p["mode"] = "idle"
+ return
+ # if unclaimed, go to 'new' mode
+ elif not anyregion and p["mode"] == "idle":
+ p["mode"] = "new"
+ return
+ # If your claim, then go to 'edit' mode (but don't make first point)
+ elif region_owner_uuid == playeruuid and p["mode"] == "idle":
+ p["mode"] = "edit"
+ p["rgedit"] = anyregion
+ # TODO STUFF to draw claim, place edit markers
+ player.sendBlock(cl["claiminfo"][anyregion]["handle1"],
+ LITREDSTONEORE, 0)
+ player.sendBlock(cl["claiminfo"][anyregion]["handle2"],
+ LITREDSTONEORE, 0)
+ player.message(
+ {
+ "text":
+ "You are now editing the claim marked by the "
+ "restone corners. Select a new corner (to cancel, "
+ "put shovel away).",
+ "color": "gold"
+ }
+ )
+ return
+ else:
+ # -we know it is not claimed (or is owned by player)
+ # only successful selection as point1 enables point2
+ p["point1"] = position
+ p["dim1"] = dim
+ p["point"] = "point2"
+ # re-draw new point1 as point1 color (diamond)
+ player.sendBlock(p["point1"], DIAMONDBLOCK, 0)
+ return
+ elif p["point"] == "point2":
+ # If not your claim, draw the conflicting claim
+ if region_owner_uuid and region_owner_uuid != playeruuid:
+ # TODO draw the claim you are in, message with "not your claim"
+ return
+ p["point2"] = position
+ p["dim2"] = dim
+ # Stay at point two until successful (unless user cycles wand)
+ p["point"] = "point2"
+ # UNLESS, they re-select point1:
+ if p["point2"] == p["point1"]:
+ p["point"] = "point1"
+ # TODO tell player to continue with selecting first point.
+ return
+ # or dimensions don't match:
+ if p["dim1"] != p["dim2"]:
+ self._reset_selections(playeruuid)
+ p["mode"] = "idle"
+ return
+ # We now have a 'tentative' claim we can validate:
+ # We know it's corner points were not claimed... but:
+ p["proposed"] = self.regions.stat_normalize_selection(
+ p["point1"], p["point2"]
+ )
+ newclaim = self._claim(player)
+ if newclaim:
+ # player.sendBlock(position, GOLDBLOCK, 0)
+ player.message("&6Second Corner selected.")
+ player.message("&6Claim action successful.")
+
+ pos1 = cl["claiminfo"][newclaim]["handle1"]
+ pos2 = cl["claiminfo"][newclaim]["handle2"]
+
+ player.sendBlock(pos1, DIAMONDBLOCK, 0)
+ player.sendBlock(pos2, GOLDBLOCK, 0)
+
+ low = self.regions.getregioninfo(newclaim, "pos1")
+ high = self.regions.getregioninfo(newclaim, "pos2")
+ x = int(pos2[0])
+ y = int(pos2[1]) - 1
+ z = int(pos2[2])
+ self._show(player, (x, y, z), low, high)
+ p["mode"] = None
+ p["point"] = "point1"
+ return
+ if newclaim is False:
+ player.message("&cClaim action failed.")
+ player.message(
+ {
+ "text": "Change or edit selection area by selecting"
+ " a restone corner and then selecting a "
+ "new spot", "color": "yellow"
+ }
+ )
+ player.sendBlock(
+ p["point1"],
+ LITREDSTONEORE, 0
+ )
+ player.sendBlock(
+ p["point2"],
+ LITREDSTONEORE, 0
+ )
+ self.data[playeruuid]["point"] = "error"
+ return
+
+ def _claim(self, player):
+ playerid = player.uuid
+ p = self.get_player_data(player.username)
+ cl = self.get_claim_data(player)
+ # 1) calculate the claim size parameters
+ lowcoord = p["proposed"][0]
+ highcoord = p["proposed"][1]
+ blocks, length, width = self._getsizeclaim(lowcoord, highcoord)
+ playersblocks = cl["blocks"]
+ usedblocks = cl["blocksused"]
+ if p["mode"] == "edit":
+ # credit back blocks used by an existing claim being edited.
+ pos1 = self.regions.getregioninfo(p["rgedit"], "pos1")
+ pos2 = self.regions.getregioninfo(p["rgedit"], "pos2")
+ x_dia = pos2[0] - pos1[0]
+ z_dia = pos2[2] - pos1[2]
+ usedblocks -= (x_dia * z_dia)
+
+ if blocks < self.minclaimsize:
+ player.message(
+ "&cClaim (%d) is not minimum size of at least %d blocks." % (
+ blocks, self.minclaimsize
+ )
+ )
+ return False
+
+ if length < self.minclaimwidth or width < self.minclaimwidth:
+ player.message(
+ "&cClaim has to be at least %d blocks wide all "
+ "around." % self.minclaimwidth
+ )
+ return False
+
+ if blocks > playersblocks - usedblocks:
+ player.message(
+ "&cYou do not have enough blocks to make this claim."
+ )
+ player.message("&eYou have: %d" % playersblocks)
+ player.message("&eYou need: %d" % blocks)
+ return False
+
+ # 2) look for intersecting regions
+ collisions = self.regions.intersecting_regions(
+ p["dim1"], lowcoord, highcoord, rect=True
+ )
+ if collisions:
+ if p["mode"] == "edit" and len(
+ collisions) < 2 and p["rgedit"] in collisions:
+ collisions.remove(p["rgedit"])
+ if len(collisions) > 0:
+ player.message("&cArea overlaps region(s):")
+ player.message("&5%s" % str(collisions).replace("u'", "'"))
+ return False
+
+ if p["mode"] == "edit":
+ self._delete_claim(player, p["rgedit"], playerid)
+
+ # get a new claims region name
+ thisclaimname, humanname = self._get_claimname(
+ playerid, cl["admin"]
+ )
+ if not thisclaimname:
+ player.message(
+ "&cyou have claimed the maximum number of areas "
+ "(%s)" % self.maxclaims
+ )
+ return False
+ # 3) inspections passed, claim allowed.
+ lowcorner = (lowcoord[0], 5, lowcoord[2])
+ highcorner = (highcoord[0], 255, highcoord[2])
+ handle1 = p["point1"]
+ handle2 = p["point2"]
+ self.regions.rgdefine(
+ thisclaimname, playerid, p["dim1"], lowcorner, highcorner
+ )
+ self.regions.protection_on(thisclaimname)
+ player.message(
+ "&2Region &5%s&2 created and protected." % thisclaimname
+ )
+
+ cl["claimlist"].append(thisclaimname)
+ cl["claiminfo"][thisclaimname] = {}
+ cl["claiminfo"][thisclaimname]["handle1"] = handle1
+ cl["claiminfo"][thisclaimname]["handle2"] = handle2
+ cl["blocksused"] += blocks
+
+ self._reset_selections(player.username)
+
+ p["mode"] = None
+ return thisclaimname
+
+ def _check_username(self, playerobj, args, usage_msg, arg_count=1):
+ if len(args) < arg_count:
+ playerobj.message("&cUsage: %s" % usage_msg)
+ return False
+ targetuuid = str(self.api.minecraft.lookupbyName(args[0]))
+ targetname = self.api.minecraft.lookupbyUUID(targetuuid)
+ if not targetuuid or targetname.lower() != args[0].lower():
+ playerobj.message("&cinvalid username.")
+ return False
+ return targetname, targetuuid
+
+ def _check_regionname(self, player):
+ try:
+ position = player.getPosition()
+ dim = player.getDimension()
+ except AttributeError:
+ return False
+ regionname = self.regions.regionname(position, dim)
+ if regionname:
+ return regionname, position, dim
+ else:
+ player.message("&cYou are not standing in a claim.")
+ return False
+
+ def _trust_comm(self, *args):
+ player = args[0]
+ try:
+ targetname, targetuuid = self._check_username(
+ player, args[1], "&/trust ")
+ regionname, position, dim = self._check_regionname(player)
+ except TypeError:
+ return
+
+ owner = self.regions.getregioninfo(regionname, "ownerUuid")
+ playeruuid = str(player.mojangUuid)
+ if playeruuid != owner:
+ player.message("&cThis is not your claim.")
+ return
+ self.regions.rgedit(
+ regionname, playername=targetname,
+ addbreak=True, addplace=True, addaccess=True
+ )
+ player.message(
+ "&e%s has been granted full access to this claim." % targetname
+ )
+
+ def _untrust_comm(self, *args):
+ player = args[0]
+ try:
+ targetname, targetuuid = self._check_username(
+ player, args[1], "/untrust ")
+ regionname, position, dim = self._check_regionname(player)
+ except TypeError:
+ return
+
+ owner = self.regions.getregioninfo(regionname, "ownerUuid")
+ playeruuid = str(player.mojangUuid)
+ if playeruuid != owner:
+ player.message("&cThis is not your claim.")
+ return
+ self.regions.rgedit(
+ regionname, playername=targetname, remove=True
+ )
+ player.message("&e%s has been removed from this claim." % targetname)
+
+ def _breaktrust_comm(self, *args):
+ player = args[0]
+ try:
+ targetname, targetuuid = self._check_username(
+ player, args[1], "/breaktrust ")
+ regionname, position, dim = self._check_regionname(player)
+ except TypeError:
+ return
+
+ owner = self.regions.getregioninfo(regionname, "ownerUuid")
+ playeruuid = str(player.mojangUuid)
+ if playeruuid != owner:
+ player.message("&cThis is not your claim.")
+ return
+ self.regions.rgedit(
+ regionname, playername=targetname, addbreak=True
+ )
+ player.message(
+ "&e%s added to this claim. Player can now break items "
+ "here." % targetname
+ )
+
+ def _placetrust_comm(self, *args):
+ player = args[0]
+ try:
+ targetname, targetuuid = self._check_username(
+ player, args[1], "/placetrust ")
+ regionname, position, dim = self._check_regionname(player)
+ except TypeError:
+ return
+
+ owner = self.regions.getregioninfo(regionname, "ownerUuid")
+ playeruuid = str(player.mojangUuid)
+ if playeruuid != owner:
+ player.message("&cThis is not your claim.")
+ return
+ self.regions.rgedit(
+ regionname, playername=targetname, addplace=True
+ )
+ player.message(
+ "&e%s added to this claim. Player can now access/place items"
+ " here." % targetname)
+
+ def _accesstrust_comm(self, *args):
+ player = args[0]
+ try:
+ targetname, targetuuid = self._check_username(
+ player, args[1], "/accesstrust ")
+ regionname, position, dim = self._check_regionname(player)
+ except TypeError:
+ return
+
+ owner = self.regions.getregioninfo(regionname, "ownerUuid")
+ playeruuid = str(player.mojangUuid)
+ if playeruuid != owner:
+ player.message("&cThis is not your claim.")
+ return
+ self.regions.rgedit(
+ regionname, playername=targetname, addaccess=True
+ )
+ player.message(
+ "&e%s added to this claim. Player can now access/place items"
+ " here." % targetname
+ )
+
+ def _claimblocks_comm(self, *args):
+ player = args[0]
+ self._claimblocks(player, player.uuid, player.username)
+
+ def _adjustclaimblocks_comm(self, player, args):
+ player = args[0]
+ try:
+ targetname, targetuuid = self._check_username(
+ player, args[1],
+ "/adjustclaimblocks ", 3
+ )
+ except TypeError:
+ return
+
+ amount = int(args[2])
+ subcommmand = str(args[1]).lower()
+ blocksinuse = self.data[targetuuid]["blocksused"]
+ if subcommmand == "add":
+ self.data[targetuuid]["blocks"] += amount
+ player.message(
+ "&eAdded %s blocks to player %s" % (amount, targetname)
+ )
+ if subcommmand == "sub":
+ self.data[targetuuid]["blocks"] -= amount
+ player.message(
+ "&eremoved %s blocks from player %s" % (amount, targetname)
+ )
+ if subcommmand == "set":
+ self.data[targetuuid]["blocks"] = amount
+ player.message("&eset %s's blocks to %s" % (targetname, amount))
+ if subcommmand == "info":
+ self._claimblocks(player, targetuuid, targetname)
+ return
+ amount = self.data[targetuuid]["blocks"]
+ player.message("&2%s has %s blocks." % (targetname, amount))
+
+ def _spade(self, *args):
+ player = args[0]
+ self.api.minecraft.console(
+ "give %s minecraft:golden_shovel 1 32" % player.username
+ )
+
+ def _abandonclaim_comm(self, *args):
+ player = args[0]
+ try:
+ regionname, position, dim = self._check_regionname(player)
+ except TypeError:
+ return
+
+ owner = self.regions.getregioninfo(regionname, "ownerUuid")
+ if player.uuid != owner:
+ player.message("&cThis is not your claim.")
+ return
+ self._abandonclaim(player, regionname, player.uuid)
+
+ def _deleteclaim_comm(self, *args):
+ player = args[0]
+ try:
+ regionname, position, dim = self._check_regionname(player)
+ except TypeError:
+ return
+ owneruuid = self.regions.getregioninfo(regionname, "ownerUuid")
+ self._abandonclaim(player, regionname, owneruuid)
+
+ def _abandonallclaims_comm(self, *args):
+ player = args[0]
+ playerid = str(player.mojangUuid)
+ claimlist = list(self.data[playerid]["claimlist"])
+ for thisclaimname in claimlist:
+ self._abandonclaim(player, str(thisclaimname), playerid)
+ return
+
+ def _deleteallclaims_comm(self, *args):
+ player = args[0]
+ try:
+ targetname, targetuuid = self._check_username(
+ player, args[1], "/deleteallclaims ",
+ )
+ except TypeError:
+ return
+
+ claimlist = list(self.data[targetuuid]["claimlist"])
+ for thisclaimname in claimlist:
+ self._abandonclaim(player, str(thisclaimname), targetuuid)
+ return
+
+ def _transferclaim_comm(self, *args):
+ player = args[0]
+ try:
+ regionname, position, dim = self._check_regionname(player)
+ targetname, targetuuid = self._check_username(
+ player, args[1], "/transferclaim "
+ )
+ except TypeError:
+ return
+
+ oldowneruuid = self.regions.getregioninfo(regionname, "ownerUuid")
+ pos1 = self.regions.getregioninfo(regionname, "pos1")
+ pos2 = self.regions.getregioninfo(regionname, "pos2")
+ if targetuuid not in self.data:
+ self._init_player_record(targetuuid, targetname)
+ self._abandonclaim(player, regionname, oldowneruuid)
+ self._quick_claim(
+ player, targetuuid, dim, pos1, pos2, ycoords_of_feet=position[1]
+ )
+
+ def _show_comm(self, *args):
+ player = args[0]
+ pos5 = player.getPosition()
+ pos = (int(pos5[0]), int(pos5[1]), int(pos5[2]))
+ dim = player.getDimension()
+ regionname = self.regions.regionname(pos, dim)
+ if regionname is False:
+ player.message("ðis is unclaimed")
+ return
+ point1 = self.regions.getregioninfo(
+ regionname, "pos1"
+ )
+ point2 = self.regions.getregioninfo(
+ regionname, "pos2"
+ )
+ x = int(pos[0])
+ y = int(pos[1]) - 1
+ z = int(pos[2])
+ self._show(player, (x, y, z), point1, point2)
+ player.message("&eRegion: &5%s" % regionname)
+
+ def _claimblocks(self, playerobject, playerid, playername):
+ totalblocks = self.data[playerid]["blocks"]
+ blocksinuse = self.data[playerid]["blocksused"]
+ blocksavailable = totalblocks - blocksinuse
+
+ claimlist = self.data[playerid]["claimlist"]
+ totalclaims = len(claimlist)
+ playerobject.message("")
+ playerobject.message("&6Claims information for &e%s&6:" % playername)
+ playerobject.message("&6Total claim blocks &5%s&6" % totalblocks)
+ playerobject.message(
+ "&6Blocks used: &5%s &6Blocks available: &5%s" % (
+ blocksinuse, blocksavailable
+ )
+ )
+ playerobject.message("&6Using &5%s&6 claims." % totalclaims)
+
+ def _delete_claim(self, player, claimname, ownerid):
+ cl = self.get_claim_data(player)
+ handle1 = cl["claiminfo"][claimname]["handle1"]
+ handle2 = cl["claiminfo"][claimname]["handle2"]
+ blocksize, length, width = self._getsizeclaim(handle1, handle2)
+ if claimname in cl["claiminfo"]:
+ del cl["claiminfo"][claimname]
+ if claimname in cl["claimlist"]:
+ cl["claimlist"].remove(claimname)
+ self.regions.clicks_queue.append(["break", player, handle1])
+ self.regions.clicks_queue.append(["break", player, handle2])
+ self.regions.rgdelete(claimname)
+ cl["blocksused"] -= blocksize
+
+ def _abandonclaim(self, player, thisclaimname, playerid):
+ self._delete_claim(player, thisclaimname, playerid)
+ player.message("&eClaim %s deleted!" % thisclaimname)
+
+ def _get_claimname(self, playerid, admin):
+ x = 0
+ humanname = self.data[playerid]["playername"]
+
+ while True:
+ claimname = "%s-%d" % (humanname, x)
+ if claimname not in self.data[playerid]["claimlist"]:
+ break
+ else:
+ x += 1
+ if x > self.maxclaims and not admin:
+ return False, False
+ return claimname, humanname
+
+ def _show(self, player, position, low, high):
+ """
+
+ :param player:
+ :param position:
+ :param low:
+ :param high:
+ :return:
+ """
+ lowcorner = low[0], position[1] + 1, low[2]
+ highcorner = (high[0], position[1] + 4, high[2])
+ self.regions.client_show_cube(
+ player, lowcorner, highcorner, sendblock=False
+ )
+
+ def _finishwithselectionmode(self, playername):
+ self._reset_selections(playername)
+ p = self.player_dat[playername]
+ p["mode"] = None
+
+ def _reset_selections(self, playername):
+ p = self.player_dat[playername]
+ p["point1"] = [0, 0, 0]
+ p["point2"] = [0, 0, 0]
+ p["dim1"] = 0
+ p["dim2"] = 0
+ p["point"] = "point1"
+ p["proposed"] = [0, 0, 0], [0, 0, 0]
+ p["rgedit"] = None
+
+ def _quick_claim(self, player_msg_object, owneruuid,
+ dim, pos1, pos2, ycoords_of_feet=62):
+ data = self.data[owneruuid]
+
+ data["point"] = "point2"
+ data["dim1"] = dim
+ data["dim2"] = dim
+ data["point1"] = pos1
+ data["point2"] = pos2
+ low, high = self.regions.stat_normalize_selection(
+ data["point1"],
+ data["point2"]
+ )
+ highcorner = high[0], ycoords_of_feet + 1, high[2]
+ lowcorner = low[0], ycoords_of_feet + 5, low[2]
+ data["point3"] = lowcorner
+ data["point4"] = highcorner
+ self.data_storageobject.save()
+ claimed = self._claim(player_msg_object, owneruuid)
+ if claimed:
+ player_msg_object.message("&6Claim action successful.")
+ data["mode"] = "none"
+
+ @staticmethod
+ def _getsizeclaim(coord1, coord2):
+ # size is including boundary
+ width = abs(coord2[0] - coord1[0]) + 1
+ length = abs(coord2[2] - coord1[2]) + 1
+ blocks = length * width
+ return blocks, length, width
diff --git a/wrapper/api/minecraft.py b/wrapper/api/minecraft.py
index d8a48a69..e898d991 100644
--- a/wrapper/api/minecraft.py
+++ b/wrapper/api/minecraft.py
@@ -47,7 +47,7 @@ def isServerStarted(self):
Return a boolean indicating if the server is
fully booted or not.
"""
- return self.wrapper.servervitals.state == 2
+ return self.wrapper.javaserver.state == 2
def changeServerProps(self, config_item, new_value, reload_server=False):
"""
@@ -147,7 +147,7 @@ def getServerPackets(self, packetset="CB"):
if not self.wrapper.proxymode:
return False
- version = self.wrapper.proxy.srv_data.protocolVersion
+ version = self.wrapper.javaserver.protocolVersion
if packetset == "SB":
return ServerBound(version)
@@ -170,7 +170,7 @@ def getTimeofDay(self, dttmformat=0):
# 0 = ticks, 1 = Military, else = civilian AM/PM, return -1 if no one
# on or server not started
if self.isServerStarted is True and self.wrapper.proxymode:
- servertimeofday = self.wrapper.proxy.srv_data.timeofday
+ servertimeofday = self.wrapper.javaserver.timeofday
ticktime = servertimeofday % 24000
if dttmformat == 0 or ticktime == -1:
return ticktime
@@ -282,7 +282,7 @@ def getPlayers(self): # returns a list of players
Returns a list of the currently connected players.
"""
- return self.wrapper.servervitals.players
+ return self.wrapper.players
def getEntityControl(self):
"""
@@ -342,7 +342,7 @@ def getPlayer(self, username=""):
"""
try:
- return self.wrapper.servervitals.players[str(username)]
+ return self.wrapper.players[str(username)]
except Exception as e:
self.log.error("No such player %s is logged in:\n%s", username, e)
@@ -356,7 +356,7 @@ def getplayerby_eid(self, eid):
:returns: The Player Class object for the specified EID.
If the EID is not a player or is not found, returns False
"""
- for client in self.wrapper.servervitals.clients:
+ for client in self.wrapper.proxy.clients:
if client.server_eid == eid:
try:
return self.wrapper.players[client.username]
@@ -705,7 +705,7 @@ def getLevelInfo(self, worldname=False):
"""
if not worldname:
- worldname = self.wrapper.servervitals.worldname
+ worldname = self.wrapper.javaserver.worldname
if not worldname:
raise Exception("Server Uninitiated")
f = NBTFile("%s/%s/level.dat" % (self.serverpath, worldname), "rb")
@@ -768,7 +768,7 @@ def getServerPath(self):
Gets the server's path.
"""
- return self.wrapper.servervitals.serverpath
+ return self.wrapper.javaserver.serverpath
def getWorld(self):
"""
@@ -787,7 +787,7 @@ def getWorldName(self):
new server instance not started, it will return the old world name.
"""
- return self.wrapper.servervitals.worldname
+ return self.wrapper.javaserver.worldname
def getUuidCache(self):
"""
diff --git a/wrapper/api/player.py b/wrapper/api/player.py
index 723752e8..a288af50 100644
--- a/wrapper/api/player.py
+++ b/wrapper/api/player.py
@@ -185,7 +185,7 @@ def __init__(self, username, wrapper):
self._position = [0, 0, 0, 0, 0] # internally used for non-proxy mode
self.client = None
- self.clientgameversion = self.wrapper.servervitals.protocolVersion
+ self.clientgameversion = self.wrapper.javaserver.protocolVersion
self.cbpkt = Packets_cb(self.clientgameversion)
self.sbpkt = Packets_sb(self.clientgameversion)
@@ -204,7 +204,7 @@ def __init__(self, username, wrapper):
if self.wrapper.proxy:
gotclient = False
- for client in self.wrapper.servervitals.clients:
+ for client in self.wrapper.proxy.clients:
if client.username == self.username:
self.client = client
self.clientUuid = client.wrapper_uuid
@@ -212,13 +212,13 @@ def __init__(self, username, wrapper):
self.mojangUuid = client.mojanguuid
self.ipaddress = client.ip
- # pktSB already set to self.wrapper.servervitals.protocolVersion # noqa
+ # pktSB already set to self.wrapper.javaserver.protocolVersion # noqa
self.clientboundPackets = self.client.pktCB
self.clientgameversion = self.client.clientversion
gotclient = True
break
if not gotclient:
- pprint.pprint(self.wrapper.servervitals.clients)
+ pprint.pprint(self.wrapper.proxy.clients)
self.log.error("Proxy is on, but this client is not "
"listed in proxy.clients!")
self.log.error("The usual cause of this would be that"
@@ -325,12 +325,12 @@ def execute(self, string):
"execute" command.
"""
- if string[0] in (self.wrapper.servervitals.command_prefix, "/"):
+ if string[0] in (self.wrapper.proxy.command_prefix, "/"):
string = string[1:]
try:
self.client.chat_to_server("/%s" % string)
except AttributeError:
- if self.wrapper.servervitals.protocolVersion > PROTOCOL_1_7_9:
+ if self.wrapper.javaserver.protocolVersion > PROTOCOL_1_7_9:
self.wrapper.javaserver.console(
"execute %s ~ ~ ~ %s" % (self.username, string))
else:
@@ -398,7 +398,7 @@ def getClient(self):
"""
if self.client is None:
- for client in self.wrapper.servervitals.clients:
+ for client in self.wrapper.proxy.clients:
if client.username == self.username:
self.client = client
return client
@@ -506,7 +506,7 @@ def setResourcePack(self, url, hashrp=""):
"""
try:
- version = self.wrapper.proxy.srv_data.protocolVersion
+ version = self.wrapper.javaserver.protocolVersion
except AttributeError:
# Non proxy mode
return False
@@ -550,10 +550,10 @@ def isOp(self, strict=False):
"""
- if self.wrapper.servervitals.operator_list in (False, None):
+ if self.wrapper.javaserver.operator_list in (False, None):
return False # no ops in file
# each op item is a dictionary
- for ops in self.wrapper.servervitals.operator_list:
+ for ops in self.wrapper.javaserver.operator_list:
if ops["uuid"] == self.serverUuid.string:
return ops["level"]
if ops["name"] == self.username and not strict:
@@ -603,7 +603,7 @@ def setVisualXP(self, progress, level, total):
"""
try:
- version = self.wrapper.proxy.srv_data.protocolVersion
+ version = self.wrapper.javaserver.protocolVersion
except AttributeError:
# Non proxy mode
return False
@@ -662,7 +662,7 @@ def openWindow(self, windowtype, title, slots):
"""
try:
- version = self.wrapper.proxy.srv_data.protocolVersion
+ version = self.wrapper.javaserver.protocolVersion
except AttributeError:
# Non proxy mode
return False
@@ -1077,7 +1077,7 @@ def getFirstLogin(self):
return self.data.Data["firstLoggedIn"]
# Cross-server commands
- def connect(self, ip="127.0.0.1", port=25600):
+ def connect(self, ip="localhost", port=25600):
"""
Connect to another server. Upon calling, the client's current
server instance will be closed and a new server connection made
diff --git a/wrapper/api/world.py b/wrapper/api/world.py
index fae97200..9f0d66a0 100644
--- a/wrapper/api/world.py
+++ b/wrapper/api/world.py
@@ -64,7 +64,7 @@ def fill(self, position1, position2, tilename, damage=0, mode="destroy", data=No
x1, y1, z1 = position1
x2, y2, z2 = position2
- if self.javaserver.vitals.protocolVersion < 6:
+ if self.javaserver.protocolVersion < 6:
raise Exception("Must be running Minecraft 1.8 or above"
" to use the world.fill() method.")
else:
@@ -82,7 +82,7 @@ def replace(self, position1, position2, tilename1, damage1, tilename2, damage2=0
"""
x1, y1, z1 = position1
x2, y2, z2 = position2
- if self.javaserver.vitals.protocolVersion < 6:
+ if self.javaserver.protocolVersion < 6:
raise Exception(
"Must be running Minecraft 1.8 or above"
" to use the world.replace() method.")
diff --git a/wrapper/core/backups.py b/wrapper/core/backups.py
index 62b0f260..181078fc 100644
--- a/wrapper/core/backups.py
+++ b/wrapper/core/backups.py
@@ -63,7 +63,7 @@ def _bu_process(self):
while not self.wrapper.haltsig.halt:
time.sleep(1)
# only run backups in server running/starting states
- if self.wrapper.javaserver.vitals.state in (1, 2) and not self.idle:
+ if self.wrapper.javaserver.state in (1, 2) and not self.idle:
if time.time() - self.timer > self.backup_interval and self.enabled: # noqa
self.dobackup()
else:
diff --git a/wrapper/core/buildinfo.py b/wrapper/core/buildinfo.py
index c6b6fc19..5d31059f 100644
--- a/wrapper/core/buildinfo.py
+++ b/wrapper/core/buildinfo.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Do not edit this file to bump versions; it is built automatically
-__version__ = [1, 0, 15, 'rc', 20]
+__version__ = [1, 0, 19, 'rc', 28]
__branch__ = 'stable'
diff --git a/wrapper/core/commands.py b/wrapper/core/commands.py
index 5c6f48f2..883f12f7 100644
--- a/wrapper/core/commands.py
+++ b/wrapper/core/commands.py
@@ -521,7 +521,7 @@ def command_help(self, player, payload):
"clickEvent": {
"action": "run_command",
"value": "%shelp Minecraft %d" % (
- self.wrapper.servervitals.command_prefix,
+ self.wrapper.proxy.command_prefix,
page + 2)
}
}, {
@@ -579,7 +579,7 @@ def command_help(self, player, payload):
"clickEvent": {
"action": "suggest_command",
"value": "%s%s" % (
- self.wrapper.servervitals.command_prefix, # noqa
+ self.wrapper.proxy.command_prefix, # noqa
command[1:])
},
"hoverEvent": {
@@ -607,7 +607,7 @@ def command_help(self, player, payload):
_showpage(
player, page, items, "help %s" % groupname,
4,
- command_prefix=self.wrapper.servervitals.command_prefix) # noqa
+ command_prefix=self.wrapper.proxy.command_prefix) # noqa
return
player.message("&cThe help group '%s' does not exist." % group)
@@ -638,13 +638,13 @@ def command_help(self, player, payload):
"clickEvent": {
"action": "run_command",
"value": "%shelp %s" % (
- self.wrapper.servervitals.command_prefix,
+ self.wrapper.proxy.command_prefix,
v["name"])
},
"hoverEvent": {
"action": "show_text",
"value": "%shelp %s" % (
- self.wrapper.servervitals.command_prefix,
+ self.wrapper.proxy.command_prefix,
v["name"])
}
},
@@ -653,7 +653,7 @@ def command_help(self, player, payload):
}]
})
_showpage(player, page, items, "help", 8,
- command_prefix=self.wrapper.servervitals.command_prefix)
+ command_prefix=self.wrapper.proxy.command_prefix)
return False
def command_password(self, player, payload):
@@ -781,7 +781,7 @@ def _command_whitelist_add(self, player, arg):
if not self.wrapper.proxymode:
player.execute("whitelist add %s" % arg)
player.message("..Working. Server may lag.")
- player.message()
+ player.message("...")
return
whitelist = getjsonfile(
"whitelist", self.wrapper.serverpath, self.wrapper.encoding
@@ -908,18 +908,17 @@ def _command_whitelist_online(self, player, _arg):
self.wrapper.shutdown()
def command_deop(self, player, payload):
- # if player is None:
- # player = self.wrapper.xplayer
- if not self._superop(player, 9):
+ """DeOP has lower permission level"""
+ if not self._superop(player, 3):
return False
operator_name = getargs(payload["args"], 0)
- if self.wrapper.servervitals.state == 2:
+ if self.wrapper.javaserver.state == 2:
# deop from server
self.wrapper.javaserver.console("deop %s" % operator_name)
# deop from superops.txt
file_text = ""
- owner_names = self.wrapper.servervitals.ownernames
+ owner_names = self.wrapper.javaserver.ownernames
for eachname in owner_names:
if eachname != operator_name:
if eachname not in ("", ""):
@@ -977,13 +976,13 @@ def command_op(self, player, payload):
if superop and superlevel > 4:
superlevel = max(5, superlevel)
# 2 = make sure server STARTED
- if self.wrapper.servervitals.state == 2:
+ if self.wrapper.javaserver.state == 2:
self.wrapper.javaserver.console("op %s" % name)
# if not, wrapper makes ops.json edits
else:
self.wrapper.javaserver.refresh_ops(read_super_ops=False)
- oplist = self.wrapper.servervitals.operator_list
+ oplist = self.wrapper.javaserver.operator_list
newop_item = {
"uuid": uuid,
"name": name,
diff --git a/wrapper/core/events.py b/wrapper/core/events.py
index ea91d094..89923106 100644
--- a/wrapper/core/events.py
+++ b/wrapper/core/events.py
@@ -87,10 +87,10 @@ def _callevent(self, event, payload, abortable=True):
# create reference player object for payload, if needed.
if payload and ("playername" in payload) and ("player" not in payload):
- for client in self.wrapper.servervitals.clients:
+ for client in self.wrapper.proxy.clients:
if client.username == payload["playername"]:
- if client.username not in self.wrapper.servervitals.players:
- self.wrapper.servervitals.players[
+ if client.username not in self.wrapper.players:
+ self.wrapper.players[
client.username] = Player(client.username,
self.wrapper)
payload["player"] = self.wrapper.api.minecraft.getPlayer(
diff --git a/wrapper/core/mcserver.py b/wrapper/core/mcserver.py
index 487426f8..41ae6049 100644
--- a/wrapper/core/mcserver.py
+++ b/wrapper/core/mcserver.py
@@ -41,11 +41,28 @@
# noinspection PyBroadException,PyUnusedLocal
class MCServer(object):
- def __init__(self, wrapper, servervitals):
+ def __init__(self, wrapper):
self.log = wrapper.log
self.config = wrapper.config
- self.vitals = servervitals
-
+ self.serverpath = self.config["General"]["server-directory"]
+ self.state = OFF
+ self.properties = {}
+ self.worldname = None
+ self.worldsize = 0
+ # owner/op info
+ self.ownernames = {}
+ self.operator_list = []
+ self.spammy_stuff = ["found nothing", "vehicle of", "Wrong location!",
+ "Tried to add entity", ]
+ # this is string name of the version, collected by console output
+ self.version = ""
+ self.version_compute = 0
+ self.servericon = None
+ self.motd = None
+ self.timeofday = -1
+ self.protocolVersion = -1
+ self.server_port = "25564"
+
self.encoding = self.config["General"]["encoding"]
self.stop_message = self.config["Misc"]["stop-message"]
self.reboot_message = self.config["Misc"]["reboot-message"]
@@ -64,7 +81,7 @@ def __init__(self, wrapper, servervitals):
for part in commargs:
if part[-4:] == ".jar":
- self.args.append("%s/%s" % (self.vitals.serverpath, part))
+ self.args.append("%s/%s" % (self.serverpath, part))
else:
self.args.append(part)
@@ -137,13 +154,13 @@ def init(self):
capturethread.start()
def __del__(self):
- self.vitals.state = 0
+ self.state = 0
def accepteula(self):
- if os.path.isfile("%s/eula.txt" % self.vitals.serverpath):
+ if os.path.isfile("%s/eula.txt" % self.serverpath):
self.log.debug("Checking EULA agreement...")
- with open("%s/eula.txt" % self.vitals.serverpath) as f:
+ with open("%s/eula.txt" % self.serverpath) as f:
eula = f.read()
# if forced, should be at info level since acceptance
@@ -152,7 +169,7 @@ def accepteula(self):
self.log.warning(
"EULA agreement was not accepted, accepting on"
" your behalf...")
- set_item("eula", "true", "eula.txt", self.vitals.serverpath)
+ set_item("eula", "true", "eula.txt", self.serverpath)
self.log.debug("EULA agreement has been accepted.")
return True
@@ -181,7 +198,7 @@ def handle_server(self):
command = self.args
self.proc = subprocess.Popen(
- command, cwd=self.vitals.serverpath, stdout=subprocess.PIPE,
+ command, cwd=self.serverpath, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, stdin=subprocess.PIPE,
universal_newlines=True)
self.wrapper.players = {}
@@ -230,7 +247,7 @@ def start(self):
Start the Minecraft server
"""
self.server_autorestart = self.config["General"]["auto-restart"]
- if self.vitals.state in (STARTED, STARTING):
+ if self.state in (STARTED, STARTING):
self.log.warning("The server is already running!")
return
if not self.boot_server:
@@ -247,21 +264,21 @@ def restart(self, reason=""):
if reason == "":
reason = self.restart_message
- if self.vitals.state in (STOPPING, OFF):
+ if self.state in (STOPPING, OFF):
self.start()
return
self.doserversaving()
self.stop(reason)
def kick_players(self, reasontext):
- playerlist = copy.copy(self.vitals.players)
+ playerlist = copy.copy(self.wrapper.players)
for player in playerlist:
self.kick_player(player, reasontext)
def kick_player(self, player, reasontext):
if self.wrapper.proxymode:
try:
- playerclient = self.vitals.players[player].client
+ playerclient = self.wrapper.players[player].client
playerclient.notify_disconnect(reasontext)
except AttributeError:
self.log.warning(
@@ -302,10 +319,10 @@ def stop_server_command(self, reason="", restart_the_server=False):
"""
if reason == "":
reason = self.stop_message
- if self.vitals.state == OFF:
+ if self.state == OFF:
self.log.warning("The server is not running... :?")
return
- if self.vitals.state == FROZEN:
+ if self.state == FROZEN:
self.log.warning("The server is currently frozen.\n"
"To stop it, you must /unfreeze it first")
return
@@ -317,7 +334,7 @@ def kill(self, reason="Killing Server"):
"""Forcefully kill the server. It will auto-restart if set
in the configuration file.
"""
- if self.vitals.state in (STOPPING, OFF):
+ if self.state in (STOPPING, OFF):
self.log.warning("The server is already dead, my friend...")
return
self.log.info("Killing Minecraft server with reason: %s", reason)
@@ -334,7 +351,7 @@ def freeze(self, reason="Server is now frozen. You may disconnect."):
specify None. This command currently only works for
*NIX based systems.
"""
- if self.vitals.state != OFF:
+ if self.state != OFF:
if os.name == "posix":
self.log.info("Freezing server with reason: %s", reason)
self.broadcast("&c%s" % reason)
@@ -354,7 +371,7 @@ def unfreeze(self):
to .freeze(reason) This command currently only works
for *NIX based systems.
"""
- if self.vitals.state != OFF:
+ if self.state != OFF:
if os.name == "posix":
self.log.info("Unfreezing server (ignore any"
" messages to type /start)...")
@@ -375,7 +392,7 @@ def broadcast(self, message, who="@a"):
string with formatting codes using the § as a prefix.
"""
if isinstance(message, dict):
- if self.vitals.version_compute < 10700:
+ if self.version_compute < 10700:
self.console("say %s %s" % (who, chattocolorcodes(message)))
else:
encoding = self.wrapper.encoding
@@ -383,7 +400,7 @@ def broadcast(self, message, who="@a"):
who, json.dumps(message, ensure_ascii=False)))
else:
temp = processcolorcodes(message)
- if self.vitals.version_compute < 10700:
+ if self.version_compute < 10700:
temp = processcolorcodes(message)
self.console("say %s %s" % (
who, chattocolorcodes(temp)))
@@ -394,17 +411,17 @@ def broadcast(self, message, who="@a"):
def login(self, username, servereid, position, ipaddr):
"""Called when a player logs in."""
- if username not in self.vitals.players:
- self.vitals.players[username] = Player(username, self.wrapper)
+ if username not in self.wrapper.players:
+ self.wrapper.players[username] = Player(username, self.wrapper)
# store EID if proxy is not fully connected yet (or is not enabled).
- self.vitals.players[username].playereid = servereid
- self.vitals.players[username].loginposition = position
- if self.vitals.players[username].ipaddress == "127.0.0.0":
- self.vitals.players[username].ipaddress = ipaddr
+ self.wrapper.players[username].playereid = servereid
+ self.wrapper.players[username].loginposition = position
+ if self.wrapper.players[username].ipaddress == "127.0.0.0":
+ self.wrapper.players[username].ipaddress = ipaddr
- if self.wrapper.proxy and self.vitals.players[username].client:
- self.vitals.players[username].client.server_eid = servereid
- self.vitals.players[username].client.position = position
+ if self.wrapper.proxy and self.wrapper.players[username].client:
+ self.wrapper.players[username].client.server_eid = servereid
+ self.wrapper.players[username].client.position = position
# activate backup status
self.wrapper.backups.idle = False
@@ -441,8 +458,8 @@ def login(self, username, servereid, position, ipaddr):
def logout(self, players_name):
"""Called when a player logs out."""
- if players_name in self.vitals.players:
- player = self.vitals.players[players_name]
+ if players_name in self.wrapper.players:
+ player = self.wrapper.players[players_name]
self.wrapper.events.callevent(
"player.logout", {"player": player,
"playername": players_name},
@@ -470,14 +487,14 @@ def logout(self, players_name):
if player.client is None:
player.abort = True
- del self.vitals.players[players_name]
+ del self.wrapper.players[players_name]
elif player.client.state != LOBBY and player.client.local:
player.abort = True
- del self.vitals.players[players_name]
-
- self.wrapper.proxy.removestaleclients()
+ del self.wrapper.players[players_name]
+ if self.wrapper.proxy:
+ self.wrapper.proxy.removestaleclients()
- if len(self.vitals.players) == 0:
+ if len(self.wrapper.players) == 0:
self.wrapper.backups.idle = True
def getplayer(self, username):
@@ -488,10 +505,12 @@ def getplayer(self, username):
api.minecraft.getPlayer will deal in all players, including
those in proxy and/or other hub servers.
"""
- if username in self.vitals.players:
- player = self.vitals.players[username]
+ if username in self.wrapper.players:
+ player = self.wrapper.players[username]
if player.client and player.client.state != LOBBY and player.client.local: # noqa
return player
+ elif not self.wrapper.proxymode:
+ return player
return False
def reloadproperties(self):
@@ -500,38 +519,30 @@ def reloadproperties(self):
# straightforward and works in both PY2 and PY3
# Load server icon
- if os.path.exists("%s/server-icon.png" % self.vitals.serverpath):
- with open("%s/server-icon.png" % self.vitals.serverpath, "rb") as f:
+ if os.path.exists("%s/server-icon.png" % self.serverpath):
+ with open("%s/server-icon.png" % self.serverpath, "rb") as f:
theicon = f.read()
iconencoded = base64.standard_b64encode(theicon)
- self.vitals.serverIcon = b"data:image/png;base64," + iconencoded
+ self.servericon = b"data:image/png;base64," + iconencoded
- self.vitals.properties = config_to_dict_read(
- "server.properties", self.vitals.serverpath)
+ self.properties = config_to_dict_read(
+ "server.properties", self.serverpath)
- if self.vitals.properties == {}:
+ if self.properties == {}:
self.log.warning("File 'server.properties' not found.")
return False
- if "level-name" in self.vitals.properties:
- self.vitals.worldname = self.vitals.properties["level-name"]
+ if "level-name" in self.properties:
+ self.worldname = self.properties["level-name"]
else:
self.log.warning("No 'level-name=(worldname)' was"
" found in the server.properties.")
return False
- self.vitals.motd = self.vitals.properties["motd"]
- if "max-players" in self.vitals.properties:
- self.vitals.maxPlayers = self.vitals.properties["max-players"]
- else:
- self.log.warning(
- "No 'max-players=(count)' was found in the"
- " server.properties. The default of '20' will be used.")
- self.vitals.maxPlayers = 20
- self.vitals.onlineMode = self.vitals.properties["online-mode"]
+ self.motd = self.properties["motd"]
def console(self, command):
"""Execute a console command on the server."""
- if self.vitals.state in (STARTING, STARTED, STOPPING) and self.proc:
+ if self.state in (STARTING, STARTED, STOPPING) and self.proc:
self.proc.stdin.write("%s\n" % command)
self.proc.stdin.flush()
else:
@@ -542,17 +553,17 @@ def changestate(self, state, reason=None):
"""Change the boot state indicator of the server, with a
reason message.
"""
- self.vitals.state = state
- if self.vitals.state == OFF:
+ self.state = state
+ if self.state == OFF:
self.wrapper.events.callevent(
"server.stopped", {"reason": reason}, abortable=False)
- elif self.vitals.state == STARTING:
+ elif self.state == STARTING:
self.wrapper.events.callevent(
"server.starting", {"reason": reason}, abortable=False)
- elif self.vitals.state == STARTED:
+ elif self.state == STARTED:
self.wrapper.events.callevent(
"server.started", {"reason": reason}, abortable=False)
- elif self.vitals.state == STOPPING:
+ elif self.state == STOPPING:
self.wrapper.events.callevent(
"server.stopping", {"reason": reason}, abortable=False)
self.wrapper.events.callevent(
@@ -592,7 +603,7 @@ def server_reload(self):
is in proxy mode, it will reconnect all clients to the
serverconnection.
"""
- if self.vitals.state in (STOPPING, OFF):
+ if self.state in (STOPPING, OFF):
self.log.warning(
"The server is not already running... Just use '/start'.")
return
@@ -657,14 +668,14 @@ def read_ops_file(self, read_super_ops=True):
"""
ops = False
# (4 = PROTOCOL_1_7 ) - 1.7.6 or greater use ops.json
- if self.vitals.protocolVersion > 4:
+ if self.version_compute > 10700:
ops = getjsonfile(
- "ops", self.vitals.serverpath, encodedas=self.encoding
+ "ops", self.serverpath, encodedas=self.encoding
)
if not ops:
# try for an old "ops.txt" file instead.
ops = []
- opstext = getfileaslines("ops.txt", self.vitals.serverpath)
+ opstext = getfileaslines("ops.txt", self.serverpath)
if not opstext:
return False
for op in opstext:
@@ -681,17 +692,17 @@ def read_ops_file(self, read_super_ops=True):
# Grant "owner" an op level above 4. required for some wrapper commands
if read_super_ops:
for eachop in ops:
- if eachop["name"] in self.vitals.ownernames:
- eachop["level"] = self.vitals.ownernames[eachop["name"]]
+ if eachop["name"] in self.ownernames:
+ eachop["level"] = self.ownernames[eachop["name"]]
return ops
def refresh_ops(self, read_super_ops=True):
- self.vitals.ownernames = config_to_dict_read("superops.txt", ".")
- if self.vitals.ownernames == {}:
+ self.ownernames = config_to_dict_read("superops.txt", ".")
+ if self.ownernames == {}:
sample = "=10\n=9"
with open("superops.txt", "w") as f:
f.write(sample)
- self.vitals.operator_list = self.read_ops_file(read_super_ops)
+ self.operator_list = self.read_ops_file(read_super_ops)
def getmemoryusage(self):
"""Returns allocated memory in bytes. This command
@@ -767,21 +778,21 @@ def readconsole(self, buff):
break
line_words = buff.split(' ')[self.prepends_offset:]
- self.vitals.version = getargs(line_words, 4)
- semantics = self.vitals.version.split(".")
+ self.version = getargs(line_words, 4)
+ semantics = self.version.split(".")
release = get_int(getargs(semantics, 0))
major = get_int(getargs(semantics, 1))
minor = get_int(getargs(semantics, 2))
- self.vitals.version_compute = minor + (major * 100) + (release * 10000) # noqa
+ self.version_compute = minor + (major * 100) + (release * 10000) # noqa
- if len(self.vitals.version.split("w")) > 1:
+ if len(self.version.split("w")) > 1:
# It is a snap shot
- self.vitals.version_compute = 10800
+ self.version_compute = 10800
# 1.7.6 (protocol 5) is the cutoff where ops.txt became ops.json
- if self.vitals.version_compute > 10705 and self.vitals.protocolVersion < 0: # noqa
- self.vitals.protocolVersion = 5
+ if self.version_compute > 10705 and self.protocolVersion < 0: # noqa
+ self.protocolVersion = 5
self.wrapper.api.registerPermission("mc1.7.6", value=True)
- if self.vitals.version_compute < 10702 and self.wrapper.proxymode:
+ if self.version_compute < 10702 and self.wrapper.proxymode:
self.log.warning("\nProxy mode cannot run because the "
"server is a pre-Netty version:\n\n"
"http://wiki.vg/Protocol_version_numbers"
@@ -818,33 +829,36 @@ def readconsole(self, buff):
prefix = " ".join(buff.split(' ')[:self.prepends_offset])
if not self.wrapper.wrapper_onlinemode:
+ try:
+ pport = "either port %s or " % self.wrapper.proxy.proxy_port
+ except AttributeError:
+ pport = ""
message = (
"%s Since you are running Wrapper in OFFLINE mode, THIS "
"COULD BE SERIOUS!\n%s Wrapper is not handling any"
" authentication.\n%s This is only ok if this wrapper "
- "is not accessible from either port %s or port %s"
+ "is not accessible from %sport %s"
" (I.e., this wrapper is a multiworld for a hub server, or"
" you are doing your own authorization via a plugin)." % (
- prefix, prefix, prefix,
- self.vitals.server_port, self.wrapper.proxy.proxy_port))
+ prefix, prefix, prefix, pport, self.server_port))
else:
message = (
"%s Since you are running Wrapper in proxy mode, this"
" should be ok because Wrapper is handling the"
" authentication, PROVIDED no one can access port"
" %s from outside your network." % (
- prefix, self.vitals.server_port))
+ prefix, self.server_port))
if self.wrapper.proxymode:
buff = message
# read port of server and display proxy port, if applicable
if "Starting Minecraft server on" in buff:
- self.vitals.server_port = get_int(buff.split(':')[-1:][0])
+ self.server_port = get_int(buff.split(':')[-1:][0])
# check for server console spam before printing to wrapper console
server_spaming = False
- for things in self.vitals.spammy_stuff:
+ for things in self.spammy_stuff:
if things in buff:
server_spaming = True
@@ -868,8 +882,8 @@ def readconsole(self, buff):
# Getting world name
elif "Preparing level" in buff:
- self.vitals.worldname = getargs(line_words, 2).replace('"', "")
- self.world = World(self.vitals.worldname, self)
+ self.worldname = getargs(line_words, 2).replace('"', "")
+ self.world = World(self.worldname, self)
# Player Message
elif first_word[0] == "<":
@@ -988,13 +1002,16 @@ def readconsole(self, buff):
elif second_word == "Teleported" and getargs(line_words, 3) == "to":
playername = getargs(line_words, 2)
# [SurestTexas00: Teleported SapperLeader to 48.49417131908783, 77.67081086259394, -279.88880690937475] # noqa
- if playername in self.wrapper.servervitals.players:
+ if playername in self.wrapper.players:
playerobj = self.getplayer(playername)
- playerobj._position = [
- get_int(float(getargs(line_words, 4).split(",")[0])),
- get_int(float(getargs(line_words, 5).split(",")[0])),
- get_int(float(getargs(line_words, 6).split("]")[0])), 0, 0
- ]
+ try:
+ playerobj._position = [
+ get_int(float(getargs(line_words, 4).split(",")[0])),
+ get_int(float(getargs(line_words, 5).split(",")[0])),
+ get_int(float(getargs(line_words, 6).split("]")[0])), 0, 0
+ ]
+ except ValueError:
+ pass
self.wrapper.events.callevent(
"player.teleport",
{"player": playerobj}, abortable=False)
@@ -1018,13 +1035,16 @@ def readconsole(self, buff):
elif first_word == "Teleported" and getargs(line_words, 2) == "to":
playername = second_word
# Teleported SurestTexas00 to 48.49417131908783, 77.67081086259394, -279.88880690937475 # noqa
- if playername in self.wrapper.servervitals.players:
+ if playername in self.wrapper.players:
playerobj = self.getplayer(playername)
- playerobj._position = [
- get_int(float(getargs(line_words, 3).split(",")[0])),
- get_int(float(getargs(line_words, 4).split(",")[0])),
- get_int(float(getargs(line_words, 5))), 0, 0
- ]
+ try:
+ playerobj._position = [
+ get_int(float(getargs(line_words, 3).split(",")[0])),
+ get_int(float(getargs(line_words, 4).split(",")[0])),
+ get_int(float(getargs(line_words, 5))), 0, 0
+ ]
+ except ValueError:
+ pass
self.wrapper.events.callevent(
"player.teleport",
{"player": playerobj}, abortable=False)
@@ -1052,7 +1072,7 @@ def reboot_timer(self):
while not self.wrapper.haltsig.halt:
time.sleep(1)
timer = rb_mins - rb_mins_warn
- while self.vitals.state in (STARTED, STARTING):
+ while self.state in (STARTED, STARTING):
timer -= 1
time.sleep(60)
if timer > 0:
@@ -1094,17 +1114,17 @@ def reboot_timer(self):
def eachsecond_web(self):
if time.time() - self.lastsizepoll > 120:
- if self.vitals.worldname is None:
+ if self.worldname is None:
return True
self.lastsizepoll = time.time()
size = 0
# os.scandir not in standard library on early py2.7.x systems
for i in os.walk(
- "%s/%s" % (self.vitals.serverpath, self.vitals.worldname)
+ "%s/%s" % (self.serverpath, self.worldname)
):
for f in os.listdir(i[0]):
size += os.path.getsize(os.path.join(i[0], f))
- self.vitals.worldsize = size
+ self.worldsize = size
def _console_event(self, payload):
"""This function is used in conjunction with event handlers to
diff --git a/wrapper/core/servervitals.py b/wrapper/core/servervitals.py
deleted file mode 100644
index e8108536..00000000
--- a/wrapper/core/servervitals.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (C) 2016, 2017 - BenBaptist and Wrapper.py developer(s).
-# https://github.com/benbaptist/minecraft-wrapper
-# This program is distributed under the terms of the GNU
-# General Public License, version 3 or later.
-
-
-class ServerVitals(object):
- """ Centralized location for server information. This class also
- permits sharing of server information between the caller (such as
- a Wrapper instance) and proxy."""
- def __init__(self, playerobjects):
-
- # operational info
- self.serverpath = ""
- self.state = 0
- self.server_port = "25564"
- self.command_prefix = "/"
-
- # Shared data structures and run-time
- self.players = playerobjects
-
- # TODO - I don't think this is used or needed (same name as proxy.entity_control!)
- self.entity_control = None
- # -1 until a player logs on and server sends a time update
- self.timeofday = -1
- self.spammy_stuff = ["found nothing", "vehicle of", "Wrong location!",
- "Tried to add entity", ]
-
- # PROPOSE
- self.clients = []
-
- # owner/op info
- self.ownernames = {}
- self.operator_list = []
-
- # server properties and folder infos
- self.properties = {}
- self.worldname = None
- self.worldsize = 0
- self.maxplayers = 20
- self.motd = None
- self.serverIcon = None
-
- # # Version information
- # -1 until proxy mode checks the server's MOTD on boot
- self.protocolVersion = -1
- # this is string name of the version, collected by console output
- self.version = ""
- # a comparable number = x0y0z, where x, y, z = release,
- # major, minor, of version.
- self.version_compute = 0
diff --git a/wrapper/core/wrapper.py b/wrapper/core/wrapper.py
index 829f61a0..2737bac8 100644
--- a/wrapper/core/wrapper.py
+++ b/wrapper/core/wrapper.py
@@ -17,7 +17,11 @@
import logging
# import smtplib
import sys # used to pass sys.argv to server
-# from pprint import pprint
+
+try:
+ from concurrent.futures import ProcessPoolExecutor
+except ImportError:
+ ProcessPoolExecutor = False
# non standard library imports
try:
@@ -51,7 +55,7 @@
from core.irc import IRC
from core.scripts import Scripts
import core.buildinfo as buildinfo
-from proxy.utils.mcuuid import UUIDS
+from proxy.utils.mcuuid import UUIDS, MCUUID
from core.config import Config
from core.backups import Backups
from core.consoleuser import ConsolePlayer
@@ -60,8 +64,7 @@
from utils.crypt import Crypt, phrase_to_url_safebytes, gensalt
# optional API type stuff
-from core.servervitals import ServerVitals
-from proxy.base import Proxy, ProxyConfig, HaltSig
+from proxy.base import Proxy
from api.base import API
import management.web as manageweb
@@ -188,9 +191,8 @@ def __init__(self, secret_passphrase):
# the value of self.haltsig would not necessarily change the value of
# the passed parameter (unless it was specifically referenced back as
# `wrapper.haltsig`). Since the halt signal needs to be passed, possibly
- # several layers deep, and into modules that it may be desireable to
- # not have direct access to wrapper, using a HaltSig object is
- # required to ensure we are actually sharing the same value between
+ # several layers deep, and into other modules , using a HaltSig object
+ # is required to ensure we are actually sharing the same value between
# different objects.
self.haltsig = HaltSig()
@@ -207,6 +209,7 @@ def __init__(self, secret_passphrase):
# core functions and datasets
self.perms = Permissions(self)
self.uuids = UUIDS(self.log, self.usercache)
+ self.mcuuid = MCUUID
self.plugins = Plugins(self)
self.commands = Commands(self)
self.events = Events(self)
@@ -237,24 +240,6 @@ def __init__(self, secret_passphrase):
" console functioning. Press to acknowledge...")
sys.stdin.readline()
- # create server/proxy vitals and config objects
- self.servervitals = ServerVitals(self.players)
-
- # LETS TAKE A SECOND TO DISCUSS PLAYER OBJECTS:
- # The ServerVitals class gets passed the player object list now, but
- # player objects are now housed in wrapper. This is how we are
- # passing information between proxy and wrapper.
-
- self.servervitals.serverpath = self.config[
- "General"]["server-directory"]
- self.servervitals.state = OFF
- self.servervitals.command_prefix = self.config[
- "Proxy"]["command-prefix"]
-
- self.proxyconfig = ProxyConfig()
- self.proxyconfig.proxy = self.config["Proxy"]
- self.proxyconfig.entity = self.config["Entities"]
-
def __del__(self):
"""prevent error message on very first wrapper starts when
wrapper exits after creating new wrapper.properties file.
@@ -281,7 +266,7 @@ def start(self):
self._registerwrappershelp()
# The MCServerclass is a console wherein the server is started
- self.javaserver = MCServer(self, self.servervitals)
+ self.javaserver = MCServer(self)
self.javaserver.init()
# load plugins
@@ -403,7 +388,7 @@ def sigtstp(*args):
self._halt()
def _halt(self):
- if self.servervitals.state in (1, 2):
+ if self.javaserver.state in (1, 2):
self.javaserver.stop(self.halt_message, restart_the_server=False)
self.haltsig.halt = True
@@ -812,7 +797,7 @@ def isonlinemode(self):
return self.config["Proxy"]["online-mode"]
if self.javaserver:
try:
- return self.servervitals.properties["online-mode"]
+ return self.javaserver.properties["online-mode"]
except KeyError:
pass
return False
@@ -844,9 +829,7 @@ def _start_emailer(self):
def _startproxy(self):
try:
- self.proxy = Proxy(self.haltsig, self.proxyconfig, self.servervitals,
- self.log, self.wrapper_usercache, self.events,
- self.encoding)
+ self.proxy = Proxy(self)
except ImportError:
self.log.error("Proxy mode not started because of missing "
"dependencies for encryption!")
@@ -855,7 +838,7 @@ def _startproxy(self):
# wait for server to start
timer = 0
- while self.servervitals.state < STARTED:
+ while self.javaserver.state < STARTED:
timer += 1
time.sleep(.1)
if timer > 1200:
@@ -866,15 +849,19 @@ def _startproxy(self):
self.disable_proxymode()
return
- if self.proxy.proxy_port == self.servervitals.server_port:
+ if self.proxy.proxy_port == self.javaserver.server_port:
self.log.warning("Proxy mode cannot start because the wrapper"
" port is identical to the server port.")
self.disable_proxymode()
return
- proxythread = threading.Thread(target=self.proxy.host, args=())
- proxythread.daemon = True
- proxythread.start()
+ if not ProcessPoolExecutor:
+ proxythread = threading.Thread(target=self.proxy.host, args=())
+ proxythread.daemon = True
+ proxythread.start()
+ else:
+ with ProcessPoolExecutor(max_workers=2) as executor:
+ executor.submit(self.proxy.host())
def disable_proxymode(self):
self.proxymode = False
@@ -1340,3 +1327,16 @@ def _show_help_bans(self, player):
" displays on single page!)",
separator="[players|ips] [searchtext] ", pad=12,
usereadline=self.use_readline, player=player)
+
+
+class HaltSig(object):
+ """
+ HaltSig is simply a sort of dummy class created for the
+ proxy. proxy expects this object with a self.halt property
+ that tells proxy to shutdown. The caller maintains control
+ of the Haltsig object and uses it to signal the proxy to
+ shut down. The caller will import this class, instantiate
+ it, and then pass the object to proxy as the argument for
+ termsignal."""
+ def __init__(self):
+ self.halt = False
diff --git a/wrapper/management/web.py b/wrapper/management/web.py
index 4d4e4983..afdc390d 100644
--- a/wrapper/management/web.py
+++ b/wrapper/management/web.py
@@ -696,8 +696,8 @@ def run_action(self, request):
last_refresh = time.time()
players = []
refresh_time = time.time()
- for i in self.wrapper.servervitals.players:
- player = self.wrapper.servervitals.players[i]
+ for i in self.wrapper.players:
+ player = self.wrapper.players[i]
players.append({
"name": i,
"loggedIn": player.loggedIn,
@@ -743,17 +743,17 @@ def run_action(self, request):
mem_use = self.wrapper.memory_usage()
wrapper_peak_mem = mem_use["peak"] * 1000
wrapper_rss_mem = mem_use["rss"] * 1000
- stats = {"playerCount": (len(self.wrapper.servervitals.players),
- self.wrapper.servervitals.maxplayers),
+ stats = {"playerCount": (len(self.wrapper.players),
+ self.wrapper.proxy.maxplayers),
"players": players,
"plugins": plugins,
- "server_state": self.wrapper.servervitals.state,
+ "server_state": self.wrapper.javaserver.state,
"wrapper_build": self.wrapper.getbuildstring(),
"console": console_scrollback,
"chat": chat_scrollback,
- "level_name": self.wrapper.servervitals.worldname,
- "server_version": self.wrapper.servervitals.version,
- "motd": self.wrapper.servervitals.motd,
+ "level_name": self.wrapper.javaserver.worldname,
+ "server_version": self.wrapper.javaserver.version,
+ "motd": self.wrapper.javaserver.motd,
"last_refresh": refresh_time,
"disk_avail": self.web.getdisk_usage(),
"server_name": self.config["Web"]["server-name"],
@@ -761,7 +761,7 @@ def run_action(self, request):
"wrapper_memory_rss": wrapper_rss_mem,
"wrapper_memory_peak": wrapper_peak_mem,
"server_memory_graph": memory_graph,
- "world_size": self.wrapper.servervitals.worldsize
+ "world_size": self.wrapper.javaserver.worldsize
}
return stats
diff --git a/wrapper/proxy/base.py b/wrapper/proxy/base.py
index 82762651..d4a59d68 100644
--- a/wrapper/proxy/base.py
+++ b/wrapper/proxy/base.py
@@ -20,11 +20,9 @@
from utils.py23 import py_str
from proxy.utils.constants import *
-from proxy.utils import mcuuid
from proxy.entity.entitycontrol import EntityControl
# encryption requires 'cryptography' package.
-
try:
import proxy.utils.encryption as encryption
except ImportError:
@@ -50,101 +48,20 @@
Client = False
Packet = False
-""" The whole point of what follows was originally intended to
-support making proxy an independent thing that does not need
-a wrapper or server instance to function. Not sure it was a
-great idea, but... We shall see."""
-
-class NullEventHandler(object):
- def __init__(self):
- pass
+class Proxy(object):
+ def __init__(self, wrapper):
+ self.wrapper = wrapper
+ self.javaserver = self.wrapper.javaserver
+ self.encoding = self.wrapper.encoding
+ self.config = self.wrapper.config["Proxy"]
+ self.ent_config = self.wrapper.config["Entities"]
+ self.log = self.wrapper.log
- def callevent(self, event, payload):
- """
- An event handler must have this method that expects
- two positional arguments:
- :event: The string name of the event.
- :payload: A dictionary of items describing the event (varies
- with event.
- """
- pass
-
-
-class HaltSig(object):
- """
- HaltSig is simply a sort of dummy class created for the
- proxy. proxy expects this object with a self.halt property
- that tells proxy to shutdown. The caller maintains control
- of the Haltsig object and uses it to signal the proxy to
- shut down. The caller will import this class, instantiate
- it, and then pass the object to proxy as the argument for
- termsignal."""
- def __init__(self):
- self.halt = False
-
-
-class ProxyConfig(object):
- def __init__(self):
- self.proxy = {
- "auto-name-changes": True,
- "hidden-ops": [],
- "max-players": 1024,
- "online-mode": True,
- "proxy-bind": "0.0.0.0",
- "proxy-enabled": True,
- "proxy-port": 25570,
- "silent-ipban": True,
- }
- self.entity = {
- "enable-entity-controls": False,
- "entity-update-frequency": 4,
- "thin-chicken": 30,
- "thin-cow": 40,
- "thin-sheep": 40,
- "thin-zombie_pigman": 200,
- "thinning-activation-threshhold": 100,
- "thinning-frequency": 30
- }
-
-
-"""
-class ServerVitals(object):
- def __init__(self, playerobjects):
- self.serverpath = ""
- self.state = 0
- self.server_port = "25564"
- self.command_prefix = "/"
- self.players = playerobjects
- self.entity_control = None
- self.timeofday = -1
- self.spammy_stuff = ["found nothing", "vehicle of", "Wrong location!",
- "Tried to add entity", ]
self.clients = []
- self.ownernames = {}
- self.operator_list = []
- self.properties = {}
- self.worldname = None
- self.worldsize = 0
self.maxplayers = 20
- self.motd = None
- self.serverIcon = None
- self.protocolVersion = -1
- self.version = ""
- self.version_compute = 0
-"""
-
-
-class Proxy(object):
- def __init__(self, termsignal, config, servervitals, loginstance,
- usercache_object, eventhandler, encoding="utf-8"):
+ self.command_prefix = self.config["command-prefix"]
- self.encoding = encoding
- self.srv_data = servervitals
- self.config = config.proxy
- self.ent_config = config.entity
-
- self.log = loginstance
# encryption = False if proxy.utils.encryption does not import
if not encryption and self.config["proxy-enabled"]:
self.log.error(importerror)
@@ -157,22 +74,19 @@ def __init__(self, termsignal, config, servervitals, loginstance,
"esources for possible solutions")
raise ImportError()
- self.usercache = usercache_object.Data
- self.usercache_obj = usercache_object
- self.eventhandler = eventhandler
- self.uuids = mcuuid.UUIDS(self.log, self.usercache)
+ self.usercache_obj = self.wrapper.wrapper_usercache
+ self.usercache = self.usercache_obj.Data
+ self.eventhandler = self.wrapper.events
+ self.uuids = self.wrapper.uuids
- # termsignal is an object with a `halt` property set to True/False
- # it represents the calling program's run status
- self.caller = termsignal
- # Proxy's run status (set True to shutdown/ end `host()` while loop
+ # Proxy's run status (set True to shutdown/ end `host()` while loop)
self.abort = False
# self assignments (gets specific values)
self.proxy_bind = self.config["proxy-bind"]
self.proxy_port = int(self.config["proxy-port"])
self.silent_ip_banning = self.config["silent-ipban"]
- self.srv_data.maxPlayers = self.config["max-players"]
+ self.maxlayers = self.config["max-players"]
self.proxy_worlds = self.config["worlds"]
self.usehub = self.config["built-in-hub"]
self.onlinemode = self.config["online-mode"]
@@ -212,7 +126,7 @@ def host(self):
server is fully up and running."""
# loops while server is not started (STARTED = 2)
- while not self.srv_data.state == 2:
+ while not self.javaserver.state == 2:
time.sleep(1)
# get the protocol version from the server
@@ -223,8 +137,8 @@ def host(self):
"check server/wrapper configs? (%s)", e)
args = [-1, "none", False]
- self.srv_data.protocolVersion = args[0]
- self.srv_data.version = args[1]
+ self.javaserver.protocolVersion = args[0]
+ self.javaserver.version = args[1]
self.forge = args[2]
if self.forge:
self.mod_info["modinfo"] = args[3]
@@ -247,7 +161,7 @@ def host(self):
self.entity_control = EntityControl(self)
# accept clients and start their threads
- while not (self.abort or self.caller.halt):
+ while not (self.abort or self.wrapper.haltsig.halt):
try:
sock, addr = self.proxy_socket.accept()
except Exception as e:
@@ -259,6 +173,7 @@ def host(self):
if self.silent_ip_banning and banned_ip:
# 0: done receiving, 1: done sending, 2: both
sock.shutdown(2)
+ sock.close()
self.log.info("Someone tried to connect from a banned ip:"
" %s (connection refused)", addr)
continue
@@ -272,11 +187,11 @@ def host(self):
def removestaleclients(self):
"""removes aborted client and player objects"""
- for i, client in enumerate(self.srv_data.clients):
- if self.srv_data.clients[i].abort:
- if self.srv_data.clients[i].username in self.srv_data.players:
- del self.srv_data.players[self.srv_data.clients[i].username]
- self.srv_data.clients.pop(i)
+ for i, client in enumerate(self.clients):
+ if self.clients[i].abort:
+ if self.clients[i].username in self.wrapper.players:
+ del self.wrapper.players[self.clients[i].username]
+ self.clients.pop(i)
def pollserver(self, host="localhost", port=None):
"""
@@ -289,7 +204,7 @@ def pollserver(self, host="localhost", port=None):
modinfo (if Forge) ]
"""
if port is None:
- port = self.srv_data.server_port
+ port = self.javaserver.server_port
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -303,7 +218,7 @@ def pollserver(self, host="localhost", port=None):
# Disconnect
packet.sendpkt(0x00, [NULL, ], ["", ])
packet.flush()
- self.srv_data.protocolVersion = -1
+ self.javaserver.protocolVersion = -1
container = []
while True:
pkid, packet_tuple = packet.grabpacket()
@@ -352,7 +267,9 @@ def use_newname(self, oldname, newname, realuuid, client):
old_local_uuid = self.uuids.getuuidfromname(oldname)
new_local_uuid = self.uuids.getuuidfromname(newname)
cwd = "%s/%s" % (
- self.srv_data.serverpath, self.srv_data.worldname)
+ self.javaserver.serverpath,
+ self.javaserver.worldname
+ )
self.uuids.convert_files(old_local_uuid, new_local_uuid, cwd)
self.usercache[realuuid]["localname"] = newname
client.info["username"] = newname
@@ -366,7 +283,7 @@ def getclientbyofflineserveruuid(self, uuid):
:return: the matching client
"""
attempts = ["Search: %s" % str(uuid)]
- for client in self.srv_data.clients:
+ for client in self.clients:
attempts.append("try: client-%s uuid-%s serveruuid-%s name-%s" %
(client, client.wrapper_uuid.string,
client.local_uuid.string, client.username))
@@ -375,7 +292,7 @@ def getclientbyofflineserveruuid(self, uuid):
return client
self.log.debug("getclientbyofflineserveruuid failed: \n %s", attempts)
- self.log.debug("POSSIBLE CLIENTS: \n %s", self.srv_data.clients)
+ self.log.debug("POSSIBLE CLIENTS: \n %s", self.clients)
return False # no client
def banplayer(self, playername, reason="Banned by an operator",
@@ -398,7 +315,9 @@ def getuuidbanreason(self, uuid):
:param uuid: uuid of player as string
:return: string representing ban reason
"""
- banlist = getjsonfile("banned-players", self.srv_data.serverpath)
+ banlist = getjsonfile(
+ "banned-players", self.javaserver.serverpath
+ )
if banlist:
banrecord = find_in_json(banlist, "uuid", uuid)
return "%s by %s" % (banrecord["reason"], banrecord["source"])
@@ -418,7 +337,9 @@ def banuuid(self, uuid, reason="The Ban Hammer has spoken!",
This probably only works on 1.7.10 servers or later
"""
- banlist = getjsonfile("banned-players", self.srv_data.serverpath)
+ banlist = getjsonfile(
+ "banned-players", self.javaserver.serverpath
+ )
if banlist is not False: # file and directory exist.
if banlist is None: # file was empty or not valid
banlist = dict() # ensure valid dict before operating on it
@@ -442,7 +363,7 @@ def banuuid(self, uuid, reason="The Ban Hammer has spoken!",
"reason": reason})
if putjsonfile(banlist,
"banned-players",
- self.srv_data.serverpath):
+ self.javaserver.serverpath):
# this actually is not needed. Commands now handle the kick.
console_command = "kick %s %s" % (name, reason)
self.run_command(console_command)
@@ -467,7 +388,9 @@ def banuuidraw(self, uuid, username, reason="The Ban Hammer has spoken!",
This probably only works on 1.7.10 servers or later
"""
- banlist = getjsonfile("banned-players", self.srv_data.serverpath)
+ banlist = getjsonfile(
+ "banned-players", self.javaserver.serverpath
+ )
if banlist is not False: # file and directory exist.
if banlist is None: # file was empty or not valid
banlist = dict() # ensure valid dict before operating on it
@@ -490,7 +413,7 @@ def banuuidraw(self, uuid, username, reason="The Ban Hammer has spoken!",
"reason": reason})
if putjsonfile(banlist,
"banned-players",
- self.srv_data.serverpath):
+ self.javaserver.serverpath):
self.log.info("kicking %s... %s", username, reason)
console_command = "kick %s Banned: %s" % (username, reason)
@@ -517,7 +440,7 @@ def banip(self, ipaddress, reason="The Ban Hammer has spoken!",
"""
if not isipv4address(ipaddress):
return "Invalid IPV4 address: %s" % ipaddress
- banlist = getjsonfile("banned-ips", self.srv_data.serverpath)
+ banlist = getjsonfile("banned-ips", self.javaserver.serverpath)
if banlist is not False: # file and directory exist.
if banlist is None: # file was empty or not valid
banlist = dict() # ensure valid dict before operating on it
@@ -537,9 +460,10 @@ def banip(self, ipaddress, reason="The Ban Hammer has spoken!",
"source": source,
"expires": expiration,
"reason": reason})
- if putjsonfile(banlist, "banned-ips", self.srv_data.serverpath):
+ if putjsonfile(banlist, "banned-ips",
+ self.javaserver.serverpath):
banned = ""
- for client in self.srv_data.clients:
+ for client in self.clients:
if client.ip == str(ipaddress):
console_command = "kick %s Your IP is Banned!" % client.username # noqa
@@ -555,7 +479,7 @@ def banip(self, ipaddress, reason="The Ban Hammer has spoken!",
def pardonip(self, ipaddress):
if not isipv4address(ipaddress):
return "Invalid IPV4 address: %s" % ipaddress
- banlist = getjsonfile("banned-ips", self.srv_data.serverpath)
+ banlist = getjsonfile("banned-ips", self.javaserver.serverpath)
if banlist is not False: # file and directory exist.
if banlist is None: # file was empty or not valid
return "No IP bans have ever been recorded."
@@ -564,7 +488,8 @@ def pardonip(self, ipaddress):
for x in banlist:
if x == banrecord:
banlist.remove(x)
- if putjsonfile(banlist, "banned-ips", self.srv_data.serverpath):
+ if putjsonfile(banlist, "banned-ips",
+ self.javaserver.serverpath):
return "pardoned %s" % ipaddress
return "Could not write banlist to disk"
else:
@@ -574,7 +499,9 @@ def pardonip(self, ipaddress):
return "Banlist not found on disk" # error text
def pardonuuid(self, uuid):
- banlist = getjsonfile("banned-players", self.srv_data.serverpath)
+ banlist = getjsonfile(
+ "banned-players", self.javaserver.serverpath
+ )
if banlist is not False: # file and directory exist.
if banlist is None: # file was empty or not valid
return "No bans have ever been recorded..?"
@@ -585,7 +512,7 @@ def pardonuuid(self, uuid):
banlist.remove(x)
if putjsonfile(banlist,
"banned-players",
- self.srv_data.serverpath):
+ self.javaserver.serverpath):
name = self.uuids.getusernamebyuuid(str(uuid))
return "pardoned %s" % name
return "Could not write banlist to disk"
@@ -595,7 +522,9 @@ def pardonuuid(self, uuid):
return "Banlist not found on disk" # error text
def pardonname(self, username):
- banlist = getjsonfile("banned-players", self.srv_data.serverpath)
+ banlist = getjsonfile(
+ "banned-players", self.javaserver.serverpath
+ )
if banlist is not False: # file and directory exist.
if banlist is None: # file was empty or not valid
return "No bans have ever been recorded..?"
@@ -606,7 +535,7 @@ def pardonname(self, username):
banlist.remove(x)
if putjsonfile(banlist,
"banned-players",
- self.srv_data.serverpath):
+ self.javaserver.serverpath):
return "pardoned %s" % username
return "Could not write banlist to disk"
else:
@@ -615,7 +544,9 @@ def pardonname(self, username):
return "Banlist not found on disk" # error text
def isuuidbanned(self, uuid): # Check if the UUID of the user is banned
- banlist = getjsonfile("banned-players", self.srv_data.serverpath)
+ banlist = getjsonfile(
+ "banned-players", self.javaserver.serverpath
+ )
if banlist: # make sure banlist exists
banrecord = find_in_json(banlist, "uuid", str(uuid))
if banrecord:
@@ -635,7 +566,7 @@ def isuuidbanned(self, uuid): # Check if the UUID of the user is banned
return False # banlist empty or record not found
def isipbanned(self, ipaddress): # Check if the IP address is banned
- banlist = getjsonfile("banned-ips", self.srv_data.serverpath)
+ banlist = getjsonfile("banned-ips", self.javaserver.serverpath)
if banlist: # make sure banlist exists
for record in banlist:
_ip = record["ip"]
diff --git a/wrapper/proxy/client/clientconnection.py b/wrapper/proxy/client/clientconnection.py
index 9da4ce33..d046348c 100644
--- a/wrapper/proxy/client/clientconnection.py
+++ b/wrapper/proxy/client/clientconnection.py
@@ -27,7 +27,6 @@
from proxy.packets import mcpackets_cb
from proxy.utils.constants import *
-from proxy.utils.mcuuid import MCUUID
from api.helpers import processcolorcodes, getjsonfile, putjsonfile
@@ -44,8 +43,7 @@ class Client(object):
client (self.packet.sendpkt())
Client receives the parent proxy as it's argument.
- No longer receives the proxy's wrapper instance! All
- data is passed via srv_data from proxy's srv_data.
+
"""
def __init__(self, proxy, clientsock, client_addr, banned=False):
@@ -53,9 +51,10 @@ def __init__(self, proxy, clientsock, client_addr, banned=False):
self.client_socket = clientsock
self.client_address = client_addr
self.proxy = proxy
+ self.wrapper = self.proxy.wrapper
+ self.javaserver = self.wrapper.javaserver
self.public_key = self.proxy.public_key
self.private_key = self.proxy.private_key
- self.srv_data = self.proxy.srv_data
self.log = self.proxy.log
self.ipbanned = banned
@@ -76,9 +75,9 @@ def __init__(self, proxy, clientsock, client_addr, banned=False):
self.MOTD = {}
# client will reset this later, if need be..
- self.clientversion = self.srv_data.protocolVersion
+ self.clientversion = self.javaserver.protocolVersion
# default server port (to this wrapper's server)
- self.serverport = self.srv_data.server_port
+ self.serverport = self.javaserver.server_port
# packet stuff
self.pktSB = mcpackets_sb.Packets(self.clientversion)
@@ -221,7 +220,7 @@ def notify_disconnect(self, message):
)
time.sleep(.4)
self.disc_request = False
- self.change_servers("127.0.0.1", self.serverport)
+ self.change_servers("localhost", self.serverport)
else:
self.disc_request = True
@@ -268,15 +267,11 @@ def handle(self):
self._close_server_instance("Client Handle Ended")
try:
self.client_socket.shutdown(2)
- except AttributeError:
- self.log.debug(
- "(%s, %s) handle aborted and self.client_socket has no"
- " shutdown attribute", self.username, self.ip
- )
- except socket_error:
+ self.client_socket.close()
+ except (AttributeError, socket_error):
self.log.debug(
- "(%s, %s) handle aborted and self.client_socket experienced a "
- "socket error while doing 'shutdown'.", self.username, self.ip
+ "(%s, %s) handle ending and client_socket does not "
+ "exist any longer", self.username, self.ip
)
def _flush_loop(self):
@@ -306,7 +301,7 @@ def _flush_loop(self):
if self.username != "PING REQUEST":
self.log.debug("%s clientconnection _flush_loop thread ended",
self.username)
- self.proxy.removestaleclients() # from proxy.srv_data.clients
+ self.proxy.removestaleclients() # from proxy.clients
def _parse(self, pkid):
"""
@@ -398,6 +393,7 @@ def _parse_handshaking_legacy(self):
)
self.packet.send_raw(0xff+0x00+0x00+0x00)
self.client_socket.shutdown(2)
+ self.client_socket.close()
self.abort = True
def _parse_handshaking(self):
@@ -443,20 +439,20 @@ def _parse_handshaking(self):
# and cannot be sure of the info itself
if not self.onlinemode:
# Spigot and Wrapper share this in common:
- self.mojanguuid = MCUUID(splitaddress[2])
+ self.mojanguuid = self.proxy.wrapper.mcuuid(splitaddress[2])
self.info["realuuid"] = self.mojanguuid.string
self.ip = splitaddress[1]
if len(splitaddress) > 3 and splitaddress[3] == "WPY":
self.info["client-is-wrapper"] = True
- if self.srv_data.protocolVersion == -1:
+ if self.javaserver.protocolVersion == -1:
# ... returns -1 to signal no server
self.disconnect(
"The server is not started (protocol not established)."
)
return False
- if not self.srv_data.state == 2:
+ if not self.javaserver.state == 2:
self.disconnect(
"Server has not finished booting. Please try"
" connecting again in a few seconds"
@@ -467,7 +463,7 @@ def _parse_handshaking(self):
self.disconnect("You're running an unsupported snapshot"
" (protocol: %s)!" % self.clientversion)
return False
- if self.srv_data.protocolVersion != self.clientversion:
+ if self.javaserver.protocolVersion != self.clientversion:
self.disconnect("You're not running the same Minecraft"
" version as the server!")
return False
@@ -499,16 +495,16 @@ def _parse_status_request(self):
back to HANDSHAKE mode.
"""
sample = []
- for player in self.srv_data.players:
- playerobj = self.srv_data.players[player]
+ for player in self.proxy.wrapper.players:
+ playerobj = self.proxy.wrapper.players[player]
if playerobj.username not in self.hidden_ops:
sample.append({"name": playerobj.username,
"id": str(playerobj.mojangUuid)})
if len(sample) > 5:
break
- reported_version = self.srv_data.protocolVersion
- reported_name = self.srv_data.version
- motdtext = self.srv_data.motd
+ reported_version = self.javaserver.protocolVersion
+ reported_name = self.javaserver.version
+ motdtext = self.javaserver.motd
if self.clientversion >= PROTOCOL_1_8START:
motdtext = processcolorcodes(motdtext.replace(
"\\", ""))
@@ -516,7 +512,7 @@ def _parse_status_request(self):
"description": motdtext,
"players": {
"max": int(self.proxy.config["max-players"]),
- "online": len(self.srv_data.players),
+ "online": len(self.proxy.wrapper.players),
"sample": sample
},
"version": {
@@ -526,8 +522,8 @@ def _parse_status_request(self):
}
# add Favicon, if it exists
- if self.srv_data.serverIcon:
- self.MOTD["favicon"] = self.srv_data.serverIcon
+ if self.javaserver.servericon:
+ self.MOTD["favicon"] = self.javaserver.servericon
# add Forge information, if applicable.
if self.proxy.forge:
@@ -625,7 +621,7 @@ def _parse_login_encr_response(self):
"""
# read response Tokens - "shared_secret|verify_token"
- if self.srv_data.protocolVersion < 6:
+ if self.javaserver.protocolVersion < 6:
data = self.packet.readpkt([BYTEARRAY_SHORT, BYTEARRAY_SHORT])
else:
data = self.packet.readpkt([BYTEARRAY, BYTEARRAY])
@@ -684,7 +680,7 @@ def _logon_client_into_proxy(self):
return
# add client (or disconnect if full
- if len(self.proxy.srv_data.clients) < self.proxy.config["max-players"]:
+ if len(self.proxy.clients) < self.proxy.config["max-players"]:
self._add_client()
else:
uuids = getjsonfile(
@@ -744,7 +740,7 @@ def _logon_client_into_proxy(self):
self.state = HANDSHAKE
self.disconnect("Login denied by a Plugin.")
- del self.srv_data.players[self.username]
+ del self.proxy.wrapper.players[self.username]
return
self.permit_disconnect_from_server = True
@@ -757,8 +753,8 @@ def _logon_client_into_proxy(self):
# set compression
# compression was at the bottom of _login_authenticate_client...
if self.clientversion >= PROTOCOL_1_8START:
- if "network-compression-threshold" in self.proxy.srv_data.properties: # noqa
- comp = self.proxy.srv_data.properties[
+ if "network-compression-threshold" in self.javaserver.properties: # noqa
+ comp = self.javaserver.properties[
"network-compression-threshold"]
self.packet.sendpkt(
self.pktCB.LOGIN_SET_COMPRESSION[PKT], [VARINT], [comp])
@@ -873,7 +869,7 @@ def _close_server_instance(self, term_message):
if self.server_connection:
self.server_connection.close_server(term_message)
- def change_servers(self, ip="127.0.0.1", port=25600):
+ def change_servers(self, ip="localhost", port=25600):
"""
Leaves the current proxy server connection and attempts a
new server connection. If it fails, it attempts to re-connect
@@ -1248,7 +1244,7 @@ def _login_authenticate_client(self, server_id):
# }
requestdata = r.json()
playerid = requestdata["id"]
- self.wrapper_uuid = MCUUID(playerid)
+ self.wrapper_uuid = self.proxy.wrapper.mcuuid(playerid)
if requestdata["name"] != self.username:
self.disconnect("Client's username did not"
@@ -1334,8 +1330,8 @@ def _add_client(self):
Put client into server data. (player login will be called
later by mcserver.py)
"""
- if self not in self.proxy.srv_data.clients:
- self.proxy.srv_data.clients.append(self)
+ if self not in self.proxy.clients:
+ self.proxy.clients.append(self)
def _keep_alive_tracker(self):
"""
@@ -1386,10 +1382,10 @@ def _remove_client_and_player(self):
onto the local server (which normally keeps tabs on player
and client objects).
"""
- if self.username in self.proxy.srv_data.players:
- if self.proxy.srv_data.players[self.username].client.state != LOBBY:
- self.proxy.srv_data.players[self.username].abort = True
- del self.proxy.srv_data.players[self.username]
+ if self.username in self.proxy.wrapper.players:
+ if self.proxy.wrapper.players[self.username].client.state != LOBBY:
+ self.proxy.wrapper.players[self.username].abort = True
+ del self.proxy.wrapper.players[self.username]
def send_client_settings(self):
"""
diff --git a/wrapper/proxy/client/parse_sb.py b/wrapper/proxy/client/parse_sb.py
index 0d8cc9c9..5e9ee982 100644
--- a/wrapper/proxy/client/parse_sb.py
+++ b/wrapper/proxy/client/parse_sb.py
@@ -10,7 +10,6 @@
import time
from proxy.utils.constants import *
-from proxy.utils.mcuuid import MCUUID
# noinspection PyMethodMayBeStatic
@@ -26,7 +25,7 @@ def __init__(self, client, packet):
self.pktSB = self.client.pktSB
self.pktCB = self.client.pktCB
- self.command_prefix = self.proxy.srv_data.command_prefix
+ self.command_prefix = self.proxy.command_prefix
self.command_prefix_non_standard = self.command_prefix != "/"
def keep_alive(self):
@@ -78,12 +77,14 @@ def _plugin_response(self, response):
"""
if "ip" in response:
self.client.info["username"] = response["username"]
- self.client.info["realuuid"] = MCUUID(response["realuuid"]).string
+ self.client.info["realuuid"] = self.proxy.wrapper.mcuuid(
+ response["realuuid"]).string
self.client.info["ip"] = response["ip"]
self.client.ip = response["ip"]
if response["realuuid"] != "":
- self.client.mojanguuid = MCUUID(response["realuuid"])
+ self.client.mojanguuid = self.proxy.wrapper.mcuuid(
+ response["realuuid"])
self.client.username = response["username"]
return True
else:
@@ -173,7 +174,7 @@ def play_chat_message(self):
return True
try:
- player = self.client.srv_data.players[self.client.username]
+ player = self.client.proxy.wrapper.players[self.client.username]
except KeyError:
return False
payload = self.proxy.eventhandler.callevent("player.rawMessage", {
@@ -228,7 +229,7 @@ def play_chat_message(self):
"playername":
self.client.username,
"player":
- self.client.srv_data.players[self.client.username],
+ self.client.proxy.wrapper.players[self.client.username],
"command":
allwords[0][1:],
"args":
@@ -287,8 +288,8 @@ def _world_hub_command(self, where=""):
return self._world_hub_help("w")
elif where == "":
- port = self.proxy.srv_data.server_port
- ip = "127.0.0.1"
+ port = self.client.javaserver.server_port
+ ip = "localhost"
else:
worlds = self.proxy.proxy_worlds
if where in worlds:
@@ -296,7 +297,7 @@ def _world_hub_command(self, where=""):
try:
ip = self.proxy.proxy_worlds[where]["ip"]
except KeyError:
- ip = "127.0.0.1"
+ ip = "localhost"
else:
return self._world_hub_help("w")
t = threading.Thread(target=self.client.change_servers,
@@ -373,7 +374,7 @@ def play_player_digging(self):
position = data[1]
try:
- player = self.client.srv_data.players[self.client.username]
+ player = self.client.proxy.wrapper.players[self.client.username]
except KeyError:
return False
# finished digging
@@ -419,7 +420,7 @@ def play_player_digging(self):
if self.client.gamemode != 1:
if not self.proxy.eventhandler.callevent("player.dig", {
"playername": self.client.username,
- "player": self.client.srv_data.players[
+ "player": self.client.proxy.wrapper.players[
self.client.username],
"position": position,
"action": "begin_break",
@@ -429,7 +430,7 @@ def play_player_digging(self):
else:
if not self.proxy.eventhandler.callevent("player.dig", {
"playername": self.client.username,
- "player": self.client.srv_data.players[
+ "player": self.client.proxy.wrapper.players[
self.client.username],
"position": position,
"action": "end_break",
@@ -536,7 +537,7 @@ def play_player_block_placement(self):
position = (position[0] + 1, position[1], position[2])
try:
- player = self.client.srv_data.players[self.client.username]
+ player = self.client.proxy.wrapper.players[self.client.username]
except KeyError:
return False
@@ -594,7 +595,7 @@ def play_use_item(self): # no 1.8 or prior packet
position = self.client.lastplacecoords[0]
try:
- player = self.client.srv_data.players[self.client.username]
+ player = self.client.proxy.wrapper.players[self.client.username]
except KeyError:
return False
if not self.proxy.eventhandler.callevent("player.interact", {
@@ -643,7 +644,7 @@ def play_player_update_sign(self):
l4 = data[6]
try:
- player = self.client.srv_data.players[self.client.username]
+ player = self.client.proxy.wrapper.players[self.client.username]
except KeyError:
return False
payload = self.proxy.eventhandler.callevent("player.createSign", {
@@ -734,7 +735,7 @@ def play_click_window(self): # click window
data = [False, 0, 0, 0, 0, 0, 0]
try:
- player = self.client.srv_data.players[self.client.username]
+ player = self.client.proxy.wrapper.players[self.client.username]
except KeyError:
return False
datadict = {
diff --git a/wrapper/proxy/entity/entitycontrol.py b/wrapper/proxy/entity/entitycontrol.py
index cb5932ba..b3a46969 100644
--- a/wrapper/proxy/entity/entitycontrol.py
+++ b/wrapper/proxy/entity/entitycontrol.py
@@ -39,11 +39,11 @@ def __init__(self, proxy):
self.proxy = proxy
self.ent_config = self.proxy.ent_config
- self.srvr_data = self.proxy.srv_data
+ self.javaserver = self.proxy.wrapper.javaserver
self._log = self.proxy.log
# Entities - living beings (includes XP orbs!)
- pre1_11 = self.srvr_data.version_compute < 11100
+ pre1_11 = self.javaserver.version_compute < 11100
entitylistobject = Entitytypes(pre1_11)
self.entitytypes = entitylistobject.entitylist
@@ -221,8 +221,8 @@ def _entity_processor(self):
self._log.debug("_entityprocessor thread started.")
timer = float(0)
# server is running
- while self.srvr_data.state in (1, 2, 4) and not (
- self.proxy.caller.halt or self.proxy.abort
+ while self.javaserver.state in (1, 2, 4) and not (
+ self.proxy.wrapper.haltsig.halt or self.proxy.abort
):
timer += .1
sleep(.1)
@@ -234,7 +234,7 @@ def _entity_processor(self):
# start looking for stale client entities
playerlist = []
- for player in self.srvr_data.clients:
+ for player in self.proxy.clients:
playerlist.append(player.username)
entity_eids = list(self.entities.keys())
for eid in entity_eids:
@@ -253,8 +253,8 @@ def _entity_thinner(self):
timer = float(0)
# while server is running
- while self.srvr_data.state in (1, 2, 4) and not (
- self.proxy.caller.halt or self.proxy.abort
+ while self.javaserver.state in (1, 2, 4) and not (
+ self.proxy.wrapper.haltsig.halt or self.proxy.abort
):
timer += .1
@@ -270,7 +270,7 @@ def _entity_thinner(self):
continue
# gather client list
- playerlist = self.srvr_data.clients
+ playerlist = self.proxy.clients
# loop through playerlist
for playerclient in playerlist:
players_position = playerclient.position
@@ -294,8 +294,8 @@ def _entity_thinner(self):
# turn off console_spam
server_msg = "Teleported %s to" % mob_type
- if server_msg not in self.srvr_data.spammy_stuff:
- self.srvr_data.spammy_stuff.append(
+ if server_msg not in self.javaserver.spammy_stuff:
+ self.javaserver.spammy_stuff.append(
"Teleported %s to" % mob_type)
# can't be too agressive with killing because
@@ -313,8 +313,6 @@ def _kill_around_player(self, position, entity_name, count):
pos = position
# send those creatures away
self._log.debug("killing %d %s" % (count, entity_name))
-
- # if self.proxy.srv_data.protocolVersion < 204:
console_command = "tp @e[type=%s,x=%d,y=%d,z=%d,c=%s] ~ ~-500 ~" % (
entity_name, pos[0], pos[1], pos[2], count)
self.proxy.run_command(console_command)
diff --git a/wrapper/proxy/packets/packet.py b/wrapper/proxy/packets/packet.py
index e7b7918b..0133737f 100644
--- a/wrapper/proxy/packets/packet.py
+++ b/wrapper/proxy/packets/packet.py
@@ -18,7 +18,6 @@
# import StringIO
# local
-from proxy.utils.mcuuid import MCUUID
from proxy.utils.constants import *
# Py3-2
@@ -77,7 +76,7 @@ def __init__(self, sock, obj):
# this is set by the calling class/method. Not presently used here,
# but could be. maybe to decide which metadata parser to use?
- self.version = self.obj.srv_data.protocolVersion
+ self.version = self.obj.javaserver.protocolVersion
self.buffer = io.BytesIO() # Py3
# self.buffer = StringIO.StringIO()
@@ -719,7 +718,7 @@ def read_position(self):
return x, y, z
def read_uuid(self):
- return MCUUID(bytes=self.read_data(16))
+ return self.obj.proxy.wrapper.mcuuid(bytes=self.read_data(16))
def read_metadata_1_9(self):
meta_data = {}
diff --git a/wrapper/proxy/server/parse_cb.py b/wrapper/proxy/server/parse_cb.py
index de0cb122..011e7f6a 100644
--- a/wrapper/proxy/server/parse_cb.py
+++ b/wrapper/proxy/server/parse_cb.py
@@ -220,7 +220,7 @@ def play_chat_message(self):
# self.log.debug(data)
try:
- player = self.client.srv_data.players[self.client.username]
+ player = self.proxy.wrapper.players[self.client.username]
except KeyError:
return False
payload = self.proxy.eventhandler.callevent(
@@ -284,7 +284,7 @@ def play_use_bed(self):
data = self.packet.readpkt([VARINT, POSITION])
try:
- player = self.client.srv_data.players[self.client.username]
+ player = self.proxy.wrapper.players[self.client.username]
except KeyError:
return False
if data[0] == self.client.server_eid:
@@ -336,7 +336,7 @@ def play_spawn_position(self):
data = self.packet.readpkt([POSITION])
try:
- player = self.client.srv_data.players[self.client.username]
+ player = self.proxy.wrapper.players[self.client.username]
except KeyError:
return False
self.proxy.eventhandler.callevent(
@@ -409,7 +409,7 @@ def play_time_update(self):
# There could be a number of clients trying to update this at once
# noinspection PyBroadException
try:
- self.proxy.srv_data.timeofday = data[1]
+ self.proxy.wrapper.javaserver.timeofday = data[1]
except:
pass
return True
@@ -441,7 +441,7 @@ def play_tab_complete(self):
print([match])
try:
- player = self.client.srv_data.players[self.client.username]
+ player = self.proxy.wrapper.players[self.client.username]
except KeyError:
return False
payload = self.proxy.eventhandler.callevent(
@@ -682,7 +682,7 @@ def play_attach_entity(self):
if entityeid == self.client.server_eid:
try:
- player = self.client.srv_data.players[self.client.username]
+ player = self.proxy.wrapper.players[self.client.username]
except KeyError:
return False
if not leash:
diff --git a/wrapper/proxy/server/serverconnection.py b/wrapper/proxy/server/serverconnection.py
index 27fcd62e..37a18a42 100644
--- a/wrapper/proxy/server/serverconnection.py
+++ b/wrapper/proxy/server/serverconnection.py
@@ -19,7 +19,6 @@
from proxy.packets import mcpackets_cb
from proxy.utils.constants import *
-from proxy.utils.mcuuid import MCUUID
# noinspection PyMethodMayBeStatic,PyBroadException
@@ -43,10 +42,11 @@ def __init__(self, client, ip=None, port=None):
self.client = client
self.username = self.client.username
self.proxy = client.proxy
+ self.wrapper = self.proxy.wrapper
+ self.javaserver = self.wrapper.javaserver
self.log = client.log
self.ip = ip
self.port = port
- self.srv_data = self.proxy.srv_data
# server setup and operating paramenters
self.abort = False
@@ -72,7 +72,7 @@ def __init__(self, client, ip=None, port=None):
def _refresh_server_version(self):
"""Get serverversion for mcpackets use"""
- self.version = self.proxy.srv_data.protocolVersion
+ self.version = self.proxy.javaserver.protocolVersion
self.pktSB = mcpackets_sb.Packets(self.version)
self.pktCB = mcpackets_cb.Packets(self.version)
self.parse_cb = ParseCB(self, self.packet)
@@ -89,7 +89,7 @@ def connect(self):
# Connect to a local server address
if self.ip is None:
self.server_socket.connect((
- "localhost", self.proxy.srv_data.server_port))
+ "localhost", self.proxy.javaserver.server_port))
# Connect to some specific server address
else:
@@ -167,7 +167,7 @@ def close_server(self, reason="Disconnected"):
return False
self.log.info("%s's proxy server connection closed: %s",
- self.username, reason)
+ self.username, reason)
# end 'handle' and 'flush_loop' cleanly
self.abort = True
@@ -176,6 +176,7 @@ def close_server(self, reason="Disconnected"):
# noinspection PyBroadException
try:
self.server_socket.shutdown(2)
+ self.server_socket.close()
self.log.debug("Sucessfully closed server socket for"
" %s", self.username)
# allow old packet and socket to be Garbage Collected
@@ -260,13 +261,9 @@ def _parse_login_encr_request(self):
return False
# Login Success - UUID & Username are sent in this packet as strings
+ # no point in parsing because we already know the UUID and Username
def _parse_login_success(self):
self.state = PLAY
- # todo - we may not need to assign this to a variable.
- # (we supplied uuid/name anyway!)
- # noinspection PyUnusedLocal
- data = self.packet.readpkt([STRING, STRING])
- self.client.local_uuid = MCUUID(data[0])
return False
def _parse_login_set_compression(self):