diff --git a/README.md b/README.md index 4972ccfd1..a127ea679 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,53 @@ +## Craft fork + +Running on python3, using Amazon Aurora PG instead of sqlite, deployed on Agones/NLB and using craft.auth.yahav.sa.aws.dev/auth/identity/ for auth players. + +See all users: +```bash +curl http://craft.auth.yahav.sa.aws.dev/auth/allusers/ +``` + +Create a user: +```bash +curl http://craft.auth.yahav.sa.aws.dev/auth/adduser/?username=yahavb +``` + +Generate token: +```bash +curl http://craft.auth.yahav.sa.aws.dev/auth/getoken/?username=yahavb +``` +Use the token and username to validate your token `/identity username token` in the craf game client. + +### Database setup +This fork uses postgresql instead of sqlite so some of the sql were adopted to postgresql. +To spin an aurora postgresql use https://github.com/aws-samples/amazon-aurora-call-to-amazon-sagemaker-sample/tree/master/multiplayer-matchmaker/aurora-pg-cdk + +### Making changes +branch=mybranch && git checkout -b $branch && git add server.py&&git commit -m $branch && git push --set-upstream origin $branch +To build a new image manually, use https://github.com/aws-samples/containerized-game-servers/blob/master/craft/ci/craft-server/serverfiles/build.sh. +In `aws-samples/containerized-game-servers/blob/master/craft/ci/craft-server/serverfiles` +```bash +export GITHUB_CRAFT_BRANCH=mybranch && ./build.sh +``` +### Agones + +Install agones +```bash +helm upgrade agones agones/agones --namespace agones-system --install --wait --create-namespace \ + --set agones.featureGates=PlayerTracking=true +``` + +Enable player tracking +```bash +helm upgrade agones agones/agones --namespace agones-system --set agones.featureGates=PlayerTracking=true +``` + +Add `IS_AGONES` env parameter +```bash +IS_AGONES=True +``` + +Use TBD link to https://github.com/aws-samples/containerized-game-servers/tree/master/craft ## Craft Minecraft clone for Windows, Mac OS X and Linux. Just a few thousand lines of C using modern OpenGL (shaders). Online multiplayer support is included using a Python-based server. diff --git a/builder.py b/builder.py index 990ed750b..29b73f635 100644 --- a/builder.py +++ b/builder.py @@ -5,9 +5,13 @@ import socket import sqlite3 import sys +import os +import time +import boto3 -DEFAULT_HOST = '127.0.0.1' -DEFAULT_PORT = 4080 +QUEUE_URL = os.environ['SQS_CHECKPOINT_QUEUE_URL'] +DEFAULT_HOST = os.environ['CRAFT_HOST'] +DEFAULT_PORT = os.environ['CRAFT_PORT'] EMPTY = 0 GRASS = 1 @@ -45,6 +49,43 @@ (0.5, 0.5, 0.5), ] +sqs=boto3.client('sqs') + +def store_checkpoint(checkpoint): + response=sqs.send_message( + QueueUrl=QUEUE_URL, + DelaySeconds=10, + MessageBody=(checkpoint) + ) + print(response['MessageId']) + sys.stdout.flush() + +def pull_checkpoint(): + response=sqs.receive_message( + QueueUrl=QUEUE_URL, + MaxNumberOfMessages=1, + VisibilityTimeout=0, + WaitTimeSeconds=0 + ) + print('in pull_checkpoint:response:%s'%response) + if 'Messages' in response.keys(): + message=response['Messages'][0] + receipt_handle=message['ReceiptHandle'] + last_checkpoint=message['Body'] + print('in pull_checkpoint:last_checkpoint %s' % last_checkpoint) + sys.stdout.flush() + + sqs.delete_message( + QueueUrl=QUEUE_URL, + ReceiptHandle=receipt_handle + ) + print('in pull_checkpoint:Received and deleted message:%s'%message) + sys.stdout.flush() + else: + print('in pull_checkpoint: no previous checkpoints in queue') + last_checkpoint="1" + return last_checkpoint + def sphere(cx, cy, cz, r, fill=False, fx=False, fy=False, fz=False): result = set() for x in range(cx - r, cx + r + 1): @@ -143,7 +184,7 @@ class Client(object): def __init__(self, host, port): self.conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.conn.connect((host, port)) - self.authenticate() + #self.authenticate() def authenticate(self): username, identity_token = get_identity() url = 'https://craft.michaelfogleman.com/api/1/identity' @@ -154,11 +195,27 @@ def authenticate(self): response = requests.post(url, data=payload) if response.status_code == 200 and response.text.isalnum(): access_token = response.text - self.conn.sendall('A,%s,%s\n' % (username, access_token)) + buf=b'' + string='A,%s,%s\n' % (username, access_token) + buf=bytes(string,'utf-8') + self.conn.sendall(buf) + print(buf) + sys.stdout.flush() else: raise Exception('Failed to authenticate.') def set_block(self, x, y, z, w): - self.conn.sendall('B,%d,%d,%d,%d\n' % (x, y, z, w)) + buf=b'' + string='B,%d,%d,%d,%d\n' % (x, y, z, w) + buf=bytes(string,'utf-8') + try: + r=self.conn.sendall(buf) + print('buf={},r={}'.format(buf,r)) + sys.stdout.flush() + time.sleep(1) + except Exception as error: + print('in set_block:error:',error) + sys.stdout.flush() + #self.conn.sendall('B,%d,%d,%d,%d\n' % (x, y, z, w)) def set_blocks(self, blocks, w): key = lambda block: (block[1], block[0], block[2]) for x, y, z in sorted(blocks, key=key): @@ -186,63 +243,83 @@ def get_client(): return client def main(): - client = get_client() - set_block = client.set_block - set_blocks = client.set_blocks - # set_blocks(circle_y(0, 32, 0, 16, True), STONE) - # set_blocks(circle_y(0, 33, 0, 16), BRICK) - # set_blocks(cuboid(-1, 1, 1, 31, -1, 1), CEMENT) - # set_blocks(cuboid(-1024, 1024, 32, 32, -3, 3), STONE) - # set_blocks(cuboid(-3, 3, 32, 32, -1024, 1024), STONE) - # set_blocks(cuboid(-1024, 1024, 33, 33, -3, -3), BRICK) - # set_blocks(cuboid(-1024, 1024, 33, 33, 3, 3), BRICK) - # set_blocks(cuboid(-3, -3, 33, 33, -1024, 1024), BRICK) - # set_blocks(cuboid(3, 3, 33, 33, -1024, 1024), BRICK) - # set_blocks(sphere(0, 32, 0, 16), GLASS) - # for y in range(1, 32): - # set_blocks(circle_y(0, y, 0, 4, True), CEMENT) - # set_blocks(circle_x(16, 33, 0, 3), BRICK) - # set_blocks(circle_x(-16, 33, 0, 3), BRICK) - # set_blocks(circle_z(0, 33, 16, 3), BRICK) - # set_blocks(circle_z(0, 33, -16, 3), BRICK) - # for x in range(0, 1024, 32): - # set_blocks(cuboid(x - 1, x + 1, 31, 32, -1, 1), CEMENT) - # set_blocks(cuboid(-x - 1, -x + 1, 31, 32, -1, 1), CEMENT) - # set_blocks(cuboid(x, x, 1, 32, -1, 1), CEMENT) - # set_blocks(cuboid(-x, -x, 1, 32, -1, 1), CEMENT) - # for z in range(0, 1024, 32): - # set_blocks(cuboid(-1, 1, 31, 32, z - 1, z + 1), CEMENT) - # set_blocks(cuboid(-1, 1, 31, 32, -z - 1, -z + 1), CEMENT) - # set_blocks(cuboid(-1, 1, 1, 32, z, z), CEMENT) - # set_blocks(cuboid(-1, 1, 1, 32, -z, -z), CEMENT) - # for x in range(0, 1024, 8): - # set_block(x, 32, 0, CEMENT) - # set_block(-x, 32, 0, CEMENT) - # for z in range(0, 1024, 8): - # set_block(0, 32, z, CEMENT) - # set_block(0, 32, -z, CEMENT) - # set_blocks(pyramid(32, 32+64-1, 12, 32, 32+64-1), COBBLE) - # outer = circle_y(0, 11, 0, 176 + 3, True) - # inner = circle_y(0, 11, 0, 176 - 3, True) - # set_blocks(outer - inner, STONE) - # a = sphere(-32, 48, -32, 24, True) - # b = sphere(-24, 40, -24, 24, True) - # set_blocks(a - b, PLANK) - # set_blocks(cylinder_x(-64, 64, 32, 0, 8), STONE) - # data = [ - # '...............................', - # '..xxx..xxxx...xxx..xxxxx.xxxxx.', - # '.x...x.x...x.x...x.x.......x...', - # '.x.....xxxx..xxxxx.xxx.....x...', - # '.x...x.x..x..x...x.x.......x...', - # '..xxx..x...x.x...x.x.......x...', - # '...............................', - # ] - # lookup = { - # 'x': STONE, - # '.': PLANK, - # } - # client.bitmap(0, 32, 32, (1, 0, 0), (0, -1, 0), data, lookup) + client = get_client() + set_block = client.set_block + set_blocks = client.set_blocks + #store_checkpoint('1') + last_checkpoint=pull_checkpoint() + print('in main:lastcheckpoint ',last_checkpoint) + match last_checkpoint: + case '1': + set_blocks(circle_y(0, 32, 0, 16, True), STONE) + set_blocks(circle_y(0, 33, 0, 16), BRICK) + set_blocks(cuboid(-1, 1, 1, 31, -1, 1), CEMENT) + set_blocks(cuboid(-1024, 1024, 32, 32, -3, 3), STONE) + set_blocks(cuboid(-3, 3, 32, 32, -1024, 1024), STONE) + set_blocks(cuboid(-1024, 1024, 33, 33, -3, -3), BRICK) + set_blocks(cuboid(-1024, 1024, 33, 33, 3, 3), BRICK) + set_blocks(cuboid(-3, -3, 33, 33, -1024, 1024), BRICK) + set_blocks(cuboid(3, 3, 33, 33, -1024, 1024), BRICK) + set_blocks(sphere(0, 32, 0, 16), GLASS) + store_checkpoint('1') + case '2': + for y in range(1, 32): + set_blocks(circle_y(0, y, 0, 4, True), CEMENT) + set_blocks(circle_x(16, 33, 0, 3), BRICK) + set_blocks(circle_x(-16, 33, 0, 3), BRICK) + set_blocks(circle_z(0, 33, 16, 3), BRICK) + set_blocks(circle_z(0, 33, -16, 3), BRICK) + store_checkpoint('2') + case '3': + for x in range(0, 1024, 32): + set_blocks(cuboid(x - 1, x + 1, 31, 32, -1, 1), CEMENT) + set_blocks(cuboid(-x - 1, -x + 1, 31, 32, -1, 1), CEMENT) + set_blocks(cuboid(x, x, 1, 32, -1, 1), CEMENT) + set_blocks(cuboid(-x, -x, 1, 32, -1, 1), CEMENT) + store_checkpoint('3') + case '4': + for z in range(0, 1024, 32): + set_blocks(cuboid(-1, 1, 31, 32, z - 1, z + 1), CEMENT) + set_blocks(cuboid(-1, 1, 31, 32, -z - 1, -z + 1), CEMENT) + set_blocks(cuboid(-1, 1, 1, 32, z, z), CEMENT) + set_blocks(cuboid(-1, 1, 1, 32, -z, -z), CEMENT) + store_checkpoint('4') + case '5': + for x in range(0, 1024, 8): + set_block(x, 32, 0, CEMENT) + set_block(-x, 32, 0, CEMENT) + store_checkpoint('5') + case '6': + for z in range(0, 1024, 8): + set_block(0, 32, z, CEMENT) + set_block(0, 32, -z, CEMENT) + store_checkpoint('6') + case '7': + set_blocks(pyramid(32, 32+64-1, 12, 32, 32+64-1), COBBLE) + outer = circle_y(0, 11, 0, 176 + 3, True) + inner = circle_y(0, 11, 0, 176 - 3, True) + set_blocks(outer - inner, STONE) + a = sphere(-32, 48, -32, 24, True) + b = sphere(-24, 40, -24, 24, True) + set_blocks(a - b, PLANK) + set_blocks(cylinder_x(-64, 64, 32, 0, 8), STONE) + store_checkpoint('7') + case '8': + data = [ + '...............................', + '..xxx..xxxx...xxx..xxxxx.xxxxx.', + '.x...x.x...x.x...x.x.......x...', + '.x.....xxxx..xxxxx.xxx.....x...', + '.x...x.x..x..x...x.x.......x...', + '..xxx..x...x.x...x.x.......x...', + '...............................', + ] + lookup = { + 'x': STONE, + '.': PLANK, + } + client.bitmap(0, 32, 32, (1, 0, 0), (0, -1, 0), data, lookup) + store_checkpoint('8') if __name__ == '__main__': main() diff --git a/craft.sh b/craft.sh new file mode 100755 index 000000000..b514ee6b9 --- /dev/null +++ b/craft.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +while true +do + ./craft craft.yahav.sa.aws.dev 4080 + sleep 2 +done diff --git a/create_db_schema.sql b/create_db_schema.sql new file mode 100644 index 000000000..6edca8610 --- /dev/null +++ b/create_db_schema.sql @@ -0,0 +1,69 @@ +create SEQUENCE block_rowid start 1; +create SEQUENCE light_rowid start 1; +create SEQUENCE sign_rowid start 1; +create SEQUENCE block_history_rowid start 1; + +create table block ( + rowid bigint default nextval('public.block_rowid'::regclass) primary key, + updated_at timestamp, + user_id varchar(64) not null, + p int not null, + q int not null, + x int not null, + y int not null, + z int not null, + w int not null +); +alter table block add constraint unique_block_pqxyz unique (p,q,x,y,z); + +create table if not exists light ( + rowid bigint default nextval('public.light_rowid'::regclass) primary key, + p int not null, + q int not null, + x int not null, + y int not null, + z int not null, + w int not null +); +create unique index if not exists light_pqxyz_idx on light (p, q, x, y, z); + +create table if not exists sign ( + rowid bigint default nextval('public.sign_rowid'::regclass) primary key, + p int not null, + q int not null, + x int not null, + y int not null, + z int not null, + face int not null, + text text not null +); +create index if not exists sign_pq_idx on sign (p, q); + +create unique index if not exists sign_xyzface_idx on sign (x, y, z, face); + +create table if not exists block_history ( + rowid bigint default nextval('public.block_history_rowid'::regclass), + created_at timestamp, + user_id varchar(64) not null, + p int not null, + q int not null, + x int not null, + y int not null, + z int not null, + w int not null, + primary key (rowid,created_at) +) partition by range (created_at); + +CREATE SCHEMA partman; +CREATE EXTENSION pg_partman WITH SCHEMA partman; + +SELECT partman.create_parent( p_parent_table => 'public.block_history', + p_control => 'created_at', + p_type => 'native', + p_interval=> 'monthly', + p_premake => 24); + +create table user_recent_pos(updated_at timestamp,user_id varchar(64) not null,x int not null,y int not null,z int not null); + +alter table user_recent_pos add constraint unique_username unique (user_id); +alter table auth_app_user add constraint unique_authappusername unique (username); diff --git a/deps/glfw/src/glfw3Config.cmake b/deps/glfw/src/glfw3Config.cmake new file mode 100644 index 000000000..f41a722a2 --- /dev/null +++ b/deps/glfw/src/glfw3Config.cmake @@ -0,0 +1,29 @@ +# - Config file for the glfw3 package +# It defines the following variables +# GLFW3_INCLUDE_DIR, the path where GLFW headers are located +# GLFW3_LIBRARY_DIR, folder in which the GLFW library is located +# GLFW3_LIBRARY, library to link against to use GLFW + +set(GLFW3_VERSION "3.1.2") + + +####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() ####### +####### Any changes to this file will be overwritten by the next CMake run #### +####### The input file was glfw3Config.cmake.in ######## + +get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE) + +macro(set_and_check _var _file) + set(${_var} "${_file}") + if(NOT EXISTS "${_file}") + message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !") + endif() +endmacro() + +#################################################################################### + +set_and_check(GLFW3_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include") +set_and_check(GLFW3_LIBRARY_DIR "${PACKAGE_PREFIX_DIR}/lib") + +find_library(GLFW3_LIBRARY "glfw3" HINTS ${GLFW3_LIBRARY_DIR}) + diff --git a/deps/glfw/src/glfw3ConfigVersion.cmake b/deps/glfw/src/glfw3ConfigVersion.cmake new file mode 100644 index 000000000..d73cffc15 --- /dev/null +++ b/deps/glfw/src/glfw3ConfigVersion.cmake @@ -0,0 +1,70 @@ +# This is a basic version file for the Config-mode of find_package(). +# It is used by write_basic_package_version_file() as input file for configure_file() +# to create a version-file which can be installed along a config.cmake file. +# +# The created file sets PACKAGE_VERSION_EXACT if the current version string and +# the requested version string are exactly the same and it sets +# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version, +# but only if the requested major version is the same as the current one. +# The variable CVF_VERSION must be set before calling configure_file(). + + +set(PACKAGE_VERSION "3.1.2") + +if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + + if("3.1.2" MATCHES "^([0-9]+)\\.") + set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}") + if(NOT CVF_VERSION_MAJOR VERSION_EQUAL 0) + string(REGEX REPLACE "^0+" "" CVF_VERSION_MAJOR "${CVF_VERSION_MAJOR}") + endif() + else() + set(CVF_VERSION_MAJOR "3.1.2") + endif() + + if(PACKAGE_FIND_VERSION_RANGE) + # both endpoints of the range must have the expected major version + math (EXPR CVF_VERSION_MAJOR_NEXT "${CVF_VERSION_MAJOR} + 1") + if (NOT PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR + OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX_MAJOR STREQUAL CVF_VERSION_MAJOR) + OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX VERSION_LESS_EQUAL CVF_VERSION_MAJOR_NEXT))) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + elseif(PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR + AND ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS_EQUAL PACKAGE_FIND_VERSION_MAX) + OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MAX))) + set(PACKAGE_VERSION_COMPATIBLE TRUE) + else() + set(PACKAGE_VERSION_COMPATIBLE FALSE) + endif() + else() + if(PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR) + set(PACKAGE_VERSION_COMPATIBLE TRUE) + else() + set(PACKAGE_VERSION_COMPATIBLE FALSE) + endif() + + if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION) + set(PACKAGE_VERSION_EXACT TRUE) + endif() + endif() +endif() + + +# if the installed project requested no architecture check, don't perform the check +if("FALSE") + return() +endif() + +# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it: +if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "") + return() +endif() + +# check that the installed version has the same 32/64bit-ness as the one which is currently searching: +if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8") + math(EXPR installedBits "8 * 8") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) +endif() diff --git a/deps/glfw/src/glfw_config.h b/deps/glfw/src/glfw_config.h new file mode 100644 index 000000000..fc58e1781 --- /dev/null +++ b/deps/glfw/src/glfw_config.h @@ -0,0 +1,81 @@ +//======================================================================== +// GLFW 3.1 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// As glfw_config.h.in, this file is used by CMake to produce the +// glfw_config.h configuration header file. If you are adding a feature +// requiring conditional compilation, this is where to add the macro. +//======================================================================== +// As glfw_config.h, this file defines compile-time option macros for a +// specific platform and development environment. If you are using the +// GLFW CMake files, modify glfw_config.h.in instead of this file. If you +// are using your own build system, make this file define the appropriate +// macros in whatever way is suitable. +//======================================================================== + +// Define this to 1 if building GLFW for X11 +/* #undef _GLFW_X11 */ +// Define this to 1 if building GLFW for Win32 +/* #undef _GLFW_WIN32 */ +// Define this to 1 if building GLFW for Cocoa +#define _GLFW_COCOA +// Define this to 1 if building GLFW for Wayland +/* #undef _GLFW_WAYLAND */ +// Define this to 1 if building GLFW for Mir +/* #undef _GLFW_MIR */ + +// Define this to 1 if building GLFW for EGL +/* #undef _GLFW_EGL */ +// Define this to 1 if building GLFW for GLX +/* #undef _GLFW_GLX */ +// Define this to 1 if building GLFW for WGL +/* #undef _GLFW_WGL */ +// Define this to 1 if building GLFW for NSGL +#define _GLFW_NSGL + +// Define this to 1 if building as a shared library / dynamic library / DLL +/* #undef _GLFW_BUILD_DLL */ + +// Define this to 1 to force use of high-performance GPU on hybrid systems +/* #undef _GLFW_USE_HYBRID_HPG */ + +// Define this to 1 if the XInput X11 extension is available +/* #undef _GLFW_HAS_XINPUT */ +// Define this to 1 if the Xxf86vm X11 extension is available +/* #undef _GLFW_HAS_XF86VM */ + +// Define this to 1 if glfwInit should change the current directory +#define _GLFW_USE_CHDIR +// Define this to 1 if glfwCreateWindow should populate the menu bar +#define _GLFW_USE_MENUBAR +// Define this to 1 if windows should use full resolution on Retina displays +#define _GLFW_USE_RETINA + +// Define this to 1 if using OpenGL as the client library +#define _GLFW_USE_OPENGL +// Define this to 1 if using OpenGL ES 1.1 as the client library +/* #undef _GLFW_USE_GLESV1 */ +// Define this to 1 if using OpenGL ES 2.0 as the client library +/* #undef _GLFW_USE_GLESV2 */ + diff --git a/deps/glfw/tests/cursor b/deps/glfw/tests/cursor new file mode 100755 index 000000000..33d350b67 Binary files /dev/null and b/deps/glfw/tests/cursor differ diff --git a/deps/glfw/tests/monitors b/deps/glfw/tests/monitors new file mode 100755 index 000000000..57edde4fe Binary files /dev/null and b/deps/glfw/tests/monitors differ diff --git a/deps/glfw/tests/msaa b/deps/glfw/tests/msaa new file mode 100755 index 000000000..9d55110c3 Binary files /dev/null and b/deps/glfw/tests/msaa differ diff --git a/server.py b/server.py index df8e596d9..afe0d330b 100644 --- a/server.py +++ b/server.py @@ -1,19 +1,40 @@ from math import floor from world import World -import Queue -import SocketServer +import queue +import socketserver import datetime import random import re import requests -import sqlite3 +from requests.adapters import HTTPAdapter +from requests.packages.urllib3.util.retry import Retry import sys import threading import time import traceback +import os +import psycopg2 +import signal +import datetime +from datetime import datetime, timezone +from datetime import datetime as dt + +cmd = 'rm -rf /tmp/healthy' +user=os.environ['PGUSER'] +password=os.environ['PGPASSWORD'] +host=os.environ['PGHOST'] +database=os.environ['PGDATABASE'] +dbport=os.environ['PGPORT'] +pod_name=os.environ['MY_POD_NAME'] +node_name=os.environ['MY_NODE_NAME'] DEFAULT_HOST = '0.0.0.0' -DEFAULT_PORT = 4080 +DEFAULT_PORT = int(os.environ['SERVERPORT']) +IS_AGONES=os.environ['IS_AGONES'] + +if IS_AGONES == 'True': + AGONES_SDK_HTTP_PORT=os.environ['AGONES_SDK_HTTP_PORT'] + AGONES_HEALTH_THREAD=0 DB_PATH = 'craft.db' LOG_PATH = 'log.txt' @@ -22,13 +43,16 @@ BUFFER_SIZE = 4096 COMMIT_INTERVAL = 5 -AUTH_REQUIRED = True -AUTH_URL = 'https://craft.michaelfogleman.com/api/1/access' +AUTH_REQUIRED = os.environ['USE_AUTH'] +AUTH_URL = os.environ['AUTH_SRV'] DAY_LENGTH = 600 -SPAWN_POINT = (0, 0, 0, 0, 0) +SPAWN_X=int(os.environ['SPAWN_X']) +SPAWN_Y=int(os.environ['SPAWN_Y']) +SPAWN_Z=int(os.environ['SPAWN_Z']) +SPAWN_POINT = (SPAWN_X, SPAWN_Y, SPAWN_Z, 0, 0) RATE_LIMIT = False -RECORD_HISTORY = False +RECORD_HISTORY =os.environ['RECORD_HISTORY'] INDESTRUCTIBLE_ITEMS = set([16]) ALLOWED_ITEMS = set([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, @@ -50,6 +74,7 @@ TIME = 'E' VERSION = 'V' YOU = 'U' +GETSERVERS = 'G' try: from config import * @@ -57,17 +82,75 @@ pass def log(*args): - now = datetime.datetime.utcnow() + now = dt.now() line = ' '.join(map(str, (now,) + args)) - print line + print(line) with open(LOG_PATH, 'a') as fp: fp.write('%s\n' % line) + sys.stdout.flush() + +def sig_handler(signum,frame): + global AGONES_HEALTH_THREAD + AGONES_HEALTH_THREAD=0 + log('in sig_handler:Signal hanlder called with signal',signum) + log('in sig_handler:execute ',cmd) + os.system(cmd) + model.is_going_down=1 + model.send_talk("Game server maintenance is pending - pls reconnect") + model.send_talk("Don't worry, your universe is saved with us") + model.send_talk('Removing the server from load balancer %s'%(cmd)) + headers={'Content-Type':'application/json'} + try: + url='http://localhost:'+AGONES_SDK_HTTP_PORT+'/shutdown' + r=requests.post(url,headers=headers,json={},timeout=100) + log('in sig_handler:shutdown:url:',url, ' response.status_code:',r.status_code,' response.headers:',r.headers) + except Exception as error: + log('in sig_handler:error',error) + +def pg_read(sql,param): + try: + connection = psycopg2.connect(user=user, + password=password, + host=host, + port=dbport, + database=database) + cursor = connection.cursor() + cursor.execute(sql,param) + rows = cursor.fetchall() + #log('in pg_read:','sql=',sql,'param=',param,'rows=',rows) + return rows + except (Exception, psycopg2.Error) as error: + log('Failed to select:',error,' sql:',sql,' param:',param) + finally: + if connection: + cursor.close() + connection.close() + +def pg_write(sql,param): + try: + connection = psycopg2.connect(user=user, + password=password, + host=host, + port=dbport, + database=database) + cursor = connection.cursor() + cursor.execute(sql,param) + connection.commit() + count = cursor.rowcount + #log('in pg_write:','sql=',sql,'param=',param,'count=',count) + except (Exception, psycopg2.Error) as error: + log('Failed to insert/update:',error,' sql:',sql,' param:',param) + traceback.print_exc() + finally: + if connection: + cursor.close() + connection.close() def chunked(x): return int(floor(round(x) / CHUNK_SIZE)) def packet(*args): - return '%s\n' % ','.join(map(str, args)) + return ('%s\n' % ','.join(map(str, args))).encode("UTF-8") class RateLimiter(object): def __init__(self, rate, per): @@ -90,79 +173,108 @@ def tick(self): self.allowance -= 1 return False # okay -class Server(SocketServer.ThreadingMixIn, SocketServer.TCPServer): +class Server(socketserver.ThreadingMixIn, socketserver.TCPServer): allow_reuse_address = True daemon_threads = True -class Handler(SocketServer.BaseRequestHandler): +class Handler(socketserver.BaseRequestHandler): def setup(self): + global AGONES_HEALTH_THREAD self.position_limiter = RateLimiter(100, 5) self.limiter = RateLimiter(1000, 10) self.version = None self.client_id = None self.user_id = None self.nick = None - self.queue = Queue.Queue() + self.queue = queue.Queue() self.running = True self.start() + if IS_AGONES == 'True': + AGONES_HEALTH_THREAD=1 + self.start_agones_health() def handle(self): model = self.server.model model.enqueue(model.on_connect, self) try: - buf = [] + buf = b'' while True: data = self.request.recv(BUFFER_SIZE) if not data: break - buf.extend(data.replace('\r\n', '\n')) - while '\n' in buf: - index = buf.index('\n') - line = ''.join(buf[:index]) + buf += data.replace(b'\r\n', b'\n') + while b'\n' in buf: + index = buf.index(b'\n') + line = buf[:index] buf = buf[index + 1:] - if not line: - continue - if line[0] == POSITION: + command = line.decode("utf-8") + if command[0] == POSITION: if self.position_limiter.tick(): - log('RATE', self.client_id) self.stop() return else: if self.limiter.tick(): - log('RATE', self.client_id) self.stop() return - model.enqueue(model.on_data, self, line) + model.enqueue(model.on_data, self, command) finally: model.enqueue(model.on_disconnect, self) + def agones_shutdown(self): + try: + headers={'Content-Type':'application/json'} + url='http://localhost:'+AGONES_SDK_HTTP_PORT+'/shutdown' + r=requests.post(url,headers=headers,json={}) + log('in Handler:run:response-agones:url:',url, ' response.status_code:',r.status_code,' response.headers:',r.headers) + except Exception as error: + log('agones_shutdown:',error) def finish(self): + #if IS_AGONES == 'True': + # self.agones_shutdown() self.running = False def stop(self): self.request.close() def start(self): thread = threading.Thread(target=self.run) - thread.setDaemon(True) + thread.setDaemon=True + thread.start() + def start_agones_health(self): + thread = threading.Thread(target=self.agones_health) + #thread.setDaemon=True thread.start() + def agones_health(self): + global AGONES_HEALTH_THREAD + log('in agones_health:self.running',self.running,' :AGONES_HEALTH_THREAD:',AGONES_HEALTH_THREAD) + if AGONES_HEALTH_THREAD == 1: + try: + headers={'Content-Type':'application/json'} + url='http://localhost:'+AGONES_SDK_HTTP_PORT+'/health' + r=requests.post(url,headers=headers,json={}) + log('in Handler:agones_health:url:',url, ' response.status_code:',r.status_code,' response.headers:',r.headers) + except Exception as error: + log('agones_health:error',error) + def run(self): while self.running: try: - buf = [] + buf = b'' try: - buf.append(self.queue.get(timeout=5)) + buf += self.queue.get(timeout=5) try: while True: - buf.append(self.queue.get(False)) - except Queue.Empty: + buf += self.queue.get_nowait() + except queue.Empty: pass - except Queue.Empty: + #log('in Handler:run:buf:',buf) + except queue.Empty: continue - data = ''.join(buf) - self.request.sendall(data) - except Exception: + self.request.sendall(buf) + except Exception as error: self.request.close() - raise + #raise + def send_raw(self, data): if data: self.queue.put(data) + def send(self, *args): self.send_raw(packet(*args)) @@ -170,7 +282,8 @@ class Model(object): def __init__(self, seed): self.world = World(seed) self.clients = [] - self.queue = Queue.Queue() + self.is_going_down=0 + self.queue = queue.Queue() self.commands = { AUTHENTICATE: self.on_authenticate, CHUNK: self.on_chunk, @@ -180,6 +293,7 @@ def __init__(self, seed): TALK: self.on_talk, SIGN: self.on_sign, VERSION: self.on_version, + GETSERVERS: self.on_get_servers, } self.patterns = [ (re.compile(r'^/nick(?:\s+([^,\s]+))?$'), self.on_nick), @@ -191,123 +305,91 @@ def __init__(self, seed): ] def start(self): thread = threading.Thread(target=self.run) - thread.setDaemon(True) + thread.daemon= True thread.start() def run(self): - self.connection = sqlite3.connect(DB_PATH) - self.create_tables() - self.commit() while True: try: - if time.time() - self.last_commit > COMMIT_INTERVAL: - self.commit() self.dequeue() except Exception: traceback.print_exc() + def enqueue(self, func, *args, **kwargs): - self.queue.put((func, args, kwargs)) + try: + self.queue.put((func, args, kwargs)) + except Exception as error: + log('in enqueue:Exception:',error) + traceback.print_exc() + def dequeue(self): try: func, args, kwargs = self.queue.get(timeout=5) func(*args, **kwargs) - except Queue.Empty: + except queue.Empty: pass - def execute(self, *args, **kwargs): - return self.connection.execute(*args, **kwargs) - def commit(self): - self.last_commit = time.time() - self.connection.commit() - def create_tables(self): - queries = [ - 'create table if not exists block (' - ' p int not null,' - ' q int not null,' - ' x int not null,' - ' y int not null,' - ' z int not null,' - ' w int not null' - ');', - 'create unique index if not exists block_pqxyz_idx on ' - ' block (p, q, x, y, z);', - 'create table if not exists light (' - ' p int not null,' - ' q int not null,' - ' x int not null,' - ' y int not null,' - ' z int not null,' - ' w int not null' - ');', - 'create unique index if not exists light_pqxyz_idx on ' - ' light (p, q, x, y, z);', - 'create table if not exists sign (' - ' p int not null,' - ' q int not null,' - ' x int not null,' - ' y int not null,' - ' z int not null,' - ' face int not null,' - ' text text not null' - ');', - 'create index if not exists sign_pq_idx on sign (p, q);', - 'create unique index if not exists sign_xyzface_idx on ' - ' sign (x, y, z, face);', - 'create table if not exists block_history (' - ' timestamp real not null,' - ' user_id int not null,' - ' x int not null,' - ' y int not null,' - ' z int not null,' - ' w int not null' - ');', - ] - for query in queries: - self.execute(query) + def get_default_block(self, x, y, z): p, q = chunked(x), chunked(z) chunk = self.world.get_chunk(p, q) return chunk.get((x, y, z), 0) + def get_block(self, x, y, z): - query = ( - 'select w from block where ' - 'p = :p and q = :q and x = :x and y = :y and z = :z;' - ) p, q = chunked(x), chunked(z) - rows = list(self.execute(query, dict(p=p, q=q, x=x, y=y, z=z))) + sql = """select w from block where p = %s and q = %s and x = %s and y = %s and z = %s;""" + params = [p,q,x,y,z] + rows = list(pg_read(sql,params)) if rows: return rows[0][0] return self.get_default_block(x, y, z) + def next_client_id(self): result = 1 client_ids = set(x.client_id for x in self.clients) while result in client_ids: result += 1 return result + + def agones_player(self,client_nick,action): + try: + headers={'Content-Type':'application/json'} + url='http://localhost:'+AGONES_SDK_HTTP_PORT+'/alpha/player/'+action + payload={"playerID":client_nick} + r=requests.post(url,headers=headers,json={}) + log('in Model:run:response-agones:url:',url, ' response.status_code:',r.status_code,' response.headers:',r.headers,' payload:',payload) + except Exception as error: + log('agones_player_',action,':error',error) + def on_connect(self, client): client.client_id = self.next_client_id() client.nick = 'guest%d' % client.client_id - log('CONN', client.client_id, *client.client_address) - client.position = SPAWN_POINT + log('on_connect:', client.client_id, *client.client_address) self.clients.append(client) - client.send(YOU, client.client_id, *client.position) client.send(TIME, time.time(), DAY_LENGTH) client.send(TALK, 'Welcome to Craft!') client.send(TALK, 'Type "/help" for a list of commands.') - self.send_position(client) - self.send_positions(client) self.send_nick(client) self.send_nicks(client) + def on_data(self, client, data): - #log('RECV', client.client_id, data) args = data.split(',') command, args = args[0], args[1:] if command in self.commands: func = self.commands[command] func(client, *args) + def on_disconnect(self, client): - log('DISC', client.client_id, *client.client_address) + log('on_disconnect:',self.next_client_id()) + if IS_AGONES == 'True': + if 'guest' not in client.nick: + self.agones_player(client.nick,'disconnect') + else: + log('on_disconnect:skipping:',client.nick) self.clients.remove(client) self.send_disconnect(client) - self.send_talk('%s has disconnected from the server.' % client.nick) + + def on_get_servers(self,client): + client.send(TALK, 'Availible servers for you:') + def on_version(self, client, version): if client.version is not None: return @@ -317,70 +399,99 @@ def on_version(self, client, version): return client.version = version # TODO: client.start() here + def on_authenticate(self, client, username, access_token): + global SPAWN_POINT + log('on_authenticate:',' client:',client,' username:',username,' access_token:',access_token) user_id = None if username and access_token: payload = { 'username': username, 'access_token': access_token, } - response = requests.post(AUTH_URL, data=payload) - if response.status_code == 200 and response.text.isdigit(): - user_id = int(response.text) - client.user_id = user_id + log('on_authenticate:payload',payload) + response = requests.post(AUTH_URL, json=payload) + log('on_authenticate:response.status_code',response.status_code) + #if response.status_code == 200 and response.text.isdigit(): + if response.status_code == 200: + user_id = username if user_id is None: - client.nick = 'guest%d' % client.client_id - client.send(TALK, 'Visit craft.michaelfogleman.com to register!') + client.nick = 'guest%d' % client.client_id + client.user_id='guest%d' % client.client_id + client.send(TALK, 'Visit http://craft.auth.yahav.sa.aws.dev/auth/adduser/?username=myuser to register!') else: - client.nick = username - self.send_nick(client) - # TODO: has left message if was already authenticated + client.nick = username + client.user_id = user_id + self.send_nick(client) + #log('on_authenticate:client.nick:',client.nick) + log('on_authenticate:1:SPAWN_POINT:',SPAWN_POINT) + sql="""select x,y,z from user_recent_pos where user_id=%s""" + params=[client.nick] + rows=list(pg_read(sql,params)) + if rows: + log('on_authenticate:client.nick:',client.nick,' last_pos:',rows,' rows[0][0]=',rows[0][0]) + x=rows[0][0] + y=rows[0][1] + z=rows[0][2] + SPAWN_POINT=(x,y,z,0,0) + log('on_authenticate:x,y,z:',x,y,z) + log('on_authenticate:2:SPAWN_POINT:',SPAWN_POINT) + client.position = SPAWN_POINT + self.send_position(client) + self.send_positions(client) + client.send(YOU, client.client_id, *client.position) + client.send(TALK, 'Current pod is '+pod_name) + client.send(TALK, 'Current node is '+node_name) self.send_talk('%s has joined the game.' % client.nick) + if IS_AGONES == 'True': + self.agones_player(client.nick,'connect') + headers={'Content-Type':'application/json'} + url='http://localhost:'+AGONES_SDK_HTTP_PORT+'/allocate' + r=requests.post(url,headers=headers,json={}) + log('in Model:on_authenticate:url:',url, ' response.status_code:',r.status_code,' response.headers:',r.headers,' payload:',payload) + def on_chunk(self, client, p, q, key=0): - packets = [] + packets = b'' p, q, key = map(int, (p, q, key)) - query = ( - 'select rowid, x, y, z, w from block where ' - 'p = :p and q = :q and rowid > :key;' - ) - rows = self.execute(query, dict(p=p, q=q, key=key)) + query="""select rowid, x, y, z, w from block where p = %s and q = %s and rowid > %s;""" + params=[p,q,key] + rows=pg_read(query,params) max_rowid = 0 blocks = 0 - for rowid, x, y, z, w in rows: + if rows is not None: + for rowid, x, y, z, w in rows: blocks += 1 - packets.append(packet(BLOCK, p, q, x, y, z, w)) + packets += packet(BLOCK, p, q, x, y, z, w) max_rowid = max(max_rowid, rowid) - query = ( - 'select x, y, z, w from light where ' - 'p = :p and q = :q;' - ) - rows = self.execute(query, dict(p=p, q=q)) + query="""select x, y, z, w from light where p=%s and q=%s;""" + params=[p,q] + rows=pg_read(query,params) lights = 0 for x, y, z, w in rows: lights += 1 - packets.append(packet(LIGHT, p, q, x, y, z, w)) - query = ( - 'select x, y, z, face, text from sign where ' - 'p = :p and q = :q;' - ) - rows = self.execute(query, dict(p=p, q=q)) + packets += packet(LIGHT, p, q, x, y, z, w) + query="""select x, y, z, face, text from sign where p = %s and q = %s;""" + params=[p,q] + rows=pg_read(query,params) signs = 0 for x, y, z, face, text in rows: signs += 1 - packets.append(packet(SIGN, p, q, x, y, z, face, text)) + packets += packet(SIGN, p, q, x, y, z, face, text) if blocks: - packets.append(packet(KEY, p, q, max_rowid)) + packets += packet(KEY, p, q, max_rowid) if blocks or lights or signs: - packets.append(packet(REDRAW, p, q)) - packets.append(packet(CHUNK, p, q)) - client.send_raw(''.join(packets)) + packets += packet(REDRAW, p, q) + packets += packet(CHUNK, p, q) + client.send_raw(packets) + def on_block(self, client, x, y, z, w): + #log('in on_block:',x,y,z,w) x, y, z, w = map(int, (x, y, z, w)) p, q = chunked(x), chunked(z) previous = self.get_block(x, y, z) message = None if AUTH_REQUIRED and client.user_id is None: - message = 'Only logged in users are allowed to build.' + message = 'in on_block - Only logged in users are allowed to build.' elif y <= 0 or y > 255: message = 'Invalid block coordinates.' elif w not in ALLOWED_ITEMS: @@ -396,18 +507,14 @@ def on_block(self, client, x, y, z, w): client.send(REDRAW, p, q) client.send(TALK, message) return - query = ( - 'insert into block_history (timestamp, user_id, x, y, z, w) ' - 'values (:timestamp, :user_id, :x, :y, :z, :w);' - ) + now = dt.now() if RECORD_HISTORY: - self.execute(query, dict(timestamp=time.time(), - user_id=client.user_id, x=x, y=y, z=z, w=w)) - query = ( - 'insert or replace into block (p, q, x, y, z, w) ' - 'values (:p, :q, :x, :y, :z, :w);' - ) - self.execute(query, dict(p=p, q=q, x=x, y=y, z=z, w=w)) + sql = """insert into block_history (created_at,user_id,p,q,x,y,z,w) values (%s,%s,%s,%s,%s,%s,%s,%s)""" + params=[now,client.user_id,p,q,x,y,z,w] + response=pg_write(sql,params) + sql = """insert into block (updated_at,user_id,p,q,x,y,z,w) values (%s,%s,%s,%s,%s,%s,%s,%s) on conflict on constraint unique_block_pqxyz do UPDATE SET w =%s,updated_at=%s""" + params=[now,client.user_id,p,q,x,y,z,w,w,now] + response=pg_write(sql,params) self.send_block(client, p, q, x, y, z, w) for dx in range(-1, 2): for dz in range(-1, 2): @@ -418,26 +525,26 @@ def on_block(self, client, x, y, z, w): if dz and chunked(z + dz) == q: continue np, nq = p + dx, q + dz - self.execute(query, dict(p=np, q=nq, x=x, y=y, z=z, w=-w)) + #params=[now,np,nq,x,y,z,-w] + params=[now,client.user_id,np,nq,x,y,z,-w,-w,now] + response=pg_write(sql,params) self.send_block(client, np, nq, x, y, z, -w) if w == 0: - query = ( - 'delete from sign where ' - 'x = :x and y = :y and z = :z;' - ) - self.execute(query, dict(x=x, y=y, z=z)) - query = ( - 'update light set w = 0 where ' - 'x = :x and y = :y and z = :z;' - ) - self.execute(query, dict(x=x, y=y, z=z)) + sql = """delete from sign where x = %s and y = %s and z = %s""" + params=[x,y,z] + response=pg_write(sql,params) + sql = """update light set w = 0 where x = %s and y = %s and z = %s""" + params=[x,y,z] + response=pg_write(sql,params) + def on_light(self, client, x, y, z, w): x, y, z, w = map(int, (x, y, z, w)) p, q = chunked(x), chunked(z) block = self.get_block(x, y, z) message = None if AUTH_REQUIRED and client.user_id is None: - message = 'Only logged in users are allowed to build.' + #message = 'Only logged in users are allowed to build.' + message = 'in on_block - Only logged in users are allowed to build.' elif block == 0: message = 'Lights must be placed on a block.' elif w < 0 or w > 15: @@ -447,15 +554,15 @@ def on_light(self, client, x, y, z, w): client.send(REDRAW, p, q) client.send(TALK, message) return - query = ( - 'insert or replace into light (p, q, x, y, z, w) ' - 'values (:p, :q, :x, :y, :z, :w);' - ) - self.execute(query, dict(p=p, q=q, x=x, y=y, z=z, w=w)) + sql = """insert or replace into light (p, q, x, y, z, w) values (%s,%s,%s,%s,%s,%s)""" + params=[p,q,x,y,z,w] + response=pg_write(sql,params) self.send_light(client, p, q, x, y, z, w) + def on_sign(self, client, x, y, z, face, *args): if AUTH_REQUIRED and client.user_id is None: - client.send(TALK, 'Only logged in users are allowed to build.') + # client.send(TALK, 'Only logged in users are allowed to build.') + client.send(TALK, 'in on_block - Only logged in users are allowed to build.') return text = ','.join(args) x, y, z, face = map(int, (x, y, z, face)) @@ -467,23 +574,26 @@ def on_sign(self, client, x, y, z, face, *args): return p, q = chunked(x), chunked(z) if text: - query = ( - 'insert or replace into sign (p, q, x, y, z, face, text) ' - 'values (:p, :q, :x, :y, :z, :face, :text);' - ) - self.execute(query, - dict(p=p, q=q, x=x, y=y, z=z, face=face, text=text)) + sql = """insert into sign (p, q, x, y, z, face, text) values (%s,%s,%s,%s,%s,%s,%s) on conflict on constraint sign_xyzface_idx do update set text=%s""" + params[p,q,x,y,z,face,text,text] + response=pg_write(sql,params) else: - query = ( - 'delete from sign where ' - 'x = :x and y = :y and z = :z and face = :face;' - ) - self.execute(query, dict(x=x, y=y, z=z, face=face)) + sql = """delete from sign where x = %s and y = %s and z = %s and face = %s""" + params=[x,y,z,face] + response=pg_write(sql,params) self.send_sign(client, p, q, x, y, z, face, text) + def on_position(self, client, x, y, z, rx, ry): x, y, z, rx, ry = map(float, (x, y, z, rx, ry)) client.position = (x, y, z, rx, ry) self.send_position(client) + if self.is_going_down==1: + now = dt.now() + log('on_position:is_going_down:',self.is_going_down,' client.nick:',client.nick,' x,y,z:',x,y,z) + sql = """insert into user_recent_pos (updated_at,user_id,x,y,z) values (%s,%s,%s,%s,%s) on conflict on constraint unique_username do update set x=%s,y=%s,z=%s""" + params=[now,client.nick,x,y,z,x,y,z] + response=pg_write(sql,params) + def on_talk(self, client, *args): text = ','.join(args) if text.startswith('/'): @@ -505,6 +615,7 @@ def on_talk(self, client, *args): client.send(TALK, 'Unrecognized nick: "%s"' % nick) else: self.send_talk('%s> %s' % (client.nick, text)) + def on_nick(self, client, nick=None): if AUTH_REQUIRED: client.send(TALK, 'You cannot change your nick on this server.') @@ -515,10 +626,12 @@ def on_nick(self, client, nick=None): self.send_talk('%s is now known as %s' % (client.nick, nick)) client.nick = nick self.send_nick(client) + def on_spawn(self, client): client.position = SPAWN_POINT client.send(YOU, client.client_id, *client.position) self.send_position(client) + def on_goto(self, client, nick=None): if nick is None: clients = [x for x in self.clients if x != client] @@ -530,6 +643,7 @@ def on_goto(self, client, nick=None): client.position = other.position client.send(YOU, client.client_id, *client.position) self.send_position(client) + def on_pq(self, client, p, q): p, q = map(int, (p, q)) if abs(p) > 1000 or abs(q) > 1000: @@ -537,6 +651,7 @@ def on_pq(self, client, p, q): client.position = (p * CHUNK_SIZE, 0, q * CHUNK_SIZE, 0, 0) client.send(YOU, client.client_id, *client.position) self.send_position(client) + def on_help(self, client, topic=None): if topic is None: client.send(TALK, 'Type "t" to chat. Type "/" to type commands:') @@ -626,46 +741,33 @@ def send_talk(self, text): for client in self.clients: client.send(TALK, text) -def cleanup(): - world = World(None) - conn = sqlite3.connect(DB_PATH) - query = 'select x, y, z from block order by rowid desc limit 1;' - last = list(conn.execute(query))[0] - query = 'select distinct p, q from block;' - chunks = list(conn.execute(query)) - count = 0 - total = 0 - delete_query = 'delete from block where x = %d and y = %d and z = %d;' - print 'begin;' - for p, q in chunks: - chunk = world.create_chunk(p, q) - query = 'select x, y, z, w from block where p = :p and q = :q;' - rows = conn.execute(query, {'p': p, 'q': q}) - for x, y, z, w in rows: - if chunked(x) != p or chunked(z) != q: - continue - total += 1 - if (x, y, z) == last: - continue - original = chunk.get((x, y, z), 0) - if w == original or original in INDESTRUCTIBLE_ITEMS: - count += 1 - print delete_query % (x, y, z) - conn.close() - print 'commit;' - print >> sys.stderr, '%d of %d blocks will be cleaned up' % (count, total) +def agones_ready(): + try: + headers={'Content-Type':'application/json'} + url='http://localhost:'+AGONES_SDK_HTTP_PORT+'/ready' + payload={} + r=requests.post(url,headers=headers,json={}) + log('in agones_ready:url:',url, ' response.status_code:',r.status_code,' response.headers:',r.headers,' payload:',payload) + except Exception as error: + log('agones_ready:',error) + +model = Model(None) def main(): - if len(sys.argv) == 2 and sys.argv[1] == 'cleanup': - cleanup() - return host, port = DEFAULT_HOST, DEFAULT_PORT if len(sys.argv) > 1: host = sys.argv[1] if len(sys.argv) > 2: port = int(sys.argv[2]) log('SERV', host, port) - model = Model(None) + if IS_AGONES == 'True': + headers={'Content-Type':'application/json'} + url='http://localhost:'+AGONES_SDK_HTTP_PORT+'/ready' + payload={} + r=requests.post(url,headers=headers,json={}) + log('in agones_ready:url:',url, ' response.status_code:',r.status_code,' response.headers:',r.headers,' payload:',payload) + #agones_ready() + signal.signal(signal.SIGTERM,sig_handler) model.start() server = Server((host, port), Handler) server.model = model diff --git a/src/auth.c b/src/auth.c index 4ff781580..d9357951f 100644 --- a/src/auth.c +++ b/src/auth.c @@ -21,7 +21,9 @@ size_t write_function(char *data, size_t size, size_t count, void *arg) { int get_access_token( char *result, int length, char *username, char *identity_token) { - static char url[] = "https://craft.michaelfogleman.com/api/1/identity"; + printf("auth.c/get_access_token:username=%s,identity_token=%s\n",username,identity_token); + //static char url[] = "https://craft.michaelfogleman.com/api/1/identity"; + static char url[] = "http://craft.auth.yahav.sa.aws.dev/auth/identity/"; strncpy(result, "", length); CURL *curl = curl_easy_init(); if (curl) { @@ -30,6 +32,7 @@ int get_access_token( long http_code = 0; snprintf(post, MAX_POST_LENGTH, "username=%s&identity_token=%s", username, identity_token); + printf("auth.c/get_access_token2:username=%s,identity_token=%s\n",username,identity_token); #ifdef _WIN32 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); #endif