Skip to content

Commit

Permalink
browser server added #11
Browse files Browse the repository at this point in the history
  • Loading branch information
Zamme committed Jun 12, 2024
1 parent afe6969 commit 4d48176
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 35 deletions.
67 changes: 67 additions & 0 deletions B2G3/blender2godot/b2g_misc/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/env python3

import argparse
import contextlib
import os
import socket
import subprocess
import sys
from http.server import HTTPServer, SimpleHTTPRequestHandler, test # type: ignore
from pathlib import Path


# See cpython GH-17851 and GH-17864.
class DualStackServer(HTTPServer):
def server_bind(self):
# Suppress exception when protocol is IPv4.
with contextlib.suppress(Exception):
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
return super().server_bind()


class CORSRequestHandler(SimpleHTTPRequestHandler):
def end_headers(self):
self.send_header("Cross-Origin-Opener-Policy", "same-origin")
self.send_header("Cross-Origin-Embedder-Policy", "require-corp")
self.send_header("Access-Control-Allow-Origin", "*")
super().end_headers()


def shell_open(url):
if sys.platform == "win32":
os.startfile(url)
else:
opener = "open" if sys.platform == "darwin" else "xdg-open"
subprocess.call([opener, url])


def serve(root, port, run_browser):
os.chdir(root)

if run_browser:
# Open the served page in the user's default browser.
print("Opening the served URL in the default browser (use `--no-browser` or `-n` to disable this).")
shell_open(f"http://127.0.0.1:{port}")

test(CORSRequestHandler, DualStackServer, port=port)


if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-p", "--port", help="port to listen on", default=8060, type=int)
parser.add_argument(
"-r", "--root", help="path to serve as root (relative to `platform/web/`)", default="../../bin", type=Path
)
browser_parser = parser.add_mutually_exclusive_group(required=False)
browser_parser.add_argument(
"-n", "--no-browser", help="don't open default web browser automatically", dest="browser", action="store_false"
)
parser.set_defaults(browser=True)
args = parser.parse_args()

# Change to the directory where the script is located,
# so that the script can be run from any location.
os.chdir(Path(__file__).resolve().parent)

serve(args.root, args.port, args.browser)

23 changes: 1 addition & 22 deletions B2G3/blender2godot/game_export/game_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,6 @@ def build_game(self, context):
self.export_presets_filepath = os.path.join(context.scene.project_folder, "export_presets.cfg")
self.add_selected_export_presets(context)
print("Compiling...")
#bpy.ops.scene.compile_selected_versions_operator()
bpy.ops.scene.compile_selected_versions_operator('INVOKE_DEFAULT')

def config_presets(self, context):
Expand Down Expand Up @@ -401,6 +400,7 @@ def compile_exe(self, context):
os.mkdir(context.scene.web_exports_path)
print("Web version...OK")
context.scene.web_exe_filepath = os.path.join(context.scene.web_exports_path, context.scene.game_name)
context.scene.web_exe_filepath += ".html"
self.process = subprocess.Popen([bpy.path.abspath(context.scene.godot_executable), "--no-window", "--path", context.scene.project_folder, "--export", "HTML5", context.scene.web_exe_filepath], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print("Web version exported at :", context.scene.web_exports_path)
#return {'FINISHED'}
Expand All @@ -423,27 +423,6 @@ def set_pending_platforms(self, context):
self.pending_platforms.append(self.available_platforms[4])
print("Pending versions: ", self.pending_platforms)

'''
def execute(self, context):
self.all_compiled = False
self.process = None
self.create_builds_folder(context)
self.set_pending_platforms(context)
while (len(self.pending_platforms) > 0):
if self.process is None:
print("Process None")
context.scene.current_version_compiling = self.pending_platforms.pop()
self.compile_exe(context)
else:
if self.process.poll() == 0:
print("Process Next")
context.scene.current_version_compiling = self.pending_platforms.pop()
self.compile_exe(context)
self.all_compiled = True
print("Processes completed")
return {'FINISHED'}
'''

def modal(self, context, event):
if self.all_compiled == True:
print("Processes completed")
Expand Down
92 changes: 79 additions & 13 deletions B2G3/blender2godot/test_project/test_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,94 @@


"""
Testing game actions
Testing game
"""

import subprocess
import os

import contextlib
import socket
import sys
from http.server import HTTPServer, SimpleHTTPRequestHandler, test # type: ignore
from pathlib import Path

import bpy
from blender2godot.addon_config import addon_config # type: ignore


### BROWSER SERVER ###
# See cpython GH-17851 and GH-17864.
class DualStackServer(HTTPServer):
def server_bind(self):
# Suppress exception when protocol is IPv4.
with contextlib.suppress(Exception):
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
return super().server_bind()


class CORSRequestHandler(SimpleHTTPRequestHandler):
def end_headers(self):
self.send_header("Cross-Origin-Opener-Policy", "same-origin")
self.send_header("Cross-Origin-Embedder-Policy", "require-corp")
self.send_header("Access-Control-Allow-Origin", "*")
super().end_headers()

class TestGameOperator(bpy.types.Operator): # It blocks blender execution until game exits
"""Test Game Operator"""
bl_idname = "scene.test_game_operator"
bl_label = "Test Last Exported Game"

### END BROWSER SERVER ###


class TestProjectGameOperator(bpy.types.Operator): # It blocks blender execution until game exits
"""Test Project Game Operator"""
bl_idname = "scene.test_project_game_operator"
bl_label = "Test Last Exported Project"

def start_game(self, context):
print("Starting game", context.scene.project_folder)
def start_project_game(self, context):
print("Starting project game", context.scene.project_folder)
self.cmd = subprocess.Popen([bpy.path.abspath(context.scene.godot_executable), "--path", context.scene.project_folder], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

def main(self, context):
self.start_game(context)
self.start_project_game(context)

def execute(self, context):
self.main(context)
return {'FINISHED'}

class TestBrowserGameOperator(bpy.types.Operator): # It blocks blender execution until game exits
"""Test Browser Game Operator"""
bl_idname = "scene.test_browser_game_operator"
bl_label = "Test Browser Build"

_output = None
_testing = False
_port = 8060

def shell_open(self, context, url):
if sys.platform == "win32":
os.startfile(url)
else:
opener = "open" if sys.platform == "darwin" else "xdg-open"
self._output = subprocess.run([opener, url])
print("Output:", self._output)

def execute(self, context):
return {'FINISHED'}

def modal(self, context, event):
if not self._testing:
self._testing = True
test(CORSRequestHandler, DualStackServer, port=self._port)
return {'PASS_THROUGH'}

def invoke(self, context, event):
print("Starting browser game", context.scene.project_folder)
self._path = context.scene.web_exe_filepath.rpartition(os.sep)[0]
print(self._path)
os.chdir(self._path)
self._testing = False
self.shell_open(context, f"http://127.0.0.1:{self._port}")
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}

class TestGamePanel(bpy.types.Panel):
"""Test Game Panel"""
Expand All @@ -63,7 +126,6 @@ def draw_header(self, context):

def draw(self, context):
layout = self.layout
scene = context.scene

if not bpy.data.is_saved:
return
Expand All @@ -79,15 +141,19 @@ def draw(self, context):
box = row.box()
if (os.path.isdir(context.scene.project_folder) and (context.scene.godot_export_ok)):
row.alignment="CENTER"
box.operator("scene.test_game_operator", icon="PLAY")
box.operator("scene.test_project_game_operator", icon="PLAY")
if os.path.isfile(context.scene.web_exe_filepath + ".html"):
box.operator_context = 'INVOKE_DEFAULT'
box.operator("scene.test_browser_game_operator", icon_value=addon_config.preview_collections[0]["godot_icon"].icon_id)
else:
box.label(text="Export to godot before testing", icon="ERROR")


def register():
bpy.utils.register_class(TestGameOperator)
bpy.utils.register_class(TestProjectGameOperator)
bpy.utils.register_class(TestBrowserGameOperator)
bpy.utils.register_class(TestGamePanel)

def unregister():
bpy.utils.unregister_class(TestGamePanel)
bpy.utils.unregister_class(TestGameOperator)
bpy.utils.unregister_class(TestBrowserGameOperator)
bpy.utils.unregister_class(TestProjectGameOperator)

0 comments on commit 4d48176

Please sign in to comment.