first grpc implementation
release-tag / release-image (push) Failing after 50s

This commit is contained in:
2024-05-20 15:01:04 +02:00
parent b6cbc513cb
commit 3892e4595b
19 changed files with 2142 additions and 399 deletions
+3
View File
@@ -0,0 +1,3 @@
[submodule "proto"]
path = proto
url = git@git.legonzaur.fr:legonzaur/heron-realms-protobuf.git
+25 -25
View File
@@ -1,8 +1,8 @@
<script setup lang="ts">
import goStore, { setReady, oauth2_register_discord, setup_websocket, heron_cookie_login } from "@/netcode";
// import goStore, { setReady, oauth2_register_discord, setup_websocket, heron_cookie_login } from "@/netcode";
await setup_websocket()
// await setup_websocket()
useHead
({
@@ -15,30 +15,30 @@ useHead
const heron_session = useCookie('heron_session')
const route = useRoute()
onMounted(async () => {
const code = route.query.code
if (!code) { return }
if (Array.isArray(code)) { return }
await setup_websocket()
oauth2_register_discord(code)
history.pushState(
{},
'',
'/'
)
})
// onMounted(async () => {
// const code = route.query.code
// if (!code) { return }
// if (Array.isArray(code)) { return }
// await setup_websocket()
// oauth2_register_discord(code)
// history.pushState(
// {},
// '',
// '/'
// )
// })
onMounted(async () => {
if (!heron_session.value) { return }
heron_cookie_login(heron_session.value)
})
// onMounted(async () => {
// if (!heron_session.value) { return }
// heron_cookie_login(heron_session.value)
// })
function keyDownHandler(e: KeyboardEvent) {
if (e.repeat) { return }
console.log(e.code)
if (e.code != "AltLeft") { return }
goStore.zoomKeyPressed = true
// goStore.zoomKeyPressed = true
e.preventDefault()
return false
}
@@ -46,7 +46,7 @@ function keyDownHandler(e: KeyboardEvent) {
function keyUpHandler(e: KeyboardEvent) {
if (e.repeat) { return }
if (e.code != "AltLeft") { return }
goStore.zoomKeyPressed = false
// goStore.zoomKeyPressed = false
e.preventDefault()
return false
}
@@ -57,21 +57,21 @@ function contextMenuHandler(e: MouseEvent) {
function mouseDownHandler(e: MouseEvent) {
if (e.button !== 2) { return }
goStore.zoomKeyPressed = true
// goStore.zoomKeyPressed = true
e.preventDefault()
return false
}
function mouseUpHandler(e: MouseEvent) {
if (e.button !== 2) { return }
goStore.zoomKeyPressed = false
// goStore.zoomKeyPressed = false
e.preventDefault()
return false
}
function follow_mouse(e: MouseEvent) {
goStore.clientMouseX = e.clientX
goStore.clientMouseY = e.clientY
// goStore.clientMouseX = e.clientX
// goStore.clientMouseY = e.clientY
}
onMounted(() => {
@@ -92,7 +92,7 @@ onDeactivated
</script>
<template>
<div class="root_dom_div">
<CardOverlay v-if="goStore.zoomKeyPressed" :card_id="goStore.hoveredCard" />
<!-- <CardOverlay v-if="goStore.zoomKeyPressed" :card_id="goStore.hoveredCard" /> -->
<NuxtPage />
</div>
</template>
+6
View File
@@ -0,0 +1,6 @@
services:
envoy:
image: envoyproxy/envoy:v1.22.0
network_mode: "host"
volumes: "./envoy.yaml:/etc/envoy/envoy.yaml"
entrypoint: "/usr/local/bin/envoy -c /etc/envoy/envoy.yaml -l trace --log-path /tmp/envoy_info.log"
+66
View File
@@ -0,0 +1,66 @@
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 8080 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route:
cluster: echo_service
timeout: 0s
max_stream_duration:
grpc_timeout_header_max: 0s
cors:
allow_origin_string_match:
- prefix: "*"
allow_methods: GET, PUT, DELETE, POST, OPTIONS
allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout
max_age: "1728000"
expose_headers: custom-header-1,grpc-status,grpc-message
http_filters:
- name: envoy.filters.http.grpc_web
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
- name: envoy.filters.http.cors
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: echo_service
connect_timeout: 0.25s
type: logical_dns
# HTTP/2 support
typed_extension_protocol_options:
envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
"@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
explicit_http_config:
http2_protocol_options: {}
lb_policy: round_robin
load_assignment:
cluster_name: cluster_0
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 9090
+32 -366
View File
@@ -1,375 +1,41 @@
import { type Card, create_card, type CardNetcode } from "./Card";
import {
type Effect,
create_effect,
type EffectNetcode,
EffectType,
CardEffects,
} from "./Effect";
import { type Game, create_game, type GameNetcode } from "./Game";
import type { GameObjectNetcode } from "./GameObject";
import { type Player, create_player, type PlayerNetcode } from "./Player";
import { type Team, create_team, type TeamNetcode } from "./Team";
import { type Turn, create_turn } from "./Turn";
import { type Lobby, create_lobby, type LobbyNetcode } from "./Lobby";
import * as grpcWeb from "grpc-web"
import { SubscribeRequest, SubscribeResponse } from './proto/gameobject';
import { UpdaterClient } from "./proto/gameobject.client"
import { ServerStreamingCall } from "@protobuf-ts/runtime-rpc"
import { GrpcWebFetchTransport } from "@protobuf-ts/grpcweb-transport";
import { type Ref } from "vue";
class Updater {
static readonly INTERVAL = 500; // ms
static readonly MAX_STREAM_MESSAGES = 50;
let socket: WebSocket;
stream: ServerStreamingCall<SubscribeRequest, SubscribeResponse>;
export class GameObjectRegister {
readonly effects: Map<string, Effect>;
readonly cards: Map<string, Card>;
readonly teams: Map<string, Team>;
readonly players: Map<string, Player>;
readonly turns: Map<string, Turn>;
readonly games: Map<string, Game>;
context: "lobby" | "login" | "pregame" | "game" | "rules" = "login";
private readonly objects: Map<string, GameObjectNetcode>;
current_game: Ref<Game | null>;
lobby: Ref<Lobby | null>;
self: Ref<Player | null>;
zoomKeyPressed: Ref<boolean>
hoveredCard: Ref<number | undefined>
clientMouseX: Ref<number>
clientMouseY: Ref<number>
discordId: Ref<string>
constructor() {
this.effects = reactive(new Map());
this.cards = reactive(new Map());
this.teams = reactive(new Map());
this.players = reactive(new Map());
this.turns = reactive(new Map());
this.games = reactive(new Map());
this.objects = reactive(new Map());
this.current_game = ref(null);
this.lobby = ref(null);
this.self = ref(null);
this.zoomKeyPressed = ref(false);
this.hoveredCard = ref()
this.clientMouseX = ref(0)
this.clientMouseY = ref(0)
this.discordId = ref("")
}
update_object(obj: GameObjectNetcode) {
// console.log(obj);
// console.log(obj.uuid);
// console.log(this.objects.get(obj.uuid));
Object.assign(this.objects.get(obj.uuid) as GameNetcode, obj);
if (unref(this.current_game)?.uuid === obj.uuid) {
triggerRef(this.current_game);
} else if (unref(this.lobby)?.uuid === obj.uuid) {
triggerRef(this.lobby);
} else if (unref(this.self)?.uuid === obj.uuid) {
triggerRef(this.self);
} else if (unref(this.self)?.turn?.uuid === obj.uuid) {
triggerRef(this.self);
constructor(public updaterService: UpdaterClient, uuid: string) {
// Subscribe to server
this.stream = this.updaterService.subscribeCreations({ uuid })
//Handle server stream
this.stream.responses.onNext((a) => {
console.log(a)
})
this.stream.responses.onMessage((response: SubscribeResponse) => {
console.log(response.uuid)
});
this.stream.responses.onError((err) => {
console.error(err.message)
});
this.stream.responses.onComplete(() => {
console.log('stream end signal received');
});
}
}
createObject = {
effect: (data: EffectNetcode) => {
const effect = create_effect(data, this);
this.effects.set(data.uuid, effect);
this.objects.set(data.uuid, data);
},
card: (data: CardNetcode) => {
const card = create_card(data, this);
this.cards.set(data.uuid, card);
this.objects.set(data.uuid, card);
},
player: (data: PlayerNetcode) => {
const player = create_player(data, this);
this.players.set(data.uuid, player);
this.objects.set(data.uuid, player);
},
team: (data: TeamNetcode) => {
const team = create_team(data, this);
this.teams.set(data.uuid, team);
this.objects.set(data.uuid, team);
},
game: (data: GameNetcode) => {
const game = create_game(data, this);
this.games.set(data.uuid, game);
this.objects.set(data.uuid, game);
},
turn: (data: any) => {
const turn = create_turn(data, this);
this.turns.set(data.uuid, turn);
this.objects.set(data.uuid, turn);
},
lobby: (data: LobbyNetcode) => {
this.lobby.value = create_lobby(data, this);
this.objects.set(data.uuid, this.lobby.value);
},
} as { [id: string]: (data: any) => any };
setSelf = (uuid: string) => {
this.self.value = this.players.get(uuid) ?? null;
};
setDiscordId = (username: string) => {
this.discordId.value = username
}
setCurrentGame = (uuid: string) => {
this.current_game.value = this.games.get(uuid) ?? null;
};
}
const goStore = reactive(new GameObjectRegister());
export const setup_websocket = () =>
new Promise<void>((resolve, reject) => {
if (socket) {
return resolve();
}
const config = useRuntimeConfig();
const heron_session = useCookie("heron_session");
socket = new WebSocket(config.public.websocketEndpoint);
const transport = new GrpcWebFetchTransport({
baseUrl: "http://localhost:8080"
});
socket.onopen = function (e) {
if (socket.readyState == 1) {
resolve();
}
const updaterService = new UpdaterClient(transport);
console.log("[open] Connection established");
};
socket.onclose = function (event) {
if (event.wasClean) {
console.warn(
`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`
);
} else {
// e.g. server process killed or network down
// event.code is usually 1006 in this case
console.error("[close] Connection died");
}
};
socket.onerror = function (error) {
console.error(error);
};
socket.onmessage = function (event) {
const data = JSON.parse(event.data);
if (data.type == "create" && data.data_type == "object") {
if (!(data.data.object_type in goStore.createObject)) {
throw new Error(
`Object ${data.data.object_type} couldn't be created`
);
}
goStore.createObject[data.data.object_type](data.data);
} else if (data.type == "update" && data.data_type == "object") {
goStore.update_object(data.data);
} else if (data.type === "context") {
goStore.context = data.data;
// console.log(data.data);
} else if (data.type === "set") {
if (data.data_type == "self") {
goStore.setSelf(data.data);
} else if (data.data_type == "current_game") {
goStore.setCurrentGame(data.data);
} else if (data.data_type == "session_cookie") {
heron_session.value = data.data;
} else if (data.data_type == "self_discord_id") {
goStore.setDiscordId(data.data)
}
} else {
// console.log(data.type, data.data_type, data.data);
}
};
});
export async function heron_cookie_login(cookie: string) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "cookie_login",
data_type: "cookie",
data: cookie,
})
);
}
export async function oauth2_register_discord(code: string) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "discord_login",
data_type: "code",
data: code,
})
);
}
export async function register(username: string) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "register",
data_type: "username",
data: username,
})
);
}
export async function login(username: string) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "login",
data_type: "username",
data: username,
})
);
}
export async function setReady(value: boolean) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "ready",
data_type: "ready_state",
data: value,
})
);
}
export async function buy(card: Card) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "action",
data_type: "buy",
data: card.uuid,
})
);
}
export async function endTurn() {
await setup_websocket();
socket.send(
JSON.stringify({
type: "action",
data_type: "end_turn",
data: true,
})
);
}
export function playAllCards(cards: Card[]) {
cards.forEach((c: any) => {
playCard(c);
});
}
export async function playCard(card: Card) {
// console.log(card.uuid);
await setup_websocket();
socket.send(
JSON.stringify({
type: "action",
data_type: "play_card",
data: card.uuid,
})
);
}
export async function lockCard(card: Card) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "action",
data_type: "lock_card",
data: card.uuid,
})
);
}
export async function useEffect(
effect: Effect,
target?: Effect | Card | Player | Team
) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "action",
data_type: "use_effect",
data: { effect_id: effect.uuid, target: target?.uuid },
})
);
}
export async function discard(card: Card) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "action",
data_type: "discard",
data: card.uuid,
})
);
}
h;
export async function heal() {
await setup_websocket();
socket.send(
JSON.stringify({
type: "action",
data_type: "heal",
data: 1,
})
);
}
export async function damage_team(target: Team) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "action",
data_type: "damage_team",
data: target.uuid,
})
);
}
export async function damage_champion(target: Card) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "action",
data_type: "damage_champion",
data: target.uuid,
})
);
}
export async function netcode_create_game() {
await setup_websocket();
socket.send(
JSON.stringify({
type: "create",
data_type: "game",
data: "bite",
})
);
}
export async function join_game(game_uuid: string) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "join",
data_type: "game",
data: game_uuid,
})
);
}
export default goStore;
export function subscribeObject(uuid: string) {
return new Updater(updaterService, uuid)
}
+375
View File
@@ -0,0 +1,375 @@
import { type Card, create_card, type CardNetcode } from "./Card";
import {
type Effect,
create_effect,
type EffectNetcode,
EffectType,
CardEffects,
} from "./Effect";
import { type Game, create_game, type GameNetcode } from "./Game";
import type { GameObjectNetcode } from "./GameObject";
import { type Player, create_player, type PlayerNetcode } from "./Player";
import { type Team, create_team, type TeamNetcode } from "./Team";
import { type Turn, create_turn } from "./Turn";
import { type Lobby, create_lobby, type LobbyNetcode } from "./Lobby";
import { type Ref } from "vue";
let socket: WebSocket;
export class GameObjectRegister {
readonly effects: Map<string, Effect>;
readonly cards: Map<string, Card>;
readonly teams: Map<string, Team>;
readonly players: Map<string, Player>;
readonly turns: Map<string, Turn>;
readonly games: Map<string, Game>;
context: "lobby" | "login" | "pregame" | "game" | "rules" = "login";
private readonly objects: Map<string, GameObjectNetcode>;
current_game: Ref<Game | null>;
lobby: Ref<Lobby | null>;
self: Ref<Player | null>;
zoomKeyPressed: Ref<boolean>
hoveredCard: Ref<number | undefined>
clientMouseX: Ref<number>
clientMouseY: Ref<number>
discordId: Ref<string>
constructor() {
this.effects = reactive(new Map());
this.cards = reactive(new Map());
this.teams = reactive(new Map());
this.players = reactive(new Map());
this.turns = reactive(new Map());
this.games = reactive(new Map());
this.objects = reactive(new Map());
this.current_game = ref(null);
this.lobby = ref(null);
this.self = ref(null);
this.zoomKeyPressed = ref(false);
this.hoveredCard = ref()
this.clientMouseX = ref(0)
this.clientMouseY = ref(0)
this.discordId = ref("")
}
update_object(obj: GameObjectNetcode) {
// console.log(obj);
// console.log(obj.uuid);
// console.log(this.objects.get(obj.uuid));
Object.assign(this.objects.get(obj.uuid) as GameNetcode, obj);
if (unref(this.current_game)?.uuid === obj.uuid) {
triggerRef(this.current_game);
} else if (unref(this.lobby)?.uuid === obj.uuid) {
triggerRef(this.lobby);
} else if (unref(this.self)?.uuid === obj.uuid) {
triggerRef(this.self);
} else if (unref(this.self)?.turn?.uuid === obj.uuid) {
triggerRef(this.self);
}
}
createObject = {
effect: (data: EffectNetcode) => {
const effect = create_effect(data, this);
this.effects.set(data.uuid, effect);
this.objects.set(data.uuid, data);
},
card: (data: CardNetcode) => {
const card = create_card(data, this);
this.cards.set(data.uuid, card);
this.objects.set(data.uuid, card);
},
player: (data: PlayerNetcode) => {
const player = create_player(data, this);
this.players.set(data.uuid, player);
this.objects.set(data.uuid, player);
},
team: (data: TeamNetcode) => {
const team = create_team(data, this);
this.teams.set(data.uuid, team);
this.objects.set(data.uuid, team);
},
game: (data: GameNetcode) => {
const game = create_game(data, this);
this.games.set(data.uuid, game);
this.objects.set(data.uuid, game);
},
turn: (data: any) => {
const turn = create_turn(data, this);
this.turns.set(data.uuid, turn);
this.objects.set(data.uuid, turn);
},
lobby: (data: LobbyNetcode) => {
this.lobby.value = create_lobby(data, this);
this.objects.set(data.uuid, this.lobby.value);
},
} as { [id: string]: (data: any) => any };
setSelf = (uuid: string) => {
this.self.value = this.players.get(uuid) ?? null;
};
setDiscordId = (username: string) => {
this.discordId.value = username
}
setCurrentGame = (uuid: string) => {
this.current_game.value = this.games.get(uuid) ?? null;
};
}
const goStore = reactive(new GameObjectRegister());
export const setup_websocket = () =>
new Promise<void>((resolve, reject) => {
if (socket) {
return resolve();
}
const config = useRuntimeConfig();
const heron_session = useCookie("heron_session");
socket = new WebSocket(config.public.websocketEndpoint);
socket.onopen = function (e) {
if (socket.readyState == 1) {
resolve();
}
console.log("[open] Connection established");
};
socket.onclose = function (event) {
if (event.wasClean) {
console.warn(
`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`
);
} else {
// e.g. server process killed or network down
// event.code is usually 1006 in this case
console.error("[close] Connection died");
}
};
socket.onerror = function (error) {
console.error(error);
};
socket.onmessage = function (event) {
const data = JSON.parse(event.data);
if (data.type == "create" && data.data_type == "object") {
if (!(data.data.object_type in goStore.createObject)) {
throw new Error(
`Object ${data.data.object_type} couldn't be created`
);
}
goStore.createObject[data.data.object_type](data.data);
} else if (data.type == "update" && data.data_type == "object") {
goStore.update_object(data.data);
} else if (data.type === "context") {
goStore.context = data.data;
// console.log(data.data);
} else if (data.type === "set") {
if (data.data_type == "self") {
goStore.setSelf(data.data);
} else if (data.data_type == "current_game") {
goStore.setCurrentGame(data.data);
} else if (data.data_type == "session_cookie") {
heron_session.value = data.data;
} else if (data.data_type == "self_discord_id") {
goStore.setDiscordId(data.data)
}
} else {
// console.log(data.type, data.data_type, data.data);
}
};
});
export async function heron_cookie_login(cookie: string) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "cookie_login",
data_type: "cookie",
data: cookie,
})
);
}
export async function oauth2_register_discord(code: string) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "discord_login",
data_type: "code",
data: code,
})
);
}
export async function register(username: string) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "register",
data_type: "username",
data: username,
})
);
}
export async function login(username: string) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "login",
data_type: "username",
data: username,
})
);
}
export async function setReady(value: boolean) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "ready",
data_type: "ready_state",
data: value,
})
);
}
export async function buy(card: Card) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "action",
data_type: "buy",
data: card.uuid,
})
);
}
export async function endTurn() {
await setup_websocket();
socket.send(
JSON.stringify({
type: "action",
data_type: "end_turn",
data: true,
})
);
}
export function playAllCards(cards: Card[]) {
cards.forEach((c: any) => {
playCard(c);
});
}
export async function playCard(card: Card) {
// console.log(card.uuid);
await setup_websocket();
socket.send(
JSON.stringify({
type: "action",
data_type: "play_card",
data: card.uuid,
})
);
}
export async function lockCard(card: Card) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "action",
data_type: "lock_card",
data: card.uuid,
})
);
}
export async function useEffect(
effect: Effect,
target?: Effect | Card | Player | Team
) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "action",
data_type: "use_effect",
data: { effect_id: effect.uuid, target: target?.uuid },
})
);
}
export async function discard(card: Card) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "action",
data_type: "discard",
data: card.uuid,
})
);
}
h;
export async function heal() {
await setup_websocket();
socket.send(
JSON.stringify({
type: "action",
data_type: "heal",
data: 1,
})
);
}
export async function damage_team(target: Team) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "action",
data_type: "damage_team",
data: target.uuid,
})
);
}
export async function damage_champion(target: Card) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "action",
data_type: "damage_champion",
data: target.uuid,
})
);
}
export async function netcode_create_game() {
await setup_websocket();
socket.send(
JSON.stringify({
type: "create",
data_type: "game",
data: "bite",
})
);
}
export async function join_game(game_uuid: string) {
await setup_websocket();
socket.send(
JSON.stringify({
type: "join",
data_type: "game",
data: game_uuid,
})
);
}
export default goStore;
+48
View File
@@ -0,0 +1,48 @@
// @generated by protobuf-ts 2.9.4 with parameter long_type_string
// @generated from protobuf file "gameobject.proto" (package "heron", syntax proto3)
// tslint:disable
import type { RpcTransport } from "@protobuf-ts/runtime-rpc";
import type { ServiceInfo } from "@protobuf-ts/runtime-rpc";
import { Updater } from "./gameobject";
import { stackIntercept } from "@protobuf-ts/runtime-rpc";
import type { SubscribeResponse } from "./gameobject";
import type { SubscribeRequest } from "./gameobject";
import type { ServerStreamingCall } from "@protobuf-ts/runtime-rpc";
import type { RpcOptions } from "@protobuf-ts/runtime-rpc";
/**
* @generated from protobuf service heron.Updater
*/
export interface IUpdaterClient {
/**
* @generated from protobuf rpc: SubscribeGameObject(heron.SubscribeRequest) returns (stream heron.SubscribeResponse);
*/
subscribeGameObject(input: SubscribeRequest, options?: RpcOptions): ServerStreamingCall<SubscribeRequest, SubscribeResponse>;
/**
* @generated from protobuf rpc: SubscribeCreations(heron.SubscribeRequest) returns (stream heron.SubscribeResponse);
*/
subscribeCreations(input: SubscribeRequest, options?: RpcOptions): ServerStreamingCall<SubscribeRequest, SubscribeResponse>;
}
/**
* @generated from protobuf service heron.Updater
*/
export class UpdaterClient implements IUpdaterClient, ServiceInfo {
typeName = Updater.typeName;
methods = Updater.methods;
options = Updater.options;
constructor(private readonly _transport: RpcTransport) {
}
/**
* @generated from protobuf rpc: SubscribeGameObject(heron.SubscribeRequest) returns (stream heron.SubscribeResponse);
*/
subscribeGameObject(input: SubscribeRequest, options?: RpcOptions): ServerStreamingCall<SubscribeRequest, SubscribeResponse> {
const method = this.methods[0], opt = this._transport.mergeOptions(options);
return stackIntercept<SubscribeRequest, SubscribeResponse>("serverStreaming", this._transport, method, opt, input);
}
/**
* @generated from protobuf rpc: SubscribeCreations(heron.SubscribeRequest) returns (stream heron.SubscribeResponse);
*/
subscribeCreations(input: SubscribeRequest, options?: RpcOptions): ServerStreamingCall<SubscribeRequest, SubscribeResponse> {
const method = this.methods[1], opt = this._transport.mergeOptions(options);
return stackIntercept<SubscribeRequest, SubscribeResponse>("serverStreaming", this._transport, method, opt, input);
}
}
+144
View File
@@ -0,0 +1,144 @@
// @generated by protobuf-ts 2.9.4 with parameter long_type_string
// @generated from protobuf file "gameobject.proto" (package "heron", syntax proto3)
// tslint:disable
import { ServiceType } from "@protobuf-ts/runtime-rpc";
import type { BinaryWriteOptions } from "@protobuf-ts/runtime";
import type { IBinaryWriter } from "@protobuf-ts/runtime";
import { WireType } from "@protobuf-ts/runtime";
import type { BinaryReadOptions } from "@protobuf-ts/runtime";
import type { IBinaryReader } from "@protobuf-ts/runtime";
import { UnknownFieldHandler } from "@protobuf-ts/runtime";
import type { PartialMessage } from "@protobuf-ts/runtime";
import { reflectionMergePartial } from "@protobuf-ts/runtime";
import { MessageType } from "@protobuf-ts/runtime";
/**
* @generated from protobuf message heron.SubscribeRequest
*/
export interface SubscribeRequest {
/**
* @generated from protobuf field: string uuid = 1;
*/
uuid: string;
}
/**
* @generated from protobuf message heron.SubscribeResponse
*/
export interface SubscribeResponse {
/**
* @generated from protobuf field: string uuid = 1;
*/
uuid: string;
/**
* @generated from protobuf field: string version = 2;
*/
version: string;
}
// @generated message type with reflection information, may provide speed optimized methods
class SubscribeRequest$Type extends MessageType<SubscribeRequest> {
constructor() {
super("heron.SubscribeRequest", [
{ no: 1, name: "uuid", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
]);
}
create(value?: PartialMessage<SubscribeRequest>): SubscribeRequest {
const message = globalThis.Object.create((this.messagePrototype!));
message.uuid = "";
if (value !== undefined)
reflectionMergePartial<SubscribeRequest>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: SubscribeRequest): SubscribeRequest {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* string uuid */ 1:
message.uuid = reader.string();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: SubscribeRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* string uuid = 1; */
if (message.uuid !== "")
writer.tag(1, WireType.LengthDelimited).string(message.uuid);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message heron.SubscribeRequest
*/
export const SubscribeRequest = new SubscribeRequest$Type();
// @generated message type with reflection information, may provide speed optimized methods
class SubscribeResponse$Type extends MessageType<SubscribeResponse> {
constructor() {
super("heron.SubscribeResponse", [
{ no: 1, name: "uuid", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 2, name: "version", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
]);
}
create(value?: PartialMessage<SubscribeResponse>): SubscribeResponse {
const message = globalThis.Object.create((this.messagePrototype!));
message.uuid = "";
message.version = "";
if (value !== undefined)
reflectionMergePartial<SubscribeResponse>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: SubscribeResponse): SubscribeResponse {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* string uuid */ 1:
message.uuid = reader.string();
break;
case /* string version */ 2:
message.version = reader.string();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: SubscribeResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* string uuid = 1; */
if (message.uuid !== "")
writer.tag(1, WireType.LengthDelimited).string(message.uuid);
/* string version = 2; */
if (message.version !== "")
writer.tag(2, WireType.LengthDelimited).string(message.version);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message heron.SubscribeResponse
*/
export const SubscribeResponse = new SubscribeResponse$Type();
/**
* @generated ServiceType for protobuf service heron.Updater
*/
export const Updater = new ServiceType("heron.Updater", [
{ name: "SubscribeGameObject", serverStreaming: true, options: {}, I: SubscribeRequest, O: SubscribeResponse },
{ name: "SubscribeCreations", serverStreaming: true, options: {}, I: SubscribeRequest, O: SubscribeResponse }
]);
+1422
View File
File diff suppressed because it is too large Load Diff
+12 -1
View File
@@ -3,17 +3,28 @@
"private": true,
"type": "module",
"scripts": {
"build": "nuxt build",
"build-protobuf": "npx protoc --ts_out netcode/proto --ts_opt long_type_string --proto_path proto proto/gameobject.proto",
"build": "npm run build-protobuf && nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare"
},
"dependencies": {
"@grpc/grpc-js": "^1.10.8",
"@pinia/nuxt": "^0.5.1",
"@protobuf-ts/grpcweb-transport": "^2.9.4",
"@protobuf-ts/plugin": "^2.9.4",
"@protobuf-ts/runtime": "^2.9.4",
"google-protobuf": "^3.21.2",
"grpc-web": "^1.5.0",
"nuxt": "^3.11.2",
"pinia": "^2.1.7",
"protoc-gen-js": "^3.21.2",
"vue": "^3.4.21",
"vue-router": "^4.3.0"
},
"devDependencies": {
"@types/google-protobuf": "^3.15.12"
}
}
+9 -7
View File
@@ -1,24 +1,26 @@
<script setup lang="ts">
import goStore, { setReady } from "@/netcode";
// import goStore, { setReady } from "@/netcode";
import { subscribeObject } from '~/netcode';
subscribeObject("0")
</script>
<template>
<div class="root_page_div">
<div id="game_status">
<!-- <div id="game_status">
<template v-if="goStore.self && !goStore.current_game?.started">
<input @click.prevent="setReady(($event.target as HTMLInputElement).checked)" type="checkbox" id="ready"
:checked="goStore.self?.ready" />
<label for="ready">Ready</label>
</template>
</div>
<LoginView v-if="goStore.context === 'login'"></LoginView>
<GameBoard v-if="goStore.context != 'lobby' && goStore.context != 'login'"></GameBoard>
<LobbyView v-if="goStore.context == 'lobby'"></LobbyView>
<RulesDisplay v-if="goStore.context == 'rules'"></RulesDisplay>
</div>
<LoginView v-if="goStore.context === 'login'"></LoginView>
<GameBoard v-if="goStore.context != 'lobby' && goStore.context != 'login'"></GameBoard>
<LobbyView v-if="goStore.context == 'lobby'"></LobbyView>
<RulesDisplay v-if="goStore.context == 'rules'"></RulesDisplay> -->
</div>
</template>