Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove Rivet code #5

Draft
wants to merge 2 commits into
base: 12-30-Overhaul_bomber_tutorial
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,6 @@
*.webm filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text

# Godot
*.tscn filter=lfs diff=lfs merge=lfs -text
*.tres filter=lfs diff=lfs merge=lfs -text
*.scn filter=lfs diff=lfs merge=lfs -text
*.res filter=lfs diff=lfs merge=lfs -text
*.import filter=lfs diff=lfs merge=lfs -text

# Unity
*.anim filter=lfs diff=lfs merge=lfs -text
*.asset filter=lfs diff=lfs merge=lfs -text
Expand Down
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@
# Godot-specific ignores
.import/
export.cfg
export_presets.cfg

# Godot 4.1 can let export_presets be commited. This can be changed on an
# example level if any future examples work with Godot <4.1.
# https://github.com/github/gitignore/pull/2827
# https://github.com/godotengine/godot/pull/76165
# export_presets.cfg

# Imported translations (automatically generated from CSV files)
*.translation
Expand Down
33 changes: 0 additions & 33 deletions godot/bomber/Dockerfile

This file was deleted.

2 changes: 1 addition & 1 deletion godot/bomber/LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2024 Rivet
Copyright (c) 2023 Rivet

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
13 changes: 8 additions & 5 deletions godot/bomber/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# Bomber
# Multiplayer Bomber

<p align="center">
<img src="./_media/preview_512.png" />
</p>
A multiplayer implementation of the classical bomberman game.
One of the players should press "host", while the other
should type in his address and press "play".

Language: GDScript

[Visit Tutorial](https://rivet.gg/learn/godot/tutorials/crash-course)
Renderer: GLES 2

Check out this demo on the asset library: https://godotengine.org/asset-library/asset/139



Expand All @@ -31,3 +33,4 @@

[Documentation](https://rivet.gg/learn/godot/tutorials/crash-course#step-4-deploy-to-rivet)

![Screenshot](screenshots/bomber.png)
132 changes: 132 additions & 0 deletions godot/bomber/addons/rivet/api/rivet_api.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
class_name RivetApi
const RivetRequest = preload("rivet_request.gd")

static var CONFIGURATION_CACHE

static func _get_configuration():
if CONFIGURATION_CACHE:
return CONFIGURATION_CACHE

if FileAccess.file_exists(RivetPluginBridge.RIVET_CONFIGURATION_FILE_PATH):
var config_file = ResourceLoader.load(RivetPluginBridge.RIVET_CONFIGURATION_FILE_PATH)
if config_file and 'new' in config_file:
CONFIGURATION_CACHE = config_file.new()
return CONFIGURATION_CACHE

if FileAccess.file_exists(RivetPluginBridge.RIVET_DEPLOYED_CONFIGURATION_FILE_PATH):
var deployed_config_file = ResourceLoader.load(RivetPluginBridge.RIVET_DEPLOYED_CONFIGURATION_FILE_PATH)
if deployed_config_file and 'new' in deployed_config_file:
CONFIGURATION_CACHE = deployed_config_file.new()
return CONFIGURATION_CACHE

push_warning("Rivet configuration file not found")
CONFIGURATION_CACHE = null
return CONFIGURATION_CACHE

static func _get_api_url():
# Use plugin config if available
var plugin = RivetPluginBridge.get_plugin()
if plugin:
return plugin.api_endpoint

# Override shipped configuration endpoint
var url_env = OS.get_environment("RIVET_API_ENDPOINT")
if url_env:
return url_env

# Use configuration shipped with game
var config = _get_configuration()
if config:
return config.api_endpoint

# Fallback
return "https://api.rivet.gg"

## Get authorization token used from within only the plugin for cloud-specific
## actions.
static func _get_cloud_token():
# Use plugin config if available
var plugin = RivetPluginBridge.get_plugin()
if plugin:
return plugin.cloud_token

OS.crash("Rivet cloud token not found, this should only be called within the plugin")

## Get authorization token used for making requests from within the game.
##
## The priority of tokens is:
##
## - If in editor, use the plugin token
## - If provided by environment, then use that (allows for testing)
## - Assume config is provided by the game client
static func _get_runtime_token():
# Use plugin config if available
var plugin = RivetPluginBridge.get_plugin()
if plugin:
return plugin.namespace_token

# Use configuration shipped with game
var token_env = OS.get_environment("RIVET_TOKEN")
if token_env:
return token_env

# Use configuration shipped with game
var config = _get_configuration()
if config:
return config.namespace_token

OS.crash("Rivet token not found, validate a config is shipped with the game in the .rivet folder")

## Builds the headers for a request, including the authorization token
static func _build_headers(service: String) -> PackedStringArray:
var token = _get_cloud_token() if service == "cloud" else _get_runtime_token()
return [
"Authorization: Bearer " + token,
]

## Builds a URL to Rivet cloud services
static func _build_url(path: String, service: String) -> String:
var path_segments := path.split("/", false)
path_segments.remove_at(0)
return _get_api_url() + "/%s/%s" % [service, "/".join(path_segments)]

## Gets service name from a path (e.g. /users/123 -> users)
static func _get_service_from_path(path: String) -> String:
var path_segments := path.split("/", false)
return path_segments[0]

## Creates a POST request to Rivet cloud services
## @experimental
static func POST(owner: Node, path: String, body: Dictionary) -> RivetRequest:
var service := _get_service_from_path(path)
var url := _build_url(path, service)
var body_json := JSON.stringify(body)

return RivetRequest.new(owner, HTTPClient.METHOD_POST, url, {
"headers": _build_headers(service),
"body": body_json
})

## Creates a GET request to Rivet cloud services
## @experimental
static func GET(owner: Node, path: String, body: Dictionary) -> RivetRequest:
var service := _get_service_from_path(path)
var url := _build_url(path, service)
var body_json := JSON.stringify(body)

return RivetRequest.new(owner, HTTPClient.METHOD_GET, url, {
"headers": _build_headers(service),
"body": body_json
})

## Creates a PUT request to Rivet cloud services
## @experimental
static func PUT(owner: Node, path: String, body: Dictionary) -> RivetRequest:
var service := _get_service_from_path(path)
var url := _build_url(path, service)
var body_json := JSON.stringify(body)

return RivetRequest.new(owner, HTTPClient.METHOD_PUT, url, {
"headers": _build_headers(service),
"body": body_json
})
97 changes: 97 additions & 0 deletions godot/bomber/addons/rivet/api/rivet_packages.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
const _RivetResponse = preload("rivet_response.gd")

## Lobbies
## @experimental
class Lobbies:
## Finds a lobby based on the given criteria. If a lobby is not found and
## prevent_auto_create_lobby is true, a new lobby will be created.
##
## [url]{https://rivet.gg/docs/matchmaker/api/lobbies/find}[/url]
func find(body: Dictionary = {}):
return await Rivet.POST("matchmaker/lobbies/find", body).wait_completed()

## Joins a specific lobby. This request will use the direct player count
## configured for the lobby group.
##
## [url]{https://rivet.gg/docs/matchmaker/api/lobbies/join}[/url]
func join(body: Dictionary = {}) -> _RivetResponse:
return await Rivet.POST("matchmaker/lobbies/join", body).wait_completed()

## Marks the current lobby as ready to accept connections. Players will not
## be able to connect to this lobby until the lobby is flagged as ready.
##
## [url]{https://rivet.gg/docs/matchmaker/api/lobbies/ready}[/url]
func ready(body: Dictionary = {}) -> _RivetResponse:
return await Rivet.POST("matchmaker/lobbies/ready", body).wait_completed()

## If is_closed is true, the matchmaker will no longer route players to the
## lobby. Players can still join using the /join endpoint (this can be disabled
## by the developer by rejecting all new connections after setting the lobby
## to closed). Does not shutdown the lobby.
##
## [url]{https://rivet.gg/docs/matchmaker/api/lobbies/set-closed}[/url]
func setClosed(body: Dictionary = {}) -> _RivetResponse:
return await Rivet.PUT("matchmaker/lobbies/set_closed", body).wait_completed()

## Creates a custom lobby.
##
## [url]{https://rivet.gg/docs/matchmaker/api/lobbies/create}[/url]
func create(body: Dictionary = {}) -> _RivetResponse:
return await Rivet.POST("matchmaker/lobbies/create", body).wait_completed()

## Lists all open lobbies.
##
## [url]{https://rivet.gg/docs/matchmaker/api/lobbies/list}[/url]
func list(body: Dictionary = {}) -> _RivetResponse:
return await Rivet.GET("matchmaker/lobbies/list", body).wait_completed()

##
##
## [url]{https://rivet.gg/docs/matchmaker/api/lobbies/set-state}[/url]
func setState(body: Dictionary = {}) -> _RivetResponse:
return await Rivet.PUT("matchmaker/lobbies/state", body).wait_completed()

##
##
## [url]{https://rivet.gg/docs/matchmaker/api/lobbies/get-state}[/url]
func getState(lobby_id, body: Dictionary = {}) -> _RivetResponse:
return await Rivet.GET("matchmaker/lobbies/{lobby_id}/state".format({"lobby_id": lobby_id}), body).wait_completed()

## Players
## @experimental
class Players:
## Validates the player token is valid and has not already been consumed then
## marks the player as connected.
##
## [url]{https://rivet.gg/docs/matchmaker/api/players/connected}[/url]
func connected(body: Dictionary = {}) -> _RivetResponse:
return await Rivet.POST("matchmaker/players/connected", body).wait_completed()

## Marks a player as disconnected. # Ghost Players.
##
## [url]{https://rivet.gg/docs/matchmaker/api/players/disconnected}[/url]
func disconnected(body: Dictionary = {}) -> _RivetResponse:
return await Rivet.POST("matchmaker/players/disconnected", body).wait_completed()

## Gives matchmaker statistics about the players in game.
##
## [url]{https://rivet.gg/docs/matchmaker/api/players/statistics}[/url]
func getStatistics(body: Dictionary = {}) -> _RivetResponse:
return await Rivet.GET("matchmaker/players/statistics", body).wait_completed()

class Regions:
## Returns a list of regions available to this namespace.
## Regions are sorted by most optimal to least optimal.
## The player's IP address is used to calculate the regions' optimality.
##
## [url]{https://rivet.gg/docs/matchmaker/api/regions/list}[/url]
func list(body: Dictionary = {}) -> _RivetResponse:
return await Rivet.GET("matchmaker/regions", body).wait_completed()

## Matchmaker
## @experimental
## @tutorial: https://rivet.gg/docs/matchmaker
class Matchmaker:
static var lobbies: Lobbies = Lobbies.new()
static var players: Players = Players.new()
static var regions: Regions = Regions.new()
57 changes: 57 additions & 0 deletions godot/bomber/addons/rivet/api/rivet_request.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
extends RefCounted
## A wrapper around HTTPRequest that emits a signal when the request is completed.
## This is a workaround for the fact that `HTTPRequest.request()` is blocking.
## To run a request, create a new RivetRequest, connect to the completed signal,
## and call `request().wait_completed()` to wait for the request to complete.


const _RivetResponse := preload("rivet_response.gd")
const _RivetRequest := preload("rivet_request.gd")

var response: _RivetResponse = null
var _opts: Dictionary
var _http_request: HTTPRequest

var _success_callback: Callable
var _failure_callback: Callable

signal completed(response: _RivetResponse)
signal succeeded(response: _RivetResponse)
signal failed(response: _RivetResponse)

func _init(owner: Node, method: HTTPClient.Method, url: String, opts: Variant = null):
self._http_request = HTTPRequest.new()
self._http_request.request_completed.connect(_on_request_completed)
self._opts = {
"method": method,
"url": url,
"body": opts.body,
"headers": opts.headers,
}
owner.add_child(self._http_request)
self._http_request.request(_opts.url, _opts.headers, _opts.method, _opts.body)

func set_success_callback(callback: Callable) -> _RivetRequest:
self._success_callback = callback
return self

func set_failure_callback(callback: Callable) -> _RivetRequest:
self._failure_callback = callback
return self

func _on_request_completed(result, response_code, headers, body):
self.response = _RivetResponse.new(result, response_code, headers, body)
if result == OK:
succeeded.emit(response)
if self._success_callback:
self._success_callback.call(response)
else:
failed.emit(response)
if self._failure_callback:
self._failure_callback.call(response)
completed.emit(response)

## Waits for the request to complete and returns the response in non-blocking way
func wait_completed() -> _RivetResponse:
await completed
return response
Loading