Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
c8ccb4d
Add isolated WebAssembly browser build and host gateway
genixpro Sep 8, 2026
213ba0a
Run browser gameplay through scheduled screen lifecycles
genixpro Sep 8, 2026
4f9e004
Add browser YOG cross-play and deployment support
genixpro Sep 8, 2026
ef191bb
Add durable storage, imports, resizing, and WebGL2
genixpro Sep 8, 2026
b5da8ce
Stabilize and qualify the browser release
genixpro Sep 8, 2026
ecc35f7
Fix stale trapped-unit-test harness path in CI
genixpro Sep 10, 2026
750ea6d
Regenerate cross-replay.replay for the version-94 floor
genixpro Sep 10, 2026
7662aec
Translate the new browser-durability/import UI strings
genixpro Sep 10, 2026
f01e020
Fix compile/runtime gaps from the CustomGameScreen/SettingsScreen merge
genixpro Sep 10, 2026
c5df9cb
Fix remaining stale build/src/ paths in CI
genixpro Sep 10, 2026
7a3c399
Make SettingsScreen::persist() write unconditionally, not only when d…
genixpro Sep 10, 2026
1273e92
Fix browser Settings test failures: stale coordinates, not a save bug
genixpro Sep 10, 2026
06c48ae
Fix CustomGameScreen browser crash and stale test coordinates
genixpro Sep 10, 2026
306ccbf
Route the map-import browser test through the editor, not the gone lo…
genixpro Sep 10, 2026
ad1da55
Theme ScreenStack-driven menus and make FrontendScope order-independent
genixpro Sep 11, 2026
62365ce
Size the browser canvas to the viewport before creating the SDL window
genixpro Sep 11, 2026
3d4a015
Enable the torus overview in WebGL2 browser builds
genixpro Sep 11, 2026
0733a71
Keep a generated custom map until its match has loaded
genixpro Sep 11, 2026
4d71872
Draw scaled surfaces in the software renderer
genixpro Sep 11, 2026
4a626e1
Default the browser to WebGL2 when it is hardware accelerated
genixpro Sep 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
14 changes: 14 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.git
build
build-*
tools/browser-emsdk
browser/node_modules
.codex
**/__pycache__
*.o
*.a
.scons*
config.h

.env
**/.env
198 changes: 155 additions & 43 deletions .github/workflows/build.yml

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,10 @@ Glob2-*.dmg
/build-server/

/artifacts/
/tools/browser-emsdk/
/build-browser/
/build-browser.log
/build-*-support.log
/test/build/
/build-*.log
/browser/node_modules
107 changes: 78 additions & 29 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,24 @@ EnsureSConsVersion(3, 0, 0)
import sys
import os
import glob
from io import StringIO
import io
import atexit
from pathlib import Path
sys.path.append( os.path.abspath("scons") )
import bundle
import ccache
import dmg
import nsis
from sources import INCLUDE_DIRECTORIES
from build_layout import build_identity, default_directory, prepare_directory, write_if_changed, BuildLock

isWindowsPlatform = sys.platform=='win32'
isLinuxPlatform = sys.platform.startswith('linux')
isDarwinPlatform = sys.platform=='darwin'


def establish_options(env):
opts = Variables('options_cache.py')
opts = Variables()
opts.Add("CXX", "C++ compiler", env["CXX"])
opts.Add("CXXFLAGS", "Manually add to the CXXFLAGS", "-g")
opts.Add("LINKFLAGS", "Manually add to the LINKFLAGS", "-g")
Expand All @@ -27,6 +31,7 @@ def establish_options(env):
opts.Add("DATADIR", "Directory where data will be put, set to the same as INSTALLDIR", "/usr/local/share")
opts.Add(BoolVariable("release", "Build for release", 0))
opts.Add(BoolVariable("opengl", "Enable OpenGL detection; set to 0 for software rendering only", 1))
opts.Add(BoolVariable("wss", "Enable native secure WebSocket transport", 1))
opts.Add(BoolVariable("profile", "Build with profiling on", 0))
opts.Add(BoolVariable("mingw", "Build with mingw enabled if not auto-detected", 0))
opts.Add(BoolVariable("mingwcross", "Cross-compile with mingw for Win32", 0))
Expand All @@ -35,26 +40,37 @@ def establish_options(env):
opts.Add("font", "Build the game using an alternative font placed in the data/font folder", "sans.ttf")
Help(opts.GenerateHelpText(env))
opts.Update(env)
opts.Save("options_cache.py", env)
if env.GetOption('clean'):
Execute(Delete("options_cache.py"))
opts.Save(str(Path(env["BUILDDIR"]) / "options.py"), env)


class Configuration:
"""Handles the config.h file"""
def __init__(self):
self.f = StringIO()
self.f.write("// config.h. Generated by scons\n")
"""Writes only the selected target configuration, without touching source files."""
def __init__(self, env):
self.env = env
self.path = Path(env["BUILDDIR"]) / "include/glob2/BuildConfig.h"
self.f = io.StringIO()
self.f.write("#pragma once\n// Generated by SCons.\n")
self.f.write("\n")
def finish(self):
content = self.f.getvalue()
def write_configuration(target, source, env):
write_if_changed(str(target[0]), content)
return 0
# Register a generated header with SCons before dependency scanning.
# Writing it directly while parsing leaves a cold build's cached
# directory lookup unaware of it, so the next build recompiles objects.
self.env.Command(str(self.path), Value(content),
Action(write_configuration, 'Generating $TARGET'))

def add(self, variable, doc, value=""):
self.f.write("// %s\n" % doc)
self.f.write("#define %s %s\n" % (variable, value))
self.f.write("\n")

def configure(env, server_only):
"""Configures glob2"""
conf = Configure(env.Clone())
configfile = Configuration()
conf = Configure(env.Clone(), conf_dir=str(Path(env["BUILDDIR"]) / "configure"), log_file=str(Path(env["BUILDDIR"]) / "configure.log"))
configfile = Configuration(env)
configfile.add("PACKAGE", "Name of package", "\"glob2\"")
configfile.add("PACKAGE_BUGREPORT", "Define to the address where bug reports for this package should be sent.", "\"glob2-devel@nongnu.org\"")
if isDarwinPlatform:
Expand Down Expand Up @@ -147,6 +163,15 @@ def configure(env, server_only):
if conf.CheckLib("boost_system"):
env.Append(LIBS=["boost_system"])
env.Append(LIBS=["pthread"])
if not server_only and env["wss"]:
if not conf.CheckCXXHeader("openssl/ssl.h") or not conf.CheckLib("ssl") or not conf.CheckLib("crypto"):
missing.append("OpenSSL development headers and libraries")
env.Append(LIBS=["ssl", "crypto"])
configfile.add("GLOB2_NATIVE_WSS", "Defined when native secure WebSocket support is compiled")
if not server_only:
if env["mingw"] or env["mingwcross"]:
env.Append(LIBS=["ws2_32", "mswsock"])



if not conf.CheckCXXHeader("boost/logic/tribool.hpp"):
Expand Down Expand Up @@ -235,6 +260,7 @@ def configure(env, server_only):
print("Missing %s" % t)
Exit(1)

configfile.finish()
conf.Finish()
contents = configfile.f.getvalue()
previous = None
Expand All @@ -254,22 +280,56 @@ def main():
metavar='portaudio',
help='should portaudio be used')
AddOption('--build',
default='build',
default=None,
help='build directory')
env = Environment()
identity = build_identity(ARGUMENTS)
bdir = str(GetOption('build') or default_directory(identity))
Path(bdir).mkdir(parents=True, exist_ok=True)
build_lock = BuildLock(bdir)
atexit.register(build_lock.close)
prepare_directory(bdir, identity)
temporary = str((Path(bdir) / 'tmp').resolve())
Path(temporary).mkdir(parents=True, exist_ok=True)
# Includes response files created by SCons itself, not just compiler children.
import tempfile
tempfile.tempdir = temporary
SConsignFile(str(Path(bdir) / '.sconsign'))
if identity['target'] == 'web':
from web_build import build_web
build_web(bdir, identity, ARGUMENTS)
return
if identity['role'] == 'gateway':
from gateway_build import build_gateway
build_gateway(bdir, identity, ARGUMENTS)
return
env = Environment(tools=[])
# SCons scrubs the shell environment for build commands; without TMPDIR,
# tools like ar fall back to /tmp, which sandboxed environments may block.
if 'TMPDIR' in os.environ:
env['ENV']['TMPDIR'] = os.environ['TMPDIR']
# Respect an explicit Apple toolchain selection without changing xcode-select globally.
if 'DEVELOPER_DIR' in os.environ:
env['ENV']['DEVELOPER_DIR'] = os.environ['DEVELOPER_DIR']
# Likewise for SOURCE_DATE_EPOCH, needed by build tools for reproducible builds.
if 'SOURCE_DATE_EPOCH' in os.environ:
env['ENV']['SOURCE_DATE_EPOCH'] = os.environ['SOURCE_DATE_EPOCH']
# Compiler discovery also needs the selected SDK, not just compilation.
env.Tool('default')
env['BUILDDIR'] = bdir
env.Prepend(CPPPATH=[env.Dir(bdir + '/include')])
env['ENV'].update(TMPDIR=temporary, TMP=temporary, TEMP=temporary)
env["VERSION"] = "0.9.5.0"
establish_options(env)
env["server"] = identity["role"] in ("server", "router")
env["role"] = identity["role"]
if identity["role"] == "router":
env.Append(CPPDEFINES=["GLOB2_ROUTER_ONLY"])

# Emit compile_commands.json for clangd / IDE LSPs.
env.Tool('compilation_db')
env.CompilationDatabase()
database = env.CompilationDatabase(bdir + '/compile_commands.json')
env.Alias('compile_commands.json', database)
env.Default(database)

if env['mingw'] or env['mingwcross']:
Tool('mingw')(env)
Expand Down Expand Up @@ -327,17 +387,7 @@ def main():
env.Append(CPPDEFINES=["WIN32"])
configure(env, server_only)

env.Append(CPPPATH=['#libgag/include', '#'])
env.Append(CPPPATH=['#libusl/src', '#'])
env.Append(CPPPATH=['#src', '#src/yog', '#src/ai', '#src/building',
'#src/game/entities',
'#src/gui',
'#src/map', '#src/map/edit', '#src/map/generator',
'#src/map/gradient', '#src/map/io', '#src/map/pathfind',
'#src/net', '#src/net/irc', '#src/net/message',
'#src/sgsl',
'#src/team',
'#src/unit'])
env.Append(CPPPATH=['#'+path for path in INCLUDE_DIRECTORIES])
env.Append(CXXFLAGS=["-Wall", "-fPIC"])
# Uninitialized-read diagnostics: DET_INIT=zero|pattern forces deterministic
# stack initialization (see CLAUDE.md). Env var, not a cached scons option.
Expand Down Expand Up @@ -391,12 +441,12 @@ def main():

PackTar(env["TARFILE"], Split("COPYING INSTALL mkdist mkinstall mkuninstall README README.hg SConstruct"))
#packaging for apple
if isDarwinPlatform and env["release"] and "bundle" in COMMAND_LINE_TARGETS:
if isDarwinPlatform and env["release"] and "package" in COMMAND_LINE_TARGETS:
bundle.generate(env)
dmg.generate(env)
env.Replace(
BUNDLE_NAME="Glob2",
BUNDLE_BINARIES=["src/glob2"],
BUNDLE_NAME=bdir+"/Glob2",
BUNDLE_BINARIES=[bdir+"/src/glob2"],
BUNDLE_RESOURCEDIRS=["data","maps", "campaigns"],
BUNDLE_PLIST="darwin/Info.plist",
BUNDLE_ICON="darwin/Glob2.icns" )
Expand All @@ -415,7 +465,6 @@ def main():
Export('crossroot_abs')
Export('isWindowsPlatform')

bdir = GetOption('build')
targets = [
"campaigns",
"data",
Expand Down
Loading
Loading