Commit a6ab747d authored by talljosh's avatar talljosh

Merging unstable into default with release of version 1.13.0

......@@ -26,3 +26,5 @@ fd85c1d4bfa43e9c420cd412779388392732a092 release-1.13.0a1
3944abe8e4226bf52b639c4c730d5fcbde491a51 release-1.13.0a3
ee487c6c10187577b9ba2691c1f6a1f711e71c6c release-1.13.0a4
3c1d273627c53ca9d1fc12618a1efc24c96c6d93 release-1.13.0a5
58de941ed00367ff4b956b0b895ca6d30bc7ff60 release-1.13.0b1
34d9db97cce00854d7e9fa8905fabf5e955e7d86 release-1.13.0b2
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="RIGHT_MARGIN" value="79" />
<option name="WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN" value="true" />
<Python>
<option name="ALIGN_COLLECTIONS_AND_COMPREHENSIONS" value="false" />
<option name="ALIGN_MULTILINE_IMPORTS" value="false" />
<option name="NEW_LINE_AFTER_COLON" value="true" />
<option name="DICT_NEW_LINE_AFTER_LEFT_BRACE" value="true" />
<option name="DICT_NEW_LINE_BEFORE_RIGHT_BRACE" value="true" />
<option name="OPTIMIZE_IMPORTS_JOIN_FROM_IMPORTS_WITH_SAME_SOURCE" value="true" />
<option name="FROM_IMPORT_NEW_LINE_AFTER_LEFT_PARENTHESIS" value="true" />
<option name="FROM_IMPORT_NEW_LINE_BEFORE_RIGHT_PARENTHESIS" value="true" />
<option name="FROM_IMPORT_PARENTHESES_FORCE_IF_MULTILINE" value="true" />
<option name="FROM_IMPORT_TRAILING_COMMA_IF_MULTILINE" value="true" />
</Python>
<codeStyleSettings language="HTML">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="Python">
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="false" />
</codeStyleSettings>
</code_scheme>
</component>
\ No newline at end of file
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>
\ No newline at end of file
......@@ -5,7 +5,7 @@
<inspection_tool class="PyArgumentListInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PyAugmentAssignmentInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="PyBroadExceptionInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="PyCompatibilityInspection" enabled="true" level="WARNING" enabled_by_default="true">
<inspection_tool class="PyCompatibilityInspection" enabled="false" level="WARNING" enabled_by_default="false">
<option name="ourVersions">
<value>
<list size="1">
......
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Test Trosnoth" type="tests" factoryName="py.test">
<module name="trosnoth" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs />
<option name="SDK_HOME" value="/usr/bin/python2.7" />
<option name="WORKING_DIRECTORY" value="" />
<option name="IS_MODULE_SDK" value="false" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<module name="trosnoth" />
<option name="SCRIPT_NAME" value="" />
<option name="CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
......@@ -21,6 +20,19 @@
<option name="params" value="" />
<option name="USE_PARAM" value="false" />
<option name="USE_KEYWORD" value="false" />
<method />
<module name="trosnoth" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="_new_keywords" value="&quot;&quot;" />
<option name="_new_additionalArguments" value="&quot;&quot;" />
<option name="_new_legacyInformationCopiedToNew" value="true" />
<option name="_new_target" value="&quot;$PROJECT_DIR$/trosnoth&quot;" />
<option name="_new_targetType" value="&quot;PATH&quot;" />
<method v="2" />
</configuration>
</component>
\ No newline at end of file
v1.13.0
* Rewrote collision detection system to use separating axis theorem. This
eliminates the possibility of falling through walls.
* Improved grappling hook---you can now swing on it, and it has a nicer feel.
* Grappling hook is now the default action for right mouse button.
* Overhauled bot pathfinding so that bots can use momentum-based physics and grappling hook.
* Removed some map sections which were hard to get around and simplified others.
* Players can now hold on to the roof, and shoot while holding the walls or roof.
* Orbs now spin.
* Added taunts / emotes.
* Using trajectory assistance while a ghost now shows trajectory for firing as soon as player respawns.
* When using ninja, added a radial indicator around orbs to show how close player can get before coming visible.
* Increased player terminal velocity, and grenade velocity.
* Windows EXE and installer are now signed, thanks to pygame.org artist in residence grant money.
* Added server support for grouping matches together into tournaments and showing some aggregated statistics and leader boards.
* Moved some server command-line options to database or configuration file.
* Moved some insecure hard-coded server settings into configuration file.
* Server now opens web interface as admin user unless run with --no-browser command-line option.
* Server now runs bots in a separate process to improve server responsiveness.
* Made minor improvements to server web interface.
* Trosball no longer starts inside a wall.
* Trosball games can no longer go on forever.
* Fixed Trosball bug where front line no longer appeared to be moving with the ball.
* Fixed bug where topmost zones would show upwards indicator lights.
* Fixed bug in server record of player zone scores.
* Fixed traceback triggered in observer/replay mode when viewing an invisible player.
* Made Trosnoth still work on display systems with odd bit depths.
* Trosnoth now works on machines with no sound subsystem.
* Fixed bug where, when run with some builds of pygame, music would stop after the first piece.
* Migrated codebase to Python 3 and Django 2.
* Removed murmur/mumble integration as nobody is using it.
* Removed some unused code.
v1.12.2
* Added a finite, slightly random reaction time for bots when they try to shoot.
* Friendly players are now shown as a short name on the minimap instead of a
......
......@@ -446,11 +446,13 @@ def isSymmetrical(obstacles):
def warning(message):
print('WARNING: ' + message, file=sys.stderr)
sys.stderr.write('WARNING: ' + message)
sys.stderr.flush()
def error(message):
print('ERROR: ' + message, file=sys.stderr)
sys.stderr.write('ERROR: ' + message)
sys.stderr.flush()
sys.exit(1)
......
......@@ -3,8 +3,9 @@ import os
import sys
if __name__ == "__main__":
# Make sure that this version of trosnoth is run.
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
if not getattr(sys, 'frozen', False):
# Make sure that this version of trosnoth is run.
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "trosnoth.server.settings")
......
#!/usr/bin/python3
import sys
if sys.argv[1:] and sys.argv[1] == 'arena':
from trosnoth.server.arena import main
sys.argv[:2] = [' '.join(sys.argv[:2])]
main()
elif sys.argv[1:] and sys.argv[1] == 'bots':
from trosnoth.botprocess import main
sys.argv[:2] = [' '.join(sys.argv[:2])]
main()
else:
print('This is an internal support program for Trosnoth server.')
print('It is not designed to be run directly.')
sys.exit(1)
\ No newline at end of file
import imp
import os.path
import sys
from setuptools import setup, find_packages
from setuptools import find_packages, setup
here = os.path.abspath(os.path.dirname(__file__))
trosnoth_version = imp.load_source('trosnoth.version', os.path.join(
here, 'trosnoth', 'version.py')).version
def main():
global trosnoth_version
if 'py2exe' in sys.argv:
import py2exe
# Make sure py2exe knows which data files to include.
paths = [
'trosnoth/data',
'trosnoth/data/achievements',
'trosnoth/data/blocks',
'trosnoth/data/blocks/custom',
'trosnoth/data/config',
'trosnoth/data/fonts',
'trosnoth/data/music',
'trosnoth/data/sound',
'trosnoth/data/sprites',
'trosnoth/data/startupMenu',
'trosnoth/data/statGeneration',
'trosnoth/data/themes',
'trosnoth/data/themes/pirate',
'trosnoth/data/themes/pirate/blocks',
'trosnoth/data/themes/pirate/config',
'trosnoth/data/themes/pirate/fonts',
'trosnoth/data/themes/pirate/sprites',
'trosnoth/data/themes/pirate/startupMenu',
'trosnoth/data/web',
]
data = []
for path in paths:
files = []
for filename in os.listdir(path):
if filename in ('__init__.py', '__init__.pyc'):
continue
fn = os.path.join(path, filename)
if os.path.isfile(fn):
files.append(fn)
data.append((path, files))
moreargs = {
'console': [
{'script': 'scripts/trosnoth',
'icon_resources': [(1, 'wininstall/icon.ico')]
},
'scripts/trosnoth-server',
],
'data_files': data,
'options': {
'py2exe': {
'includes': 'zope.interface,pygame._view,trosnoth.bots.john,trosnoth.bots.ranger,trosnoth.bots.balance,trosnoth.bots.sirrobin,trosnoth.bots.puppet,trosnoth.bots.onezone',
},
},
}
elif sys.argv[1] == 'windows':
sys.argv[1] = 'build'
PYTHON_INSTALL_DIR = os.path.dirname(os.path.dirname(os.__file__))
os.environ['TCL_LIBRARY'] = os.path.join(PYTHON_INSTALL_DIR, 'tcl', 'tcl8.6')
os.environ['TK_LIBRARY'] = os.path.join(PYTHON_INSTALL_DIR, 'tcl', 'tk8.6')
from cx_Freeze import setup, Executable
moreargs = {
'executables': [
Executable('scripts/trosnoth', icon='wininstall/icon.ico'),
],
'build_exe': {
'include_files': [
os.path.join(PYTHON_INSTALL_DIR, 'DLLs', 'tk86t.dll'),
os.path.join(PYTHON_INSTALL_DIR, 'DLLs', 'tcl86t.dll'),
],
'include_msvcr': True,
'namespace_packages': ['zope'],
'zip_excludes_package': '*',
},
}
# Windows doesn't like things like 'a1' at the end
if any(c.isalpha() for c in trosnoth_version):
trosnoth_version = trosnoth_version.replace('rc', '.').replace('a', '.').replace('b', '.')
else:
moreargs = {}
if __name__ == '__main__':
setup(name = 'trosnoth',
version = trosnoth_version,
description = 'Trosnoth network platform game',
......@@ -98,28 +16,27 @@ def main():
author_email = 'josh@trosnoth.org',
url = 'http://www.trosnoth.org/',
packages=find_packages(exclude=['test']),
# Mapping says which files each package needs.
package_data = {
'trosnoth.data.blocks': ['*.block', '*.png', '*.bmp', '*.trosblock'],
'trosnoth.data.fonts': ['*.ttf', '*.TTF', '*.txt'],
'trosnoth.data.music': ['*.ogg'],
'trosnoth.data.sound': ['*.ogg'],
'trosnoth.data.sprites': ['*.png', '*.bmp'],
'trosnoth.data.startupMenu': ['*.png', '*.txt'],
'trosnoth.data.statGeneration': ['*.htm'],
'trosnoth.data.themes': ['pirate/info.txt',
'pirate/blocks/*.png', 'pirate/config/*.cfg',
'pirate/fonts/*', 'pirate/sprites/*',
'pirate/startupMenu/*'],
'trosnoth.data': [
'config/*.cfg', 'achievements/*.png', 'web/*.png',
'pathfinding.db', 'config/*.prc'],
'trosnoth': ['gpl.txt']
},
package_data={'trosnoth': [
'data/blocks/*.block',
'data/blocks/*.trosblock',
'data/config/*.cfg',
'data/fonts/*.ttf',
'data/fonts/*.TTF',
'data/fonts/*.txt',
'data/music/*.ogg',
'data/sound/*.ogg',
'data/sprites/*.png',
'data/startupMenu/*.png',
'data/startupMenu/*.txt',
'data/statGeneration/*.htm',
'data/achievements/*.png',
'data/web/*.png',
'data/*.db',
'gpl.txt',
]},
scripts = ['scripts/trosnoth', 'scripts/trosnoth-server'],
long_description = 'Trosnoth is a very very addictive and fun network team game.' ,
long_description = 'Trosnoth is a fast-paced open source territory control team platform game.' ,
install_requires = [
'pygame',
......@@ -137,14 +54,10 @@ def main():
'Natural Language :: English',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Topic :: Games/Entertainment :: Arcade',
'Topic :: Games/Entertainment :: Side-Scrolling/Arcade Games',
],
**moreargs
)
if __name__ == '__main__':
main()
)
# -*- mode: python -*-
import os
block_cipher = None
base_dir = os.path.abspath('.')
a = Analysis(
['scripts\\trosnoth'],
pathex=[base_dir],
binaries=[],
datas=[
('trosnoth/data/blocks/*.block', 'trosnoth/data/blocks'),
('trosnoth/data/blocks/*.trosblock', 'trosnoth/data/blocks'),
('trosnoth/data/config/*.cfg', 'trosnoth/data/config'),
('trosnoth/data/fonts/*.ttf', 'trosnoth/data/fonts'),
('trosnoth/data/fonts/*.txt', 'trosnoth/data/fonts'),
('trosnoth/data/music/*.ogg', 'trosnoth/data/music'),
('trosnoth/data/sound/*.ogg', 'trosnoth/data/sound'),
('trosnoth/data/sprites/*.png', 'trosnoth/data/sprites'),
('trosnoth/data/startupMenu/*.png', 'trosnoth/data/startupMenu'),
('trosnoth/data/startupMenu/*.txt', 'trosnoth/data/startupMenu'),
('trosnoth/data/statGeneration/*.htm', 'trosnoth/data/statGeneration'),
('trosnoth/data/achievements/*.png', 'trosnoth/data/achievements'),
('trosnoth/data/web/*.png', 'trosnoth/data/web'),
('trosnoth/data/*.db', 'trosnoth/data'),
('trosnoth/gpl.txt', 'trosnoth'),
],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=['django'],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='trosnoth',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False,
icon='wininstall/icon.ico',
)
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
name='trosnoth')
#!/usr/bin/env python3
if __name__ == '__main__':
# Make sure that this version of trosnoth is run.
import os
import sys
sys.path.insert(0, os.path.join(
os.path.abspath(os.path.dirname(__file__)), '..'))
import argparse
import logging
import os
import sys
import uuid
from twisted.internet import defer, reactor
from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.internet.protocol import ProcessProtocol, Factory, ClientCreator
from twisted.protocols import amp
from trosnoth.game import RemoteGame
from trosnoth.model.mapLayout import LayoutDatabase
from trosnoth.model.universe_base import NEUTRAL_TEAM_ID
from trosnoth.network.client import TrosnothClientProtocol
from trosnoth.network.server import TrosnothServerFactory
from trosnoth.utils.event import Event
from trosnoth.utils.utils import initLogging
log = logging.getLogger(__name__)
LOCALHOST = '127.0.0.1'
class ServerSideBotProcessManager:
def __init__(self, game, logPrefix):
self.game = game
self.logPrefix = logPrefix
self.process = None
self.starting = None
self.token = None
self.waitForAMPConnection = None
self.waitForProcessStart = None
self.connectingToGame = None
self.amp = None
self.server = None
self.joiningAgents = []
def stop(self):
if self.server:
self.server.stopListening()
self.server = None
async def startBot(self, aiName, fromLevel=False, nick='', team=None):
await self.ensureProcessHasStarted()
if self.server is None:
self.connectingToGame = Event(['result'])
self.server = TrosnothServerFactory(
self.game, noAuth=True, agentCallback=self.agentConnected)
self.server.startListening(port=0, interface=LOCALHOST)
await self.amp.callRemote(
ConnectToServer, port=self.server.port.getHost().port)
connectingToGame = self.connectingToGame
self.connectingToGame = None
connectingToGame.execute(None)
elif self.connectingToGame:
await self.connectingToGame.waitOrRaise()
authTag = len(self.joiningAgents)
agentHasJoined = defer.Deferred()
self.joiningAgents.append((agentHasJoined, fromLevel))
await self.amp.callRemote(
StartBot, name=aiName, fromLevel=fromLevel, nick=nick,
teamId=team.id if team else NEUTRAL_TEAM_ID,
authTag=authTag,
)
agent = await agentHasJoined
return agent
def agentConnected(self, agent, authTag):
d, fromLevel = self.joiningAgents[authTag]
self.joiningAgents[authTag] = None
while self.joiningAgents and self.joiningAgents[-1] is None:
self.joiningAgents.pop()
agent.allowBotPlayer(fromLevel)
d.callback(agent)
async def ensureProcessHasStarted(self):
if self.starting:
await self.starting.waitOrRaise()
return
if self.process:
return
success = False
self.starting = Event(['result'])
try:
await self._startProcess()
success = True
except Exception as e:
self.starting.execute(e)
raise
else:
self.starting.execute(None)
finally:
self.starting = None
if not success:
self.process = None
async def _startProcess(self):
assert self.process is None
self.process = BotProcessProtocol(self)
self.token = uuid.uuid4().hex.encode('ascii')
self.waitForAMPConnection = defer.Deferred()
ampFactory = Factory.forProtocol(ArenaSideAMPProtocol)
ampFactory.manager = self
ampEndpoint = TCP4ServerEndpoint(reactor, 0)
listeningPort = await ampEndpoint.listen(ampFactory)
try:
ampPort = listeningPort.getHost().port
cmd = self.getCommand() + [str(ampPort)]