hytopia 0.3.6 → 0.3.8

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.
Files changed (147) hide show
  1. package/boilerplate/assets/map.json +191 -43
  2. package/docs/server.playercameramode.md +14 -0
  3. package/examples/hygrounds/README.md +0 -0
  4. package/examples/hygrounds/assets/audio/sfx/chest-open-1.mp3 +0 -0
  5. package/examples/hygrounds/assets/audio/sfx/chest-open-2.mp3 +0 -0
  6. package/examples/hygrounds/assets/audio/sfx/machine-gun-reload.mp3 +0 -0
  7. package/examples/hygrounds/assets/audio/sfx/machine-gun-shoot.mp3 +0 -0
  8. package/examples/hygrounds/assets/audio/sfx/medpack-consume.mp3 +0 -0
  9. package/examples/hygrounds/assets/audio/sfx/mining-drill-drilling.mp3 +0 -0
  10. package/examples/hygrounds/assets/audio/sfx/pistol-reload.mp3 +0 -0
  11. package/examples/hygrounds/assets/audio/sfx/pistol-shoot.mp3 +0 -0
  12. package/examples/hygrounds/assets/audio/sfx/player-hurt.mp3 +0 -0
  13. package/examples/hygrounds/assets/audio/sfx/potion-consume.mp3 +0 -0
  14. package/examples/hygrounds/assets/audio/sfx/rifle-reload.mp3 +0 -0
  15. package/examples/hygrounds/assets/audio/sfx/rifle-shoot.mp3 +0 -0
  16. package/examples/hygrounds/assets/audio/sfx/rocket-launcher-explosion.mp3 +0 -0
  17. package/examples/hygrounds/assets/audio/sfx/rocket-launcher-reload.mp3 +0 -0
  18. package/examples/hygrounds/assets/audio/sfx/rocket-launcher-shoot.mp3 +0 -0
  19. package/examples/hygrounds/assets/audio/sfx/shield.png +0 -0
  20. package/examples/hygrounds/assets/audio/sfx/shotgun-reload.mp3 +0 -0
  21. package/examples/hygrounds/assets/audio/sfx/shotgun-shoot.mp3 +0 -0
  22. package/examples/hygrounds/assets/audio/sfx/sniper-reload.mp3 +0 -0
  23. package/examples/hygrounds/assets/audio/sfx/sniper-shoot.mp3 +0 -0
  24. package/examples/hygrounds/assets/icons/ak-47.png +0 -0
  25. package/examples/hygrounds/assets/icons/ammo.png +0 -0
  26. package/examples/hygrounds/assets/icons/auto-shotgun.png +0 -0
  27. package/examples/hygrounds/assets/icons/auto-sniper.png +0 -0
  28. package/examples/hygrounds/assets/icons/block.png +0 -0
  29. package/examples/hygrounds/assets/icons/bolt-action-sniper.png +0 -0
  30. package/examples/hygrounds/assets/icons/crown-bronze.png +0 -0
  31. package/examples/hygrounds/assets/icons/crown-gold.png +0 -0
  32. package/examples/hygrounds/assets/icons/crown-silver.png +0 -0
  33. package/examples/hygrounds/assets/icons/gravity-potion.png +0 -0
  34. package/examples/hygrounds/assets/icons/heart.png +0 -0
  35. package/examples/hygrounds/assets/icons/light-machine-gun.png +0 -0
  36. package/examples/hygrounds/assets/icons/medpack.png +0 -0
  37. package/examples/hygrounds/assets/icons/mining-drill.png +0 -0
  38. package/examples/hygrounds/assets/icons/pickaxe.png +0 -0
  39. package/examples/hygrounds/assets/icons/pistol.png +0 -0
  40. package/examples/hygrounds/assets/icons/revolver.png +0 -0
  41. package/examples/hygrounds/assets/icons/rocket-launcher.png +0 -0
  42. package/examples/hygrounds/assets/icons/shield-potion.png +0 -0
  43. package/examples/hygrounds/assets/icons/shield.png +0 -0
  44. package/examples/hygrounds/assets/icons/shotgun.png +0 -0
  45. package/examples/hygrounds/assets/icons/submachine-gun.png +0 -0
  46. package/examples/hygrounds/assets/map.json +31796 -0
  47. package/examples/hygrounds/assets/models/environment/.optimized/explosion/explosion-named-nodes.glb +0 -0
  48. package/examples/hygrounds/assets/models/environment/.optimized/explosion/explosion.glb +0 -0
  49. package/examples/hygrounds/assets/models/environment/.optimized/explosion/explosion.glb.md5 +1 -0
  50. package/examples/hygrounds/assets/models/environment/.optimized/explosion-2/explosion-2-named-nodes.glb +0 -0
  51. package/examples/hygrounds/assets/models/environment/.optimized/explosion-2/explosion-2.glb +0 -0
  52. package/examples/hygrounds/assets/models/environment/.optimized/explosion-2/explosion-2.glb.md5 +1 -0
  53. package/examples/hygrounds/assets/models/environment/.optimized/explosion-3/explosion-3-named-nodes.glb +0 -0
  54. package/examples/hygrounds/assets/models/environment/.optimized/explosion-3/explosion-3.glb +0 -0
  55. package/examples/hygrounds/assets/models/environment/.optimized/explosion-3/explosion-3.glb.md5 +1 -0
  56. package/examples/hygrounds/assets/models/environment/.optimized/helicopter/helicopter-named-nodes.glb +0 -0
  57. package/examples/hygrounds/assets/models/environment/.optimized/helicopter/helicopter.glb +0 -0
  58. package/examples/hygrounds/assets/models/environment/.optimized/helicopter/helicopter.glb.md5 +1 -0
  59. package/examples/hygrounds/assets/models/environment/chest.gltf +1 -0
  60. package/examples/hygrounds/assets/models/environment/explosion.glb +0 -0
  61. package/examples/hygrounds/assets/models/environment/muzzle-flash.gltf +1 -0
  62. package/examples/hygrounds/assets/models/items/.optimized/auto-sniper/auto-sniper-named-nodes.glb +0 -0
  63. package/examples/hygrounds/assets/models/items/.optimized/auto-sniper/auto-sniper.glb +0 -0
  64. package/examples/hygrounds/assets/models/items/.optimized/auto-sniper/auto-sniper.glb.md5 +1 -0
  65. package/examples/hygrounds/assets/models/items/.optimized/gravity-potion/gravity-potion-named-nodes.glb +0 -0
  66. package/examples/hygrounds/assets/models/items/.optimized/gravity-potion/gravity-potion.glb +0 -0
  67. package/examples/hygrounds/assets/models/items/.optimized/gravity-potion/gravity-potion.glb.md5 +1 -0
  68. package/examples/hygrounds/assets/models/items/.optimized/medkit/medkit-named-nodes.glb +0 -0
  69. package/examples/hygrounds/assets/models/items/.optimized/medkit/medkit.glb +0 -0
  70. package/examples/hygrounds/assets/models/items/.optimized/medkit/medkit.glb.md5 +1 -0
  71. package/examples/hygrounds/assets/models/items/.optimized/medpack/medpack-named-nodes.glb +0 -0
  72. package/examples/hygrounds/assets/models/items/.optimized/medpack/medpack.glb +0 -0
  73. package/examples/hygrounds/assets/models/items/.optimized/medpack/medpack.glb.md5 +1 -0
  74. package/examples/hygrounds/assets/models/items/.optimized/mining-drill/mining-drill-named-nodes.glb +0 -0
  75. package/examples/hygrounds/assets/models/items/.optimized/mining-drill/mining-drill.glb +0 -0
  76. package/examples/hygrounds/assets/models/items/.optimized/mining-drill/mining-drill.glb.md5 +1 -0
  77. package/examples/hygrounds/assets/models/items/.optimized/revolver/revolver-named-nodes.glb +0 -0
  78. package/examples/hygrounds/assets/models/items/.optimized/revolver/revolver.glb +0 -0
  79. package/examples/hygrounds/assets/models/items/.optimized/revolver/revolver.glb.md5 +1 -0
  80. package/examples/hygrounds/assets/models/items/.optimized/rocket-missile/rocket-missile-named-nodes.glb +0 -0
  81. package/examples/hygrounds/assets/models/items/.optimized/rocket-missile/rocket-missile.glb +0 -0
  82. package/examples/hygrounds/assets/models/items/.optimized/rocket-missile/rocket-missile.glb.md5 +1 -0
  83. package/examples/hygrounds/assets/models/items/.optimized/shield-potion/shield-potion-named-nodes.glb +0 -0
  84. package/examples/hygrounds/assets/models/items/.optimized/shield-potion/shield-potion.glb +0 -0
  85. package/examples/hygrounds/assets/models/items/.optimized/shield-potion/shield-potion.glb.md5 +1 -0
  86. package/examples/hygrounds/assets/models/items/.optimized/shield-potion-2/shield-potion-2-named-nodes.glb +0 -0
  87. package/examples/hygrounds/assets/models/items/.optimized/shield-potion-2/shield-potion-2.glb +0 -0
  88. package/examples/hygrounds/assets/models/items/.optimized/shield-potion-2/shield-potion-2.glb.md5 +1 -0
  89. package/examples/hygrounds/assets/models/items/.optimized/submachine-gun/submachine-gun-named-nodes.glb +0 -0
  90. package/examples/hygrounds/assets/models/items/.optimized/submachine-gun/submachine-gun.glb +0 -0
  91. package/examples/hygrounds/assets/models/items/.optimized/submachine-gun/submachine-gun.glb.md5 +1 -0
  92. package/examples/hygrounds/assets/models/items/ak-47.glb +0 -0
  93. package/examples/hygrounds/assets/models/items/auto-shotgun.glb +0 -0
  94. package/examples/hygrounds/assets/models/items/auto-sniper.glb +0 -0
  95. package/examples/hygrounds/assets/models/items/bolt-action-sniper.glb +0 -0
  96. package/examples/hygrounds/assets/models/items/gravity-potion.glb +0 -0
  97. package/examples/hygrounds/assets/models/items/light-machine-gun.glb +0 -0
  98. package/examples/hygrounds/assets/models/items/medpack.glb +0 -0
  99. package/examples/hygrounds/assets/models/items/mining-drill.glb +0 -0
  100. package/examples/hygrounds/assets/models/items/pickaxe.gltf +1 -0
  101. package/examples/hygrounds/assets/models/items/pistol.glb +0 -0
  102. package/examples/hygrounds/assets/models/items/revolver.glb +0 -0
  103. package/examples/hygrounds/assets/models/items/rocket-launcher.glb +0 -0
  104. package/examples/hygrounds/assets/models/items/rocket-missile.glb +0 -0
  105. package/examples/hygrounds/assets/models/items/shield-potion.glb +0 -0
  106. package/examples/hygrounds/assets/models/items/shotgun.glb +0 -0
  107. package/examples/hygrounds/assets/models/items/submachine-gun.glb +0 -0
  108. package/examples/hygrounds/assets/models/players/soldier-player.gltf +1 -0
  109. package/examples/hygrounds/assets/ui/images/scope.png +0 -0
  110. package/examples/hygrounds/assets/ui/index.html +1122 -0
  111. package/examples/hygrounds/bun.lock +503 -0
  112. package/examples/hygrounds/classes/ChestEntity.ts +133 -0
  113. package/examples/hygrounds/classes/GameManager.ts +422 -0
  114. package/examples/hygrounds/classes/GamePlayerEntity.ts +595 -0
  115. package/examples/hygrounds/classes/GunEntity.ts +259 -0
  116. package/examples/hygrounds/classes/ItemEntity.ts +225 -0
  117. package/examples/hygrounds/classes/ItemFactory.ts +61 -0
  118. package/examples/hygrounds/classes/MeleeWeaponEntity.ts +138 -0
  119. package/examples/hygrounds/classes/TerrainDamageManager.ts +56 -0
  120. package/examples/hygrounds/classes/items/GravityPotionEntity.ts +48 -0
  121. package/examples/hygrounds/classes/items/MedPackEntity.ts +43 -0
  122. package/examples/hygrounds/classes/items/ShieldPotionEntity.ts +43 -0
  123. package/examples/hygrounds/classes/weapons/AK47Entity.ts +43 -0
  124. package/examples/hygrounds/classes/weapons/AutoShotgunEntity.ts +80 -0
  125. package/examples/hygrounds/classes/weapons/AutoSniperEntity.ts +43 -0
  126. package/examples/hygrounds/classes/weapons/BoltActionSniperEntity.ts +46 -0
  127. package/examples/hygrounds/classes/weapons/LightMachineGunEntity.ts +43 -0
  128. package/examples/hygrounds/classes/weapons/MiningDrillEntity.ts +38 -0
  129. package/examples/hygrounds/classes/weapons/PickaxeEntity.ts +38 -0
  130. package/examples/hygrounds/classes/weapons/PistolEntity.ts +46 -0
  131. package/examples/hygrounds/classes/weapons/RevolverEntity.ts +46 -0
  132. package/examples/hygrounds/classes/weapons/RocketLauncherEntity.ts +195 -0
  133. package/examples/hygrounds/classes/weapons/ShotgunEntity.ts +84 -0
  134. package/examples/hygrounds/classes/weapons/SubmachineGunEntity.ts +43 -0
  135. package/examples/hygrounds/gameConfig.ts +430 -0
  136. package/examples/hygrounds/index.ts +41 -0
  137. package/examples/hygrounds/package.json +16 -0
  138. package/examples/player-persistence/README.md +3 -0
  139. package/examples/player-persistence/assets/map.json +2623 -0
  140. package/examples/player-persistence/dev/persistence/player-player-1.json +6 -0
  141. package/examples/player-persistence/dev/persistence/test.json +3 -0
  142. package/examples/player-persistence/index.ts +126 -0
  143. package/examples/player-persistence/package.json +16 -0
  144. package/package.json +1 -1
  145. package/server.api.json +21 -0
  146. package/server.d.ts +2 -1
  147. package/server.js +113 -113
@@ -0,0 +1,56 @@
1
+ import { Block, Vector3Like, World } from 'hytopia';
2
+ import {
3
+ BEDROCK_BLOCK_ID,
4
+ BLOCK_ID_BREAK_DAMAGE,
5
+ BLOCK_ID_MATERIALS,
6
+ } from '../gameConfig';
7
+
8
+ interface BlockDamage {
9
+ blockId: number;
10
+ totalDamage: number;
11
+ }
12
+
13
+ export default class TerrainDamageManager {
14
+ public static instance: TerrainDamageManager = new TerrainDamageManager();
15
+
16
+ private _blockDamages: Map<string, BlockDamage> = new Map();
17
+
18
+ private constructor() {}
19
+
20
+ public static getBreakMaterialCount(blockId: number): number {
21
+ return BLOCK_ID_MATERIALS[blockId] ?? BLOCK_ID_MATERIALS.default;
22
+ }
23
+
24
+ public damageBlock(world: World, block: Block, damage: number): boolean {
25
+ const coordinateKey = this._coordinateToKey(block.globalCoordinate);
26
+ let blockDamage = this._blockDamages.get(coordinateKey);
27
+
28
+ if (!blockDamage) {
29
+ const blockId = block.blockType.id;
30
+
31
+ if (block.blockType.isLiquid || blockId === BEDROCK_BLOCK_ID) {
32
+ return false;
33
+ }
34
+
35
+ blockDamage = { blockId, totalDamage: 0 };
36
+ this._blockDamages.set(coordinateKey, blockDamage);
37
+ }
38
+
39
+ blockDamage.totalDamage += damage;
40
+
41
+ const requiredBreakDamage = BLOCK_ID_BREAK_DAMAGE[blockDamage.blockId] ?? BLOCK_ID_BREAK_DAMAGE.default;
42
+
43
+ if (blockDamage.totalDamage >= requiredBreakDamage) {
44
+ world.chunkLattice.setBlock(block.globalCoordinate, 0);
45
+ this._blockDamages.delete(coordinateKey);
46
+
47
+ return true;
48
+ }
49
+
50
+ return false;
51
+ }
52
+
53
+ private _coordinateToKey(coordinate: Vector3Like): string {
54
+ return `${coordinate.x},${coordinate.y},${coordinate.z}`;
55
+ }
56
+ }
@@ -0,0 +1,48 @@
1
+ import { Quaternion } from 'hytopia';
2
+ import ItemEntity from "../ItemEntity";
3
+ import GamePlayerEntity from '../GamePlayerEntity';
4
+ import type { ItemEntityOptions } from "../ItemEntity";
5
+
6
+ const GRAVITY_SCALE = 0.3;
7
+ const GRAVITY_DURATION_MS = 15 * 1000; // 15 seconds
8
+
9
+ const DEFAULT_GRAVITY_POTION_OPTIONS: ItemEntityOptions = {
10
+ heldHand: 'right',
11
+ iconImageUri: 'icons/gravity-potion.png',
12
+ idleAnimation: 'idle_gun_right',
13
+ mlAnimation: 'shoot_gun_right',
14
+ modelUri: 'models/items/gravity-potion.glb',
15
+ modelScale: 0.4,
16
+ name: 'Gravity Potion',
17
+ consumable: true,
18
+ consumeAudioUri: 'audio/sfx/potion-consume.mp3',
19
+ consumeTimeMs: 1000,
20
+ quantity: 1,
21
+ }
22
+
23
+ export default class GravityPotionEntity extends ItemEntity {
24
+ public constructor(options: Partial<ItemEntityOptions> = {}) {
25
+ super({ ...DEFAULT_GRAVITY_POTION_OPTIONS, ...options });
26
+ }
27
+
28
+ public override consume(): void {
29
+ if (!(this.parent instanceof GamePlayerEntity)) {
30
+ return;
31
+ }
32
+
33
+ const parent = this.parent as GamePlayerEntity;
34
+
35
+ // Apply gravity potion effect
36
+ parent.setGravity(GRAVITY_SCALE);
37
+ setTimeout(() => parent.setGravity(1), GRAVITY_DURATION_MS);
38
+
39
+ super.consume();
40
+ }
41
+
42
+ public override equip(): void {
43
+ super.equip();
44
+
45
+ this.setPosition({ x: 0, y: 0.15, z: -0.2 });
46
+ this.setRotation(Quaternion.fromEuler(-90, 0, 0));
47
+ }
48
+ }
@@ -0,0 +1,43 @@
1
+ import { Quaternion } from 'hytopia';
2
+ import ItemEntity from "../ItemEntity";
3
+ import GamePlayerEntity from '../GamePlayerEntity';
4
+ import type { ItemEntityOptions } from "../ItemEntity";
5
+
6
+ const ADD_HEALTH_AMOUNT = 50;
7
+
8
+ const DEFAULT_MEDPACK_OPTIONS: ItemEntityOptions = {
9
+ heldHand: 'right',
10
+ iconImageUri: 'icons/medpack.png',
11
+ idleAnimation: 'idle_gun_right',
12
+ mlAnimation: 'shoot_gun_right',
13
+ modelUri: 'models/items/medpack.glb',
14
+ modelScale: 0.4,
15
+ name: 'Med Pack',
16
+ consumable: true,
17
+ consumeAudioUri: 'audio/sfx/medpack-consume.mp3',
18
+ consumeTimeMs: 1000,
19
+ quantity: 1,
20
+ }
21
+
22
+ export default class MedPackEntity extends ItemEntity {
23
+ public constructor(options: Partial<ItemEntityOptions> = {}) {
24
+ super({ ...DEFAULT_MEDPACK_OPTIONS, ...options });
25
+ }
26
+
27
+ public override consume(): void {
28
+ if (!(this.parent instanceof GamePlayerEntity) || this.parent.health >= this.parent.maxHealth) {
29
+ return;
30
+ }
31
+
32
+ this.parent.updateHealth(ADD_HEALTH_AMOUNT);
33
+
34
+ super.consume();
35
+ }
36
+
37
+ public override equip(): void {
38
+ super.equip();
39
+
40
+ this.setPosition({ x: 0, y: 0.15, z: 0.3 });
41
+ this.setRotation(Quaternion.fromEuler(-90, 0, 270));
42
+ }
43
+ }
@@ -0,0 +1,43 @@
1
+ import { Quaternion } from 'hytopia';
2
+ import ItemEntity from "../ItemEntity";
3
+ import GamePlayerEntity from '../GamePlayerEntity';
4
+ import type { ItemEntityOptions } from "../ItemEntity";
5
+
6
+ const ADD_SHIELD_AMOUNT = 25;
7
+
8
+ const DEFAULT_SHIELD_POTION_OPTIONS: ItemEntityOptions = {
9
+ heldHand: 'right',
10
+ iconImageUri: 'icons/shield-potion.png',
11
+ idleAnimation: 'idle_gun_right',
12
+ mlAnimation: 'shoot_gun_right',
13
+ modelUri: 'models/items/shield-potion.glb',
14
+ modelScale: 0.4,
15
+ name: 'Shield Potion',
16
+ consumable: true,
17
+ consumeAudioUri: 'audio/sfx/potion-consume.mp3',
18
+ consumeTimeMs: 1000,
19
+ quantity: 1,
20
+ }
21
+
22
+ export default class ShieldPotionEntity extends ItemEntity {
23
+ public constructor(options: Partial<ItemEntityOptions> = {}) {
24
+ super({ ...DEFAULT_SHIELD_POTION_OPTIONS, ...options });
25
+ }
26
+
27
+ public override consume(): void {
28
+ if (!(this.parent instanceof GamePlayerEntity) || this.parent.shield >= this.parent.maxShield) {
29
+ return;
30
+ }
31
+
32
+ this.parent.updateShield(ADD_SHIELD_AMOUNT);
33
+
34
+ super.consume();
35
+ }
36
+
37
+ public override equip(): void {
38
+ super.equip();
39
+
40
+ this.setPosition({ x: 0, y: 0.15, z: -0.2 });
41
+ this.setRotation(Quaternion.fromEuler(-90, 0, 0));
42
+ }
43
+ }
@@ -0,0 +1,43 @@
1
+ import { Quaternion, Vector3Like, QuaternionLike } from 'hytopia';
2
+ import GunEntity from '../GunEntity';
3
+ import type { GunEntityOptions } from '../GunEntity';
4
+
5
+ const DEFAULT_AK47_OPTIONS: GunEntityOptions = {
6
+ ammo: 25,
7
+ damage: 22,
8
+ fireRate: 5,
9
+ heldHand: 'both',
10
+ iconImageUri: 'icons/ak-47.png',
11
+ idleAnimation: 'idle_gun_both',
12
+ mlAnimation: 'shoot_gun_both',
13
+ name: 'AK-47',
14
+ maxAmmo: 25,
15
+ totalAmmo: 150,
16
+ scopeZoom: 2,
17
+ modelUri: 'models/items/ak-47.glb',
18
+ modelScale: 1.3,
19
+ range: 70,
20
+ reloadAudioUri: 'audio/sfx/rifle-reload.mp3',
21
+ reloadTimeMs: 2200,
22
+ shootAudioUri: 'audio/sfx/rifle-shoot.mp3',
23
+ };
24
+
25
+ export default class AK47Entity extends GunEntity {
26
+ public constructor(options: Partial<GunEntityOptions> = {}) {
27
+ super({ ...DEFAULT_AK47_OPTIONS, ...options });
28
+ }
29
+
30
+ public override shoot(): void {
31
+ if (!this.parent || !this.processShoot()) return;
32
+
33
+ super.shoot();
34
+ }
35
+
36
+ public override getMuzzleFlashPositionRotation(): { position: Vector3Like, rotation: QuaternionLike } {
37
+ return {
38
+ position: { x: 0, y: 0.01, z: -1.25 },
39
+ rotation: Quaternion.fromEuler(0, 90, 0),
40
+ };
41
+ }
42
+ }
43
+
@@ -0,0 +1,80 @@
1
+ import { Quaternion, Vector3Like, QuaternionLike } from 'hytopia';
2
+ import GunEntity from '../GunEntity';
3
+ import type { GunEntityOptions } from '../GunEntity';
4
+
5
+ const DEFAULT_AUTO_SHOTGUN_OPTIONS: GunEntityOptions = {
6
+ ammo: 6,
7
+ damage: 11,
8
+ fireRate: 1.5,
9
+ heldHand: 'both',
10
+ iconImageUri: 'icons/auto-shotgun.png',
11
+ idleAnimation: 'idle_gun_both',
12
+ mlAnimation: 'shoot_gun_both',
13
+ name: 'Auto Shotgun',
14
+ maxAmmo: 6,
15
+ totalAmmo: 30,
16
+ modelUri: 'models/items/auto-shotgun.glb',
17
+ modelScale: 1.2,
18
+ range: 8,
19
+ reloadAudioUri: 'audio/sfx/shotgun-reload.mp3',
20
+ reloadTimeMs: 3500,
21
+ shootAudioUri: 'audio/sfx/shotgun-shoot.mp3',
22
+ };
23
+
24
+ export default class AutoShotgunEntity extends GunEntity {
25
+ public constructor(options: Partial<GunEntityOptions> = {}) {
26
+ super({ ...DEFAULT_AUTO_SHOTGUN_OPTIONS, ...options });
27
+ }
28
+
29
+ public override shoot(): void {
30
+ if (!this.parent || !this.processShoot()) return;
31
+
32
+ super.shoot();
33
+ }
34
+
35
+ public override getMuzzleFlashPositionRotation(): { position: Vector3Like, rotation: QuaternionLike } {
36
+ return {
37
+ position: { x: 0.015, y: 0, z: -1 },
38
+ rotation: Quaternion.fromEuler(0, 90, 0),
39
+ };
40
+ }
41
+
42
+ public override shootRaycast(origin: Vector3Like, direction: Vector3Like, length: number) {
43
+ // Create spread pattern for auto-shotgun pellets using angles relative to direction
44
+ const spreadAngles = [
45
+ { x: 0, y: 0 }, // Center
46
+ { x: 0.05, y: 0.05 }, // Upper right
47
+ { x: -0.05, y: 0.05 }, // Upper left
48
+ { x: 0.07, y: 0 }, // Right
49
+ { x: -0.07, y: 0 }, // Left
50
+ { x: 0.05, y: -0.05 }, // Lower right
51
+ { x: -0.05, y: -0.05 } // Lower left
52
+ ];
53
+
54
+ // Fire each pellet with spread applied to original direction
55
+ for (const angle of spreadAngles) {
56
+ // Calculate spread direction relative to original direction
57
+ const spreadDirection = {
58
+ x: direction.x + (direction.z * angle.x), // Add horizontal spread
59
+ y: direction.y + angle.y, // Add vertical spread
60
+ z: direction.z - (direction.x * angle.x) // Maintain direction magnitude
61
+ };
62
+
63
+ // Normalize the spread direction to maintain consistent range
64
+ const magnitude = Math.sqrt(
65
+ spreadDirection.x * spreadDirection.x +
66
+ spreadDirection.y * spreadDirection.y +
67
+ spreadDirection.z * spreadDirection.z
68
+ );
69
+
70
+ const normalizedDirection = {
71
+ x: spreadDirection.x / magnitude,
72
+ y: spreadDirection.y / magnitude,
73
+ z: spreadDirection.z / magnitude
74
+ };
75
+
76
+ super.shootRaycast(origin, normalizedDirection, length);
77
+ }
78
+ }
79
+ }
80
+
@@ -0,0 +1,43 @@
1
+ import { Quaternion, Vector3Like, QuaternionLike } from 'hytopia';
2
+ import GunEntity from '../GunEntity';
3
+ import type { GunEntityOptions } from '../GunEntity';
4
+
5
+ const DEFAULT_AUTO_SNIPER_OPTIONS: GunEntityOptions = {
6
+ ammo: 10,
7
+ damage: 50,
8
+ fireRate: 1.5,
9
+ heldHand: 'both',
10
+ iconImageUri: 'icons/auto-sniper.png',
11
+ idleAnimation: 'idle_gun_both',
12
+ mlAnimation: 'shoot_gun_both',
13
+ name: 'Auto Sniper',
14
+ maxAmmo: 1,
15
+ totalAmmo: 12,
16
+ scopeZoom: 5,
17
+ modelUri: 'models/items/auto-sniper.glb',
18
+ modelScale: 1.3,
19
+ range: 100,
20
+ reloadAudioUri: 'audio/sfx/sniper-reload.mp3',
21
+ reloadTimeMs: 2200,
22
+ shootAudioUri: 'audio/sfx/sniper-shoot.mp3',
23
+ };
24
+
25
+ export default class AutoSniperEntity extends GunEntity {
26
+ public constructor(options: Partial<GunEntityOptions> = {}) {
27
+ super({ ...DEFAULT_AUTO_SNIPER_OPTIONS, ...options });
28
+ }
29
+
30
+ public override shoot(): void {
31
+ if (!this.parent || !this.processShoot()) return;
32
+
33
+ super.shoot();
34
+ }
35
+
36
+ public override getMuzzleFlashPositionRotation(): { position: Vector3Like, rotation: QuaternionLike } {
37
+ return {
38
+ position: { x: 0, y: 0.01, z: -2.7 },
39
+ rotation: Quaternion.fromEuler(0, 90, 0),
40
+ };
41
+ }
42
+ }
43
+
@@ -0,0 +1,46 @@
1
+ import { Quaternion, Vector3Like, QuaternionLike } from 'hytopia';
2
+ import GunEntity from '../GunEntity';
3
+ import type { GunEntityOptions } from '../GunEntity';
4
+
5
+ const DEFAULT_BOLT_ACTION_SNIPER_OPTIONS: GunEntityOptions = {
6
+ ammo: 1,
7
+ damage: 75,
8
+ fireRate: 0.5,
9
+ heldHand: 'both',
10
+ iconImageUri: 'icons/bolt-action-sniper.png',
11
+ idleAnimation: 'idle_gun_both',
12
+ mlAnimation: 'shoot_gun_both',
13
+ name: 'Bolt Action Sniper',
14
+ maxAmmo: 1,
15
+ totalAmmo: 12,
16
+ scopeZoom: 5,
17
+ modelUri: 'models/items/bolt-action-sniper.glb',
18
+ modelScale: 1.3,
19
+ range: 100,
20
+ reloadAudioUri: 'audio/sfx/sniper-reload.mp3',
21
+ reloadTimeMs: 2200,
22
+ shootAudioUri: 'audio/sfx/sniper-shoot.mp3',
23
+ };
24
+
25
+ export default class BoltActionSniperEntity extends GunEntity {
26
+ public constructor(options: Partial<GunEntityOptions> = {}) {
27
+ super({ ...DEFAULT_BOLT_ACTION_SNIPER_OPTIONS, ...options });
28
+ }
29
+
30
+ public override shoot(): void {
31
+ if (!this.parent || !this.processShoot()) return;
32
+
33
+ super.shoot();
34
+
35
+ // It's bolt action, auto reload it 300ms after a shot.
36
+ setTimeout(() => { this.reload() }, 300);
37
+ }
38
+
39
+ public override getMuzzleFlashPositionRotation(): { position: Vector3Like, rotation: QuaternionLike } {
40
+ return { // TODO: FIX MUZZLE FLASH POSITION
41
+ position: { x: 0, y: 0.01, z: -1.25 },
42
+ rotation: Quaternion.fromEuler(0, 90, 0),
43
+ };
44
+ }
45
+ }
46
+
@@ -0,0 +1,43 @@
1
+ import { Quaternion, Vector3Like, QuaternionLike } from 'hytopia';
2
+ import GunEntity from '../GunEntity';
3
+ import type { GunEntityOptions } from '../GunEntity';
4
+
5
+ const DEFAULT_LIGHT_MACHINE_GUN_OPTIONS: GunEntityOptions = {
6
+ ammo: 50,
7
+ damage: 9,
8
+ fireRate: 10,
9
+ heldHand: 'both',
10
+ iconImageUri: 'icons/light-machine-gun.png',
11
+ idleAnimation: 'idle_gun_both',
12
+ mlAnimation: 'shoot_gun_both',
13
+ name: 'Light Machine Gun',
14
+ maxAmmo: 50,
15
+ totalAmmo: 300,
16
+ scopeZoom: 1.35,
17
+ modelUri: 'models/items/light-machine-gun.glb',
18
+ modelScale: 1.3,
19
+ range: 50,
20
+ reloadAudioUri: 'audio/sfx/machine-gun-reload.mp3',
21
+ reloadTimeMs: 4200,
22
+ shootAudioUri: 'audio/sfx/machine-gun-shoot.mp3',
23
+ };
24
+
25
+ export default class LightMachineGunEntity extends GunEntity {
26
+ public constructor(options: Partial<GunEntityOptions> = {}) {
27
+ super({ ...DEFAULT_LIGHT_MACHINE_GUN_OPTIONS, ...options });
28
+ }
29
+
30
+ public override shoot(): void {
31
+ if (!this.parent || !this.processShoot()) return;
32
+
33
+ super.shoot();
34
+ }
35
+
36
+ public override getMuzzleFlashPositionRotation(): { position: Vector3Like, rotation: QuaternionLike } {
37
+ return {
38
+ position: { x: 0, y: 0.05, z: -1.7 },
39
+ rotation: Quaternion.fromEuler(0, 90, 0),
40
+ };
41
+ }
42
+ }
43
+
@@ -0,0 +1,38 @@
1
+ import { Quaternion } from 'hytopia';
2
+ import MeleeWeaponEntity from '../MeleeWeaponEntity';
3
+ import type { MeleeWeaponEntityOptions } from '../MeleeWeaponEntity';
4
+
5
+ const DEFAULT_MINING_DRILL_OPTIONS: MeleeWeaponEntityOptions = {
6
+ damage: 40,
7
+ attackRate: 5,
8
+ heldHand: 'right',
9
+ iconImageUri: 'icons/mining-drill.png',
10
+ idleAnimation: 'idle_gun_right',
11
+ mlAnimation: 'shoot_gun_right',
12
+ name: 'Mining Drill',
13
+ modelUri: 'models/items/mining-drill.glb',
14
+ modelScale: 0.05,
15
+ range: 1.5,
16
+ minesMaterials: true,
17
+ attackAudioUri: 'audio/sfx/mining-drill-drilling.mp3',
18
+ hitAudioUri: 'audio/sfx/dig/dig-stone.mp3',
19
+ };
20
+
21
+ export default class MiningDrillEntity extends MeleeWeaponEntity {
22
+ public constructor(options: Partial<MeleeWeaponEntityOptions> = {}) {
23
+ super({ ...DEFAULT_MINING_DRILL_OPTIONS, ...options, tag: 'mining-drill' });
24
+ }
25
+
26
+ public override attack(): void {
27
+ if (!this.parent || !this.processAttack()) return;
28
+
29
+ super.attack();
30
+ }
31
+
32
+ public override equip(): void {
33
+ super.equip();
34
+
35
+ this.setPosition({ x: -0.3, y: 0.5, z: -0.1 });
36
+ this.setRotation(Quaternion.fromEuler(180, 0, -90));
37
+ }
38
+ }
@@ -0,0 +1,38 @@
1
+ import { Quaternion } from 'hytopia';
2
+ import MeleeWeaponEntity from '../MeleeWeaponEntity';
3
+ import type { MeleeWeaponEntityOptions } from '../MeleeWeaponEntity';
4
+
5
+ const DEFAULT_PICKAXE_OPTIONS: MeleeWeaponEntityOptions = {
6
+ damage: 10, // 10 hits to kill unshielded
7
+ attackRate: 4.5, // Slower attack rate to prevent spam
8
+ heldHand: 'right',
9
+ iconImageUri: 'icons/pickaxe.png',
10
+ idleAnimation: 'idle_gun_right',
11
+ mlAnimation: 'simple_interact',
12
+ name: 'Pickaxe',
13
+ modelUri: 'models/items/pickaxe.gltf',
14
+ modelScale: 1.25,
15
+ range: 2,
16
+ minesMaterials: true,
17
+ attackAudioUri: 'audio/sfx/player/player-swing-woosh.mp3',
18
+ hitAudioUri: 'audio/sfx/dig/dig-stone.mp3',
19
+ };
20
+
21
+ export default class PickaxeEntity extends MeleeWeaponEntity {
22
+ public constructor(options: Partial<MeleeWeaponEntityOptions> = {}) {
23
+ super({ ...DEFAULT_PICKAXE_OPTIONS, ...options, tag: 'pickaxe' });
24
+ }
25
+
26
+ public override attack(): void {
27
+ if (!this.parent || !this.processAttack()) return;
28
+
29
+ super.attack();
30
+ }
31
+
32
+ public override equip(): void {
33
+ super.equip();
34
+
35
+ this.setPosition({ x: 0, y: 0.2, z: 0 });
36
+ this.setRotation(Quaternion.fromEuler(-90, 0, 90));
37
+ }
38
+ }
@@ -0,0 +1,46 @@
1
+ import { Quaternion, Vector3Like, QuaternionLike } from 'hytopia';
2
+ import GunEntity from '../GunEntity';
3
+ import type { GunEntityOptions } from '../GunEntity';
4
+ import type GamePlayerEntity from '../GamePlayerEntity';
5
+
6
+ const DEFAULT_PISTOL_OPTIONS: GunEntityOptions = {
7
+ ammo: 15,
8
+ damage: 18,
9
+ fireRate: 6,
10
+ heldHand: 'right',
11
+ iconImageUri: 'icons/pistol.png',
12
+ idleAnimation: 'idle_gun_right',
13
+ mlAnimation: 'shoot_gun_right',
14
+ name: 'Pistol',
15
+ maxAmmo: 15,
16
+ totalAmmo: 75,
17
+ modelUri: 'models/items/pistol.glb',
18
+ modelScale: 1.3,
19
+ range: 30,
20
+ reloadAudioUri: 'audio/sfx/pistol-reload.mp3',
21
+ reloadTimeMs: 1500,
22
+ shootAudioUri: 'audio/sfx/pistol-shoot.mp3',
23
+ };
24
+
25
+ export default class PistolEntity extends GunEntity {
26
+ public constructor(options: Partial<GunEntityOptions> = {}) {
27
+ super({ ...DEFAULT_PISTOL_OPTIONS, ...options });
28
+ }
29
+
30
+ public override shoot(): void {
31
+ if (!this.parent || !this.processShoot()) return;
32
+
33
+ super.shoot();
34
+
35
+ // Cancel input since pistol requires click-to-shoot
36
+ (this.parent as GamePlayerEntity).player.input.ml = false;
37
+ }
38
+
39
+ public override getMuzzleFlashPositionRotation(): { position: Vector3Like, rotation: QuaternionLike } {
40
+ return {
41
+ position: { x: 0.03, y: 0.1, z: -0.5 },
42
+ rotation: Quaternion.fromEuler(0, 90, 0),
43
+ };
44
+ }
45
+ }
46
+
@@ -0,0 +1,46 @@
1
+ import { Quaternion, Vector3Like, QuaternionLike } from 'hytopia';
2
+ import GunEntity from '../GunEntity';
3
+ import type { GunEntityOptions } from '../GunEntity';
4
+ import type GamePlayerEntity from '../GamePlayerEntity';
5
+
6
+ const DEFAULT_REVOLVER_OPTIONS: GunEntityOptions = {
7
+ ammo: 6,
8
+ damage: 45,
9
+ fireRate: 2,
10
+ heldHand: 'right',
11
+ iconImageUri: 'icons/revolver.png',
12
+ idleAnimation: 'idle_gun_right',
13
+ mlAnimation: 'shoot_gun_right',
14
+ name: 'Revolver',
15
+ maxAmmo: 6,
16
+ totalAmmo: 24,
17
+ modelUri: 'models/items/revolver.glb',
18
+ modelScale: 1.3,
19
+ range: 30,
20
+ reloadAudioUri: 'audio/sfx/pistol-reload.mp3',
21
+ reloadTimeMs: 2000,
22
+ shootAudioUri: 'audio/sfx/rifle-shoot.mp3',
23
+ };
24
+
25
+ export default class RevolverEntity extends GunEntity {
26
+ public constructor(options: Partial<GunEntityOptions> = {}) {
27
+ super({ ...DEFAULT_REVOLVER_OPTIONS, ...options });
28
+ }
29
+
30
+ public override shoot(): void {
31
+ if (!this.parent || !this.processShoot()) return;
32
+
33
+ super.shoot();
34
+
35
+ // Cancel input since pistol requires click-to-shoot
36
+ (this.parent as GamePlayerEntity).player.input.ml = false;
37
+ }
38
+
39
+ public override getMuzzleFlashPositionRotation(): { position: Vector3Like, rotation: QuaternionLike } {
40
+ return {
41
+ position: { x: 0.03, y: 0.18, z: -0.7 },
42
+ rotation: Quaternion.fromEuler(0, 90, 0),
43
+ };
44
+ }
45
+ }
46
+