hytopia 0.1.46 → 0.1.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,91 @@
1
+ <html>
2
+ <body>
3
+ <!--
4
+ We MUST always import the Hytopia UI library!
5
+ Importing this library also imports the hytopia global.
6
+
7
+ If we were using React, or Svelte, or another framework, we
8
+ can install the HYTPIA UI library as a package and import it
9
+ with `npm install hytopia-ui` and then import it as
10
+ `import hytopia from 'hytopia-ui';`
11
+ -->
12
+ <script src="https://unpkg.com/hytopia-ui@latest/dist/index.umd.js"></script>
13
+
14
+ <script>
15
+ document.addEventListener('DOMContentLoaded', () => {
16
+ // Handle received data from server
17
+ hytopia.ui.onData = data => {
18
+ if (data.type === 'playerList') {
19
+ const { list } = data;
20
+
21
+ // Update player count
22
+ document.getElementById('player-count').textContent = `Players Connected: ${list.length}`;
23
+
24
+ // Clear and rebuild player list
25
+ const playerListElement = document.getElementById('player-list');
26
+ playerListElement.innerHTML = '';
27
+
28
+ // Add each player to the list
29
+ list.forEach(player => {
30
+ const pos = player.position;
31
+ const playerRow = document.createElement('div');
32
+ playerRow.className = 'player-row';
33
+ playerRow.textContent = `${player.username}: x:${pos.x.toFixed(1)}, y:${pos.y.toFixed(1)}, z:${pos.z.toFixed(1)}`;
34
+ playerListElement.appendChild(playerRow);
35
+ });
36
+ }
37
+ }
38
+
39
+ // Send data to server on teleport btn press
40
+ document.getElementById('teleport-btn').addEventListener('click', () => {
41
+ // We can send any arbitrary object to the server. We as the developer define
42
+ // whatever schema we want to use for data between client and server.
43
+ // For now we'll just use a "type" property we made up so the server knows
44
+ // what to do with the data.
45
+ hytopia.ui.sendData({ type: 'teleport' });
46
+ });
47
+ });
48
+ </script>
49
+
50
+ <div id="player-panel">
51
+ <div id="player-count">Players Connected: 0</div>
52
+ <div id="player-list"></div>
53
+ <button id="teleport-btn">Click to Teleport!</button>
54
+ </div>
55
+
56
+ <style>
57
+ #player-panel {
58
+ position: absolute;
59
+ right: 20px;
60
+ top: 20px;
61
+ background-color: rgba(0, 0, 0, 0.7);
62
+ color: white;
63
+ padding: 15px;
64
+ border-radius: 8px;
65
+ min-width: 200px;
66
+ font-family: Arial, sans-serif;
67
+ letter-spacing: 0.5px;
68
+ }
69
+ .player-row {
70
+ margin: 8px 0;
71
+ }
72
+ #teleport-btn {
73
+ width: 100%;
74
+ padding: 8px;
75
+ margin-top: 15px;
76
+ background-color: #4CAF50;
77
+ color: white;
78
+ border: none;
79
+ border-radius: 4px;
80
+ cursor: pointer;
81
+ font-family: Arial, sans-serif;
82
+ font-weight: bold;
83
+ text-transform: uppercase;
84
+ letter-spacing: 1px;
85
+ }
86
+ #teleport-btn:hover {
87
+ background-color: #45a049;
88
+ }
89
+ </style>
90
+ </body>
91
+ </html>
@@ -0,0 +1,91 @@
1
+ import {
2
+ startServer,
3
+ Audio,
4
+ Player,
5
+ PlayerEntity,
6
+ PlayerUI,
7
+ } from 'hytopia';
8
+
9
+ import worldMap from './assets/map.json';
10
+
11
+ // Simple map for player -> singular controlled entity
12
+ const playerEntityMap = new Map<Player, PlayerEntity>();
13
+
14
+ startServer(world => {
15
+ world.loadMap(worldMap);
16
+
17
+ world.onPlayerJoin = player => {
18
+ // Load the UI for the player.
19
+ // This is loaded directly into a sandboxed iframe
20
+ // overlaying the game. As long as it's an HTML file,
21
+ // it can be loaded. You can bundle React, Svelte, or
22
+ // any other framework into the UI you want to serve,
23
+ // or just use plain HTML like in this example.
24
+ player.ui.load('ui/index.html');
25
+
26
+ const playerEntity = new PlayerEntity({
27
+ player,
28
+ name: 'Player',
29
+ modelUri: 'models/player.gltf',
30
+ modelLoopedAnimations: [ 'idle' ],
31
+ modelScale: 0.5,
32
+ });
33
+
34
+ playerEntity.spawn(world, { x: 0, y: 10, z: 0 });
35
+
36
+ // Set the player entity on our map for when
37
+ // we do player list updates.
38
+ playerEntityMap.set(player, playerEntity);
39
+
40
+ // Handle data sent from player to server by client UI interactions we define.
41
+ // See the ui/index.html file for the UI code that sends the data.
42
+ player.ui.onData = (playerUI: PlayerUI, data: Record<string, any>) => {
43
+ if (data.type === 'teleport') {
44
+ const randomX = Math.random() * 40 - 20; // Random between -20 and 20
45
+ const randomY = Math.random() * 13 + 2; // Random between 2 and 15
46
+ const randomZ = Math.random() * 40 - 20; // Random between -20 and 20
47
+
48
+ playerEntity.setTranslation({ x: randomX, y: randomY, z: randomZ });
49
+ }
50
+ };
51
+ };
52
+
53
+ world.onPlayerLeave = player => {
54
+ world.entityManager.getAllPlayerEntities(player).forEach(entity => entity.despawn());
55
+ // Remove the player entity from our map for our list.
56
+ playerEntityMap.delete(player);
57
+ };
58
+
59
+ // Update the player list every 1 second, no need to send too frequently.
60
+ // We want to balance not sending too much UI data too frequently, because
61
+ // it is currently sent over the same connection as game packets and will
62
+ // compete for critical game packet bandwidth on slower player connections.
63
+ setInterval(updatePlayerList, 1000);
64
+
65
+ new Audio({
66
+ uri: 'audio/music/overworld.mp3',
67
+ loop: true,
68
+ volume: 0.2,
69
+ }).play(world);
70
+ });
71
+
72
+ function updatePlayerList() {
73
+ // Create a list of all connected players and their positions
74
+ const playerListData = Array.from(playerEntityMap).map(([ player, entity ]) => {
75
+ // For each player, return their username and current position
76
+ return {
77
+ username: player.username,
78
+ position: entity.getTranslation(), // Gets x,y,z coordinate
79
+ };
80
+ });
81
+
82
+ // Send the updated player list to every connected player's UI
83
+ for (const [ player ] of playerEntityMap) {
84
+ player.ui.sendData({
85
+ type: 'playerList', // Message type for UI to handle
86
+ list: playerListData, // List of all players and positions
87
+ });
88
+ }
89
+ }
90
+
91
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hytopia",
3
- "version": "0.1.46",
3
+ "version": "0.1.47",
4
4
  "description": "The HYTOPIA SDK makes it easy for developers to create massively multiplayer games using JavaScript or TypeScript.",
5
5
  "main": "server.js",
6
6
  "bin": {
package/server.api.json CHANGED
@@ -13461,6 +13461,37 @@
13461
13461
  "isProtected": false,
13462
13462
  "isAbstract": false
13463
13463
  },
13464
+ {
13465
+ "kind": "Property",
13466
+ "canonicalReference": "server!Player#ui:member",
13467
+ "docComment": "/**\n * The UI for the player.\n */\n",
13468
+ "excerptTokens": [
13469
+ {
13470
+ "kind": "Content",
13471
+ "text": "readonly ui: "
13472
+ },
13473
+ {
13474
+ "kind": "Reference",
13475
+ "text": "PlayerUI",
13476
+ "canonicalReference": "server!PlayerUI:class"
13477
+ },
13478
+ {
13479
+ "kind": "Content",
13480
+ "text": ";"
13481
+ }
13482
+ ],
13483
+ "isReadonly": true,
13484
+ "isOptional": false,
13485
+ "releaseTag": "Public",
13486
+ "name": "ui",
13487
+ "propertyTypeTokenRange": {
13488
+ "startIndex": 1,
13489
+ "endIndex": 2
13490
+ },
13491
+ "isStatic": false,
13492
+ "isProtected": false,
13493
+ "isAbstract": false
13494
+ },
13464
13495
  {
13465
13496
  "kind": "Property",
13466
13497
  "canonicalReference": "server!Player#username:member",
@@ -16719,6 +16750,411 @@
16719
16750
  "endIndex": 2
16720
16751
  }
16721
16752
  },
16753
+ {
16754
+ "kind": "Class",
16755
+ "canonicalReference": "server!PlayerUI:class",
16756
+ "docComment": "/**\n * The UI for a player.\n *\n * @remarks\n *\n * UI allows control of all in-game overlays a player sees. UI is controlled by HTML, CSS and JavaScript files you provide in your `assets` folder.\n *\n * The constructor for this class is marked as internal. Third-party code should not call the constructor directly or create subclasses that extend the `PlayerUI` class.\n *\n * @public\n */\n",
16757
+ "excerptTokens": [
16758
+ {
16759
+ "kind": "Content",
16760
+ "text": "export default class PlayerUI "
16761
+ }
16762
+ ],
16763
+ "fileUrlPath": "src/networking/players/PlayerUI.ts",
16764
+ "releaseTag": "Public",
16765
+ "isAbstract": false,
16766
+ "name": "PlayerUI",
16767
+ "preserveMemberOrder": false,
16768
+ "members": [
16769
+ {
16770
+ "kind": "Method",
16771
+ "canonicalReference": "server!PlayerUI#load:member(1)",
16772
+ "docComment": "/**\n * Loads client UI for the player.\n *\n * @param htmlUri - The ui html uri to load.\n */\n",
16773
+ "excerptTokens": [
16774
+ {
16775
+ "kind": "Content",
16776
+ "text": "load(htmlUri: "
16777
+ },
16778
+ {
16779
+ "kind": "Content",
16780
+ "text": "string"
16781
+ },
16782
+ {
16783
+ "kind": "Content",
16784
+ "text": "): "
16785
+ },
16786
+ {
16787
+ "kind": "Content",
16788
+ "text": "void"
16789
+ },
16790
+ {
16791
+ "kind": "Content",
16792
+ "text": ";"
16793
+ }
16794
+ ],
16795
+ "isStatic": false,
16796
+ "returnTypeTokenRange": {
16797
+ "startIndex": 3,
16798
+ "endIndex": 4
16799
+ },
16800
+ "releaseTag": "Public",
16801
+ "isProtected": false,
16802
+ "overloadIndex": 1,
16803
+ "parameters": [
16804
+ {
16805
+ "parameterName": "htmlUri",
16806
+ "parameterTypeTokenRange": {
16807
+ "startIndex": 1,
16808
+ "endIndex": 2
16809
+ },
16810
+ "isOptional": false
16811
+ }
16812
+ ],
16813
+ "isOptional": false,
16814
+ "isAbstract": false,
16815
+ "name": "load"
16816
+ },
16817
+ {
16818
+ "kind": "Property",
16819
+ "canonicalReference": "server!PlayerUI#onData:member",
16820
+ "docComment": "/**\n * A function that is called when the player's client UI sends data to the server.\n *\n * @remarks\n *\n * Data sent is an object of any shape defined by you and controlled with invocations of `hytopia.ui.sendData()` from your loaded client UI files.\n *\n * @param playerUI - The PlayerUI instance that the data is from.\n *\n * @param data - The data sent from the client UI.\n */\n",
16821
+ "excerptTokens": [
16822
+ {
16823
+ "kind": "Content",
16824
+ "text": "onData?: "
16825
+ },
16826
+ {
16827
+ "kind": "Content",
16828
+ "text": "(playerUI: "
16829
+ },
16830
+ {
16831
+ "kind": "Reference",
16832
+ "text": "PlayerUI",
16833
+ "canonicalReference": "server!PlayerUI:class"
16834
+ },
16835
+ {
16836
+ "kind": "Content",
16837
+ "text": ", data: object) => void"
16838
+ },
16839
+ {
16840
+ "kind": "Content",
16841
+ "text": ";"
16842
+ }
16843
+ ],
16844
+ "isReadonly": false,
16845
+ "isOptional": true,
16846
+ "releaseTag": "Public",
16847
+ "name": "onData",
16848
+ "propertyTypeTokenRange": {
16849
+ "startIndex": 1,
16850
+ "endIndex": 4
16851
+ },
16852
+ "isStatic": false,
16853
+ "isProtected": false,
16854
+ "isAbstract": false
16855
+ },
16856
+ {
16857
+ "kind": "Property",
16858
+ "canonicalReference": "server!PlayerUI#player:member",
16859
+ "docComment": "/**\n * The player that the UI belongs to.\n *\n * @readonly\n */\n",
16860
+ "excerptTokens": [
16861
+ {
16862
+ "kind": "Content",
16863
+ "text": "readonly player: "
16864
+ },
16865
+ {
16866
+ "kind": "Reference",
16867
+ "text": "Player",
16868
+ "canonicalReference": "server!Player:class"
16869
+ },
16870
+ {
16871
+ "kind": "Content",
16872
+ "text": ";"
16873
+ }
16874
+ ],
16875
+ "isReadonly": true,
16876
+ "isOptional": false,
16877
+ "releaseTag": "Public",
16878
+ "name": "player",
16879
+ "propertyTypeTokenRange": {
16880
+ "startIndex": 1,
16881
+ "endIndex": 2
16882
+ },
16883
+ "isStatic": false,
16884
+ "isProtected": false,
16885
+ "isAbstract": false
16886
+ },
16887
+ {
16888
+ "kind": "Method",
16889
+ "canonicalReference": "server!PlayerUI#sendData:member(1)",
16890
+ "docComment": "/**\n * Sends data to the player's client UI.\n *\n * @param data - The data to send to the client UI.\n */\n",
16891
+ "excerptTokens": [
16892
+ {
16893
+ "kind": "Content",
16894
+ "text": "sendData(data: "
16895
+ },
16896
+ {
16897
+ "kind": "Content",
16898
+ "text": "object"
16899
+ },
16900
+ {
16901
+ "kind": "Content",
16902
+ "text": "): "
16903
+ },
16904
+ {
16905
+ "kind": "Content",
16906
+ "text": "void"
16907
+ },
16908
+ {
16909
+ "kind": "Content",
16910
+ "text": ";"
16911
+ }
16912
+ ],
16913
+ "isStatic": false,
16914
+ "returnTypeTokenRange": {
16915
+ "startIndex": 3,
16916
+ "endIndex": 4
16917
+ },
16918
+ "releaseTag": "Public",
16919
+ "isProtected": false,
16920
+ "overloadIndex": 1,
16921
+ "parameters": [
16922
+ {
16923
+ "parameterName": "data",
16924
+ "parameterTypeTokenRange": {
16925
+ "startIndex": 1,
16926
+ "endIndex": 2
16927
+ },
16928
+ "isOptional": false
16929
+ }
16930
+ ],
16931
+ "isOptional": false,
16932
+ "isAbstract": false,
16933
+ "name": "sendData"
16934
+ }
16935
+ ],
16936
+ "implementsTokenRanges": []
16937
+ },
16938
+ {
16939
+ "kind": "Namespace",
16940
+ "canonicalReference": "server!PlayerUIEventPayload:namespace",
16941
+ "docComment": "/**\n * Payloads for events a PlayerUI instance can emit.\n *\n * @public\n */\n",
16942
+ "excerptTokens": [
16943
+ {
16944
+ "kind": "Content",
16945
+ "text": "export declare namespace PlayerUIEventPayload "
16946
+ }
16947
+ ],
16948
+ "fileUrlPath": "src/networking/players/PlayerUI.ts",
16949
+ "releaseTag": "Public",
16950
+ "name": "PlayerUIEventPayload",
16951
+ "preserveMemberOrder": false,
16952
+ "members": [
16953
+ {
16954
+ "kind": "Interface",
16955
+ "canonicalReference": "server!PlayerUIEventPayload.Load:interface",
16956
+ "docComment": "",
16957
+ "excerptTokens": [
16958
+ {
16959
+ "kind": "Content",
16960
+ "text": "interface Load "
16961
+ }
16962
+ ],
16963
+ "releaseTag": "Public",
16964
+ "name": "Load",
16965
+ "preserveMemberOrder": false,
16966
+ "members": [
16967
+ {
16968
+ "kind": "PropertySignature",
16969
+ "canonicalReference": "server!PlayerUIEventPayload.Load#htmlUri:member",
16970
+ "docComment": "",
16971
+ "excerptTokens": [
16972
+ {
16973
+ "kind": "Content",
16974
+ "text": "htmlUri: "
16975
+ },
16976
+ {
16977
+ "kind": "Content",
16978
+ "text": "string"
16979
+ },
16980
+ {
16981
+ "kind": "Content",
16982
+ "text": ";"
16983
+ }
16984
+ ],
16985
+ "isReadonly": false,
16986
+ "isOptional": false,
16987
+ "releaseTag": "Public",
16988
+ "name": "htmlUri",
16989
+ "propertyTypeTokenRange": {
16990
+ "startIndex": 1,
16991
+ "endIndex": 2
16992
+ }
16993
+ },
16994
+ {
16995
+ "kind": "PropertySignature",
16996
+ "canonicalReference": "server!PlayerUIEventPayload.Load#playerUI:member",
16997
+ "docComment": "",
16998
+ "excerptTokens": [
16999
+ {
17000
+ "kind": "Content",
17001
+ "text": "playerUI: "
17002
+ },
17003
+ {
17004
+ "kind": "Reference",
17005
+ "text": "PlayerUI",
17006
+ "canonicalReference": "server!PlayerUI:class"
17007
+ },
17008
+ {
17009
+ "kind": "Content",
17010
+ "text": ";"
17011
+ }
17012
+ ],
17013
+ "isReadonly": false,
17014
+ "isOptional": false,
17015
+ "releaseTag": "Public",
17016
+ "name": "playerUI",
17017
+ "propertyTypeTokenRange": {
17018
+ "startIndex": 1,
17019
+ "endIndex": 2
17020
+ }
17021
+ }
17022
+ ],
17023
+ "extendsTokenRanges": []
17024
+ },
17025
+ {
17026
+ "kind": "Interface",
17027
+ "canonicalReference": "server!PlayerUIEventPayload.SendData:interface",
17028
+ "docComment": "",
17029
+ "excerptTokens": [
17030
+ {
17031
+ "kind": "Content",
17032
+ "text": "interface SendData "
17033
+ }
17034
+ ],
17035
+ "releaseTag": "Public",
17036
+ "name": "SendData",
17037
+ "preserveMemberOrder": false,
17038
+ "members": [
17039
+ {
17040
+ "kind": "PropertySignature",
17041
+ "canonicalReference": "server!PlayerUIEventPayload.SendData#data:member",
17042
+ "docComment": "",
17043
+ "excerptTokens": [
17044
+ {
17045
+ "kind": "Content",
17046
+ "text": "data: "
17047
+ },
17048
+ {
17049
+ "kind": "Content",
17050
+ "text": "object"
17051
+ },
17052
+ {
17053
+ "kind": "Content",
17054
+ "text": ";"
17055
+ }
17056
+ ],
17057
+ "isReadonly": false,
17058
+ "isOptional": false,
17059
+ "releaseTag": "Public",
17060
+ "name": "data",
17061
+ "propertyTypeTokenRange": {
17062
+ "startIndex": 1,
17063
+ "endIndex": 2
17064
+ }
17065
+ },
17066
+ {
17067
+ "kind": "PropertySignature",
17068
+ "canonicalReference": "server!PlayerUIEventPayload.SendData#playerUI:member",
17069
+ "docComment": "",
17070
+ "excerptTokens": [
17071
+ {
17072
+ "kind": "Content",
17073
+ "text": "playerUI: "
17074
+ },
17075
+ {
17076
+ "kind": "Reference",
17077
+ "text": "PlayerUI",
17078
+ "canonicalReference": "server!PlayerUI:class"
17079
+ },
17080
+ {
17081
+ "kind": "Content",
17082
+ "text": ";"
17083
+ }
17084
+ ],
17085
+ "isReadonly": false,
17086
+ "isOptional": false,
17087
+ "releaseTag": "Public",
17088
+ "name": "playerUI",
17089
+ "propertyTypeTokenRange": {
17090
+ "startIndex": 1,
17091
+ "endIndex": 2
17092
+ }
17093
+ }
17094
+ ],
17095
+ "extendsTokenRanges": []
17096
+ }
17097
+ ]
17098
+ },
17099
+ {
17100
+ "kind": "Enum",
17101
+ "canonicalReference": "server!PlayerUIEventType:enum",
17102
+ "docComment": "/**\n * Event types a\n */\n",
17103
+ "excerptTokens": [
17104
+ {
17105
+ "kind": "Content",
17106
+ "text": "export declare enum PlayerUIEventType "
17107
+ }
17108
+ ],
17109
+ "fileUrlPath": "src/networking/players/PlayerUI.ts",
17110
+ "releaseTag": "Public",
17111
+ "name": "PlayerUIEventType",
17112
+ "preserveMemberOrder": false,
17113
+ "members": [
17114
+ {
17115
+ "kind": "EnumMember",
17116
+ "canonicalReference": "server!PlayerUIEventType.LOAD:member",
17117
+ "docComment": "",
17118
+ "excerptTokens": [
17119
+ {
17120
+ "kind": "Content",
17121
+ "text": "LOAD = "
17122
+ },
17123
+ {
17124
+ "kind": "Content",
17125
+ "text": "\"PLAYER_UI.LOAD\""
17126
+ }
17127
+ ],
17128
+ "initializerTokenRange": {
17129
+ "startIndex": 1,
17130
+ "endIndex": 2
17131
+ },
17132
+ "releaseTag": "Public",
17133
+ "name": "LOAD"
17134
+ },
17135
+ {
17136
+ "kind": "EnumMember",
17137
+ "canonicalReference": "server!PlayerUIEventType.SEND_DATA:member",
17138
+ "docComment": "",
17139
+ "excerptTokens": [
17140
+ {
17141
+ "kind": "Content",
17142
+ "text": "SEND_DATA = "
17143
+ },
17144
+ {
17145
+ "kind": "Content",
17146
+ "text": "\"PLAYER_UI.SEND_DATA\""
17147
+ }
17148
+ ],
17149
+ "initializerTokenRange": {
17150
+ "startIndex": 1,
17151
+ "endIndex": 2
17152
+ },
17153
+ "releaseTag": "Public",
17154
+ "name": "SEND_DATA"
17155
+ }
17156
+ ]
17157
+ },
16722
17158
  {
16723
17159
  "kind": "Variable",
16724
17160
  "canonicalReference": "server!PORT:var",