mirror of
https://github.com/celisej567/mcpe.git
synced 2026-01-05 18:10:09 +03:00
* Initial commit.
:)
This commit is contained in:
63
.gitattributes
vendored
Normal file
63
.gitattributes
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
###############################################################################
|
||||||
|
# Set default behavior to automatically normalize line endings.
|
||||||
|
###############################################################################
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Set default behavior for command prompt diff.
|
||||||
|
#
|
||||||
|
# This is need for earlier builds of msysgit that does not have it on by
|
||||||
|
# default for csharp files.
|
||||||
|
# Note: This is only used by command line
|
||||||
|
###############################################################################
|
||||||
|
#*.cs diff=csharp
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Set the merge driver for project and solution files
|
||||||
|
#
|
||||||
|
# Merging from the command prompt will add diff markers to the files if there
|
||||||
|
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||||
|
# the diff markers are never inserted). Diff markers may cause the following
|
||||||
|
# file extensions to fail to load in VS. An alternative would be to treat
|
||||||
|
# these files as binary and thus will always conflict and require user
|
||||||
|
# intervention with every merge. To do so, just uncomment the entries below
|
||||||
|
###############################################################################
|
||||||
|
#*.sln merge=binary
|
||||||
|
#*.csproj merge=binary
|
||||||
|
#*.vbproj merge=binary
|
||||||
|
#*.vcxproj merge=binary
|
||||||
|
#*.vcproj merge=binary
|
||||||
|
#*.dbproj merge=binary
|
||||||
|
#*.fsproj merge=binary
|
||||||
|
#*.lsproj merge=binary
|
||||||
|
#*.wixproj merge=binary
|
||||||
|
#*.modelproj merge=binary
|
||||||
|
#*.sqlproj merge=binary
|
||||||
|
#*.wwaproj merge=binary
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# behavior for image files
|
||||||
|
#
|
||||||
|
# image files are treated as binary by default.
|
||||||
|
###############################################################################
|
||||||
|
#*.jpg binary
|
||||||
|
#*.png binary
|
||||||
|
#*.gif binary
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# diff behavior for common document formats
|
||||||
|
#
|
||||||
|
# Convert binary document formats to text before diffing them. This feature
|
||||||
|
# is only available from the command line. Turn it on by uncommenting the
|
||||||
|
# entries below.
|
||||||
|
###############################################################################
|
||||||
|
#*.doc diff=astextplain
|
||||||
|
#*.DOC diff=astextplain
|
||||||
|
#*.docx diff=astextplain
|
||||||
|
#*.DOCX diff=astextplain
|
||||||
|
#*.dot diff=astextplain
|
||||||
|
#*.DOT diff=astextplain
|
||||||
|
#*.pdf diff=astextplain
|
||||||
|
#*.PDF diff=astextplain
|
||||||
|
#*.rtf diff=astextplain
|
||||||
|
#*.RTF diff=astextplain
|
||||||
380
.gitignore
vendored
Normal file
380
.gitignore
vendored
Normal file
@@ -0,0 +1,380 @@
|
|||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Oo]ut/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
||||||
|
|
||||||
|
/minecraftpe/assets/font
|
||||||
|
/minecraftpe/assets/gui
|
||||||
|
/minecraftpe/assets/item
|
||||||
|
/minecraftpe/assets/mob
|
||||||
|
/minecraftpe/assets/particles.png
|
||||||
|
/minecraftpe/assets/terrain.png
|
||||||
|
|
||||||
|
/minecraftpe/games/com.mojang/*
|
||||||
|
/minecraftpe/DebugAsan
|
||||||
|
/minecraftpe/.old/DebugAsan
|
||||||
|
|
||||||
|
# Ignore sound data extracted from the game.
|
||||||
|
/sound_data
|
||||||
|
|
||||||
|
/windows_vs/games/com.mojang
|
||||||
|
/windows_vs/assets
|
||||||
76
README.md
Normal file
76
README.md
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
# Minecraft PE Reverse Engineering Project
|
||||||
|
|
||||||
|
This project is an attempt to recreate one of the first released builds of Minecraft: Pocket Edition -- mcpe01_canada.apk -- and port it to other platforms,
|
||||||
|
via binary reverse engineering.
|
||||||
|
|
||||||
|
An Android build will come soon.
|
||||||
|
|
||||||
|
* Note: The original mcpe01_canada.apk does not work on newer Android devices. A port of this likely will.
|
||||||
|
|
||||||
|
Eventually, I plan on creating a new repository, `mcpe01_canada`, which will include just the port of the Canada demo.
|
||||||
|
|
||||||
|
## WANT TO HELP?
|
||||||
|
|
||||||
|
Want to help this project? [Here's a list of things left to do.](TODO.md)
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Before opening the VS2022 project or trying to build, load the sound assets into the `sound_data/` folder in the root of the project
|
||||||
|
by running the following command:
|
||||||
|
* `tools/grabsounds.py /path/to/the/mcpe01_canada/lib/armeabi-v7a/libminecraftpe.so`.
|
||||||
|
|
||||||
|
## Have seams when playing?
|
||||||
|
|
||||||
|
I've had texture seams when playing Minecraft Classic, ClassiCube and this recreation of Minecraft PE. If seams bother you, and you are using an NVIDIA graphics card,
|
||||||
|
go to the NVIDIA Control Panel, then in "Manage 3D Settings", change "Antialiasing - Mode" to "Application Controlled".
|
||||||
|
|
||||||
|
## Notes on assets
|
||||||
|
The terrain.png and related textures appear to have stayed the same between the E3 demo and the final release for Xperia PLAY. It appears to have been fetched before
|
||||||
|
Java Edition Beta 1.4's release. This can be seen because the cookie's texture is missing. (it was added in Java Edition Beta 1.4)
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
## Known bugs
|
||||||
|
|
||||||
|
### Patched bugs
|
||||||
|
1. Due to lack of initialization of memory, fire can potentially burn normally inflammable blocks. See ]https://www.youtube.com/watch?v=3hrz7KK2EJs](this video) for a demo.
|
||||||
|
2. Due to SHAPE_FIRE not being implemented, fire is invisible in this version. Fire rendering was backported from v0.7.1 and can be disabled with the ORIGINAL_CODE define
|
||||||
|
3. Due to `GL_BLEND` being disabled, the hotbar renders as fully opaque.
|
||||||
|
4. Memory is leaked when leaving a world with particles in it.
|
||||||
|
5. Stairs are invisible when held. To fix this, a fix has been backported from v0.1.1j
|
||||||
|
6. If the game is left on for approximately 1,242 days, the level will freeze, but the GUI will still be interactable.
|
||||||
|
|
||||||
|
The bugs can be "un-patched" by defining ORIGINAL_CODE. This allows compilation of an incomplete and mostly accurate recreation of MCPE for Xperia Play.
|
||||||
|
|
||||||
|
### Unpatched bugs
|
||||||
|
1. Particles with render texture 3 are invisible.
|
||||||
|
2. Potential freeze in `Entity::move`. If z_1 is between -0.04f and 0.04f, the game may freeze.
|
||||||
|
3. In `Particle::render`, the offset (`C_MAGIC_1`) is slightly larger than 1.0f / 16.0f. It's probably meant to be _smaller_ than 1.0f / 16.0f.
|
||||||
|
4. Ice doesn't properly cull faces, except on the y axis.
|
||||||
|
5. Fire is not extinguished on the server side.
|
||||||
|
6. Due to inaccuracies in level generation, some blocks may be different in multiplayer between a player on this version, and a player on the original MCPE.
|
||||||
|
|
||||||
|
## Enhancements
|
||||||
|
The original Minecraft: Pocket Edition had some missing details that make it feel like MCPE. Here are some enhancements that I've done (these are all turned off with the
|
||||||
|
ORIGINAL_CODE define)
|
||||||
|
|
||||||
|
* Make fire burn properly (see Patched bug #1)
|
||||||
|
* Allow fire to be rendered (see Patched bug #2)
|
||||||
|
* Allow instant breaking of blocks
|
||||||
|
* Make entity models have primitive shading
|
||||||
|
* Make in-hand items have shading
|
||||||
|
* Use a GUI scale of 2 instead of 3 (temporary)
|
||||||
|
* Allow enabling ambient occlusion (smooth lighting), using a hotkey (F4)
|
||||||
|
* Allow the hotbar to be transparent. Fixes Patched bug #3
|
||||||
|
* Use Minecraft Java Edition Beta 1.6's light ramp code instead of the original (Max brightness was only 0.8 in early versions of PE for whatever reason)
|
||||||
|
* Hide particles from a camera's view. This hides the smoke particles that the camera emits, creating a clearer picture
|
||||||
|
|
||||||
|
They can be turned on/off in `source/Base/Utils.hpp`. They're disabled by default.
|
||||||
|
|
||||||
|
### Known bugs with enhancements
|
||||||
|
1. The camera's white overlay is fully opaque in shaded entity mode.
|
||||||
101
TODO.md
Normal file
101
TODO.md
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
## What is there left to do?
|
||||||
|
|
||||||
|
### GUI stuff
|
||||||
|
* [DONE] `ChatScreen`
|
||||||
|
* [DONE] `ConfirmScreen`
|
||||||
|
* [DONE] `DeleteWorldScreen`
|
||||||
|
* [DONE] `InvalidLicenseScreen`
|
||||||
|
* [DONE] `SmallButton`
|
||||||
|
* [DONE] `ScrolledSelectionList`
|
||||||
|
* [DONE] `AvailableGamesList`
|
||||||
|
* [DONE] `JoinGameScreen`
|
||||||
|
* [DONE] `RenameMPLevelScreen`
|
||||||
|
|
||||||
|
### Save data
|
||||||
|
* [DONE] `PlayerData`
|
||||||
|
* `RegionFile`
|
||||||
|
|
||||||
|
### Multiplayer
|
||||||
|
* [DONE] `ServerSideNetworkHandler`
|
||||||
|
* [DONE] `ClientSideNetworkHandler`
|
||||||
|
* [DONE] `MinecraftPackets`
|
||||||
|
* [DONE] `NetEventCallback`
|
||||||
|
* [DONE] `Packet`
|
||||||
|
* [DONE] `AddPlayerPacket`
|
||||||
|
* [DONE] `ChunkDataPacket`
|
||||||
|
* [DONE] `LoginPacket`
|
||||||
|
* [DONE] `MessagePacket`
|
||||||
|
* [DONE] `MovePlayerPacket`
|
||||||
|
* [DONE] `PlaceBlockPacket`
|
||||||
|
* [DONE] `PlayerEquipmentPacket`
|
||||||
|
* [DONE] `RemoveBlockPacket`
|
||||||
|
* [DONE] `RemoveEntityPacket`
|
||||||
|
* [DONE] `RequestChunkPacket`
|
||||||
|
* [DONE] `StartGamePacket`
|
||||||
|
* [DONE] `UpdateBlockPacket`
|
||||||
|
|
||||||
|
### Xperia Play features
|
||||||
|
* [DONE] `Controller`
|
||||||
|
* [DONE] `ControllerTurnInput`
|
||||||
|
|
||||||
|
### World gen features
|
||||||
|
* `LargeFeature`
|
||||||
|
* `LargeCaveFeature` [unused]
|
||||||
|
|
||||||
|
### Sound system:
|
||||||
|
* Mutex [used for SoundSystemSL, most of it is inlined]
|
||||||
|
* [DONE] `SoundEngine`
|
||||||
|
* [DONE] `SoundRepository`
|
||||||
|
* [DONE] `SoundSystem`
|
||||||
|
* `SoundSystemSL`
|
||||||
|
* `SoundSystemWindows` (not original, but needed if you want sound on Windows)
|
||||||
|
|
||||||
|
### Unused entities and their renderers
|
||||||
|
* [DONE] `FallingTile`
|
||||||
|
* [DONE] `ItemEntity`
|
||||||
|
* `ItemSpriteRenderer`
|
||||||
|
|
||||||
|
### From the non-demo version
|
||||||
|
* `ExternalFileLevelStorage`
|
||||||
|
* `ExternalFileLevelStorageSource`
|
||||||
|
|
||||||
|
### Miscellanea
|
||||||
|
* `StopwatchHandler` -- `Performance::watches`. Unused?! Don't know.
|
||||||
|
|
||||||
|
## More generic things left to do:
|
||||||
|
|
||||||
|
* The level generator is inaccurate in terms of features. Not sure why yet.
|
||||||
|
The land and ice generation is accurate, though :)
|
||||||
|
|
||||||
|
* Untangle all the control flow and variables. Some functions have nonsense variable names like v3, x4,
|
||||||
|
and sometimes gotos are used (like label_3). It would be nice to untangle those.
|
||||||
|
|
||||||
|
* Instead of having a list of directories to include from, have only one and use relative paths instead.
|
||||||
|
|
||||||
|
* Add the assertions from v0.1.1j (unoptimized debug build)
|
||||||
|
|
||||||
|
* Attempt to recreate the project structure from Mojang. See the [Reconstructed project structure](#reconstructed-project-structure)
|
||||||
|
|
||||||
|
## Reconstructed project structure
|
||||||
|
(note: some info is present in v0.1.0demo, some in v0.1.1j. The latter will be marked as [J].)
|
||||||
|
|
||||||
|
Obviously, this is VERY incomplete. This is what we know:
|
||||||
|
|
||||||
|
* Root: `C:/dev/subversion/mojang/minecraftcpp/trunk/handheld`
|
||||||
|
|
||||||
|
```
|
||||||
|
project/
|
||||||
|
android_java/
|
||||||
|
jni/
|
||||||
|
Possibly: Android.mk, Application.mk
|
||||||
|
src/
|
||||||
|
raknet/
|
||||||
|
The RakNet source code resides here.[1]
|
||||||
|
world/ [J]
|
||||||
|
level/ [J]
|
||||||
|
storage/ [J]
|
||||||
|
RegionFile.cpp [J]
|
||||||
|
```
|
||||||
|
|
||||||
|
* [1] - In v0.1.1j, the RakNet source files are located at: `C:/dev/subversion/mojang/minecraftcpp/trunk/handheld/project/lib_projects//raknet/jni/RakNetSources/`.
|
||||||
|
In v0.1.0 demo, they're at `C:/dev/subversion/mojang/minecraftcpp/trunk/handheld/project/android/jni/../../../src/raknet/`.
|
||||||
368
compat/AKeyCodes.hpp
Normal file
368
compat/AKeyCodes.hpp
Normal file
@@ -0,0 +1,368 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#define NOMINMAX
|
||||||
|
#include "Utils.hpp"
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
//fake keycodes for windows
|
||||||
|
AKEYCODE_UNKNOWN = 0,
|
||||||
|
|
||||||
|
AKEYCODE_MENU = VK_ESCAPE, // pause screen
|
||||||
|
AKEYCODE_SEARCH = VK_F5, // toggle third person mode
|
||||||
|
|
||||||
|
AKEYCODE_BACK = 'Y', // used to go left 1 slot
|
||||||
|
AKEYCODE_BUTTON_X = 'U', // used to go right 1 slot
|
||||||
|
AKEYCODE_BUTTON_Y = 'E', // show inventory
|
||||||
|
|
||||||
|
AKEYCODE_DPAD_UP = 'W',
|
||||||
|
AKEYCODE_DPAD_DOWN = 'S',
|
||||||
|
AKEYCODE_DPAD_LEFT = 'A',
|
||||||
|
AKEYCODE_DPAD_RIGHT = 'D',
|
||||||
|
AKEYCODE_DPAD_CENTER = ' ',
|
||||||
|
|
||||||
|
AKEYCODE_BUTTON_L1 = 'X',
|
||||||
|
AKEYCODE_BUTTON_R1 = 'C',
|
||||||
|
|
||||||
|
AKEYCODE_SHIFT_LEFT = VK_SHIFT,
|
||||||
|
AKEYCODE_SHIFT_RIGHT = VK_SHIFT,
|
||||||
|
|
||||||
|
AKEYCODE_DEL = VK_BACK,
|
||||||
|
AKEYCODE_FORWARD_DEL = VK_DELETE,
|
||||||
|
|
||||||
|
AKEYCODE_COMMA = VK_OEM_COMMA, // ',<'
|
||||||
|
AKEYCODE_PERIOD = VK_OEM_PERIOD,// '.>'
|
||||||
|
AKEYCODE_PLUS = VK_OEM_PLUS, // '=+'
|
||||||
|
AKEYCODE_MINUS = VK_OEM_MINUS, // '-_'
|
||||||
|
AKEYCODE_SEMICOLON = VK_OEM_1, // ';:'
|
||||||
|
AKEYCODE_SLASH = VK_OEM_2, // '/?'
|
||||||
|
AKEYCODE_GRAVE = VK_OEM_3, // '`~'
|
||||||
|
AKEYCODE_LEFT_BRACKET=VK_OEM_4, // '[{'
|
||||||
|
AKEYCODE_BACKSLASH = VK_OEM_5, // '\|'
|
||||||
|
AKEYCODE_RIGHT_BRACKET=VK_OEM_6,// ']}'
|
||||||
|
AKEYCODE_APOSTROPHE = VK_OEM_7, // ''"'
|
||||||
|
|
||||||
|
AKEYCODE_0 = '0',
|
||||||
|
//...
|
||||||
|
AKEYCODE_9 = '9',
|
||||||
|
|
||||||
|
AKEYCODE_A = 'A',
|
||||||
|
//...
|
||||||
|
AKEYCODE_Z = 'Z',
|
||||||
|
|
||||||
|
AKEYCODE_F4 = VK_F4,
|
||||||
|
};
|
||||||
|
|
||||||
|
// this sucks
|
||||||
|
#define AKEYCODE_ARROW_LEFT VK_LEFT
|
||||||
|
#define AKEYCODE_ARROW_RIGHT VK_RIGHT
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Add AKEYCODEs for your platform!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
//the real deal android key codes
|
||||||
|
AKEYCODE_UNKNOWN = 0,
|
||||||
|
AKEYCODE_SOFT_LEFT = 1,
|
||||||
|
AKEYCODE_SOFT_RIGHT = 2,
|
||||||
|
AKEYCODE_HOME = 3,
|
||||||
|
AKEYCODE_BACK = 4,
|
||||||
|
AKEYCODE_CALL = 5,
|
||||||
|
AKEYCODE_ENDCALL = 6,
|
||||||
|
AKEYCODE_0 = 7,
|
||||||
|
AKEYCODE_1 = 8,
|
||||||
|
AKEYCODE_2 = 9,
|
||||||
|
AKEYCODE_3 = 10,
|
||||||
|
AKEYCODE_4 = 11,
|
||||||
|
AKEYCODE_5 = 12,
|
||||||
|
AKEYCODE_6 = 13,
|
||||||
|
AKEYCODE_7 = 14,
|
||||||
|
AKEYCODE_8 = 15,
|
||||||
|
AKEYCODE_9 = 16,
|
||||||
|
AKEYCODE_STAR = 17,
|
||||||
|
AKEYCODE_POUND = 18,
|
||||||
|
AKEYCODE_DPAD_UP = 19,
|
||||||
|
AKEYCODE_DPAD_DOWN = 20,
|
||||||
|
AKEYCODE_DPAD_LEFT = 21,
|
||||||
|
AKEYCODE_DPAD_RIGHT = 22,
|
||||||
|
AKEYCODE_DPAD_CENTER = 23,
|
||||||
|
AKEYCODE_VOLUME_UP = 24,
|
||||||
|
AKEYCODE_VOLUME_DOWN = 25,
|
||||||
|
AKEYCODE_POWER = 26,
|
||||||
|
AKEYCODE_CAMERA = 27,
|
||||||
|
AKEYCODE_CLEAR = 28,
|
||||||
|
AKEYCODE_A = 29,
|
||||||
|
AKEYCODE_B = 30,
|
||||||
|
AKEYCODE_C = 31,
|
||||||
|
AKEYCODE_D = 32,
|
||||||
|
AKEYCODE_E = 33,
|
||||||
|
AKEYCODE_F = 34,
|
||||||
|
AKEYCODE_G = 35,
|
||||||
|
AKEYCODE_H = 36,
|
||||||
|
AKEYCODE_I = 37,
|
||||||
|
AKEYCODE_J = 38,
|
||||||
|
AKEYCODE_K = 39,
|
||||||
|
AKEYCODE_L = 40,
|
||||||
|
AKEYCODE_M = 41,
|
||||||
|
AKEYCODE_N = 42,
|
||||||
|
AKEYCODE_O = 43,
|
||||||
|
AKEYCODE_P = 44,
|
||||||
|
AKEYCODE_Q = 45,
|
||||||
|
AKEYCODE_R = 46,
|
||||||
|
AKEYCODE_S = 47,
|
||||||
|
AKEYCODE_T = 48,
|
||||||
|
AKEYCODE_U = 49,
|
||||||
|
AKEYCODE_V = 50,
|
||||||
|
AKEYCODE_W = 51,
|
||||||
|
AKEYCODE_X = 52,
|
||||||
|
AKEYCODE_Y = 53,
|
||||||
|
AKEYCODE_Z = 54,
|
||||||
|
AKEYCODE_COMMA = 55,
|
||||||
|
AKEYCODE_PERIOD = 56,
|
||||||
|
AKEYCODE_ALT_LEFT = 57,
|
||||||
|
AKEYCODE_ALT_RIGHT = 58,
|
||||||
|
AKEYCODE_SHIFT_LEFT = 59,
|
||||||
|
AKEYCODE_SHIFT_RIGHT = 60,
|
||||||
|
AKEYCODE_TAB = 61,
|
||||||
|
AKEYCODE_SPACE = 62,
|
||||||
|
AKEYCODE_SYM = 63,
|
||||||
|
AKEYCODE_EXPLORER = 64,
|
||||||
|
AKEYCODE_ENVELOPE = 65,
|
||||||
|
AKEYCODE_ENTER = 66,
|
||||||
|
AKEYCODE_DEL = 67,
|
||||||
|
AKEYCODE_GRAVE = 68,
|
||||||
|
AKEYCODE_MINUS = 69,
|
||||||
|
AKEYCODE_EQUALS = 70,
|
||||||
|
AKEYCODE_LEFT_BRACKET = 71,
|
||||||
|
AKEYCODE_RIGHT_BRACKET = 72,
|
||||||
|
AKEYCODE_BACKSLASH = 73,
|
||||||
|
AKEYCODE_SEMICOLON = 74,
|
||||||
|
AKEYCODE_APOSTROPHE = 75,
|
||||||
|
AKEYCODE_SLASH = 76,
|
||||||
|
AKEYCODE_AT = 77,
|
||||||
|
AKEYCODE_NUM = 78,
|
||||||
|
AKEYCODE_HEADSETHOOK = 79,
|
||||||
|
AKEYCODE_FOCUS = 80,
|
||||||
|
AKEYCODE_PLUS = 81,
|
||||||
|
AKEYCODE_MENU = 82,
|
||||||
|
AKEYCODE_NOTIFICATION = 83,
|
||||||
|
AKEYCODE_SEARCH = 84,
|
||||||
|
AKEYCODE_MEDIA_PLAY_PAUSE = 85,
|
||||||
|
AKEYCODE_MEDIA_STOP = 86,
|
||||||
|
AKEYCODE_MEDIA_NEXT = 87,
|
||||||
|
AKEYCODE_MEDIA_PREVIOUS = 88,
|
||||||
|
AKEYCODE_MEDIA_REWIND = 89,
|
||||||
|
AKEYCODE_MEDIA_FAST_FORWARD = 90,
|
||||||
|
AKEYCODE_MUTE = 91,
|
||||||
|
AKEYCODE_PAGE_UP = 92,
|
||||||
|
AKEYCODE_PAGE_DOWN = 93,
|
||||||
|
AKEYCODE_PICTSYMBOLS = 94,
|
||||||
|
AKEYCODE_SWITCH_CHARSET = 95,
|
||||||
|
AKEYCODE_BUTTON_A = 96,
|
||||||
|
AKEYCODE_BUTTON_B = 97,
|
||||||
|
AKEYCODE_BUTTON_C = 98,
|
||||||
|
AKEYCODE_BUTTON_X = 99,
|
||||||
|
AKEYCODE_BUTTON_Y = 100,
|
||||||
|
AKEYCODE_BUTTON_Z = 101,
|
||||||
|
AKEYCODE_BUTTON_L1 = 102,
|
||||||
|
AKEYCODE_BUTTON_R1 = 103,
|
||||||
|
AKEYCODE_BUTTON_L2 = 104,
|
||||||
|
AKEYCODE_BUTTON_R2 = 105,
|
||||||
|
AKEYCODE_BUTTON_THUMBL = 106,
|
||||||
|
AKEYCODE_BUTTON_THUMBR = 107,
|
||||||
|
AKEYCODE_BUTTON_START = 108,
|
||||||
|
AKEYCODE_BUTTON_SELECT = 109,
|
||||||
|
AKEYCODE_BUTTON_MODE = 110,
|
||||||
|
AKEYCODE_ESCAPE = 111,
|
||||||
|
AKEYCODE_FORWARD_DEL = 112,
|
||||||
|
AKEYCODE_CTRL_LEFT = 113,
|
||||||
|
AKEYCODE_CTRL_RIGHT = 114,
|
||||||
|
AKEYCODE_CAPS_LOCK = 115,
|
||||||
|
AKEYCODE_SCROLL_LOCK = 116,
|
||||||
|
AKEYCODE_META_LEFT = 117,
|
||||||
|
AKEYCODE_META_RIGHT = 118,
|
||||||
|
AKEYCODE_FUNCTION = 119,
|
||||||
|
AKEYCODE_SYSRQ = 120,
|
||||||
|
AKEYCODE_BREAK = 121,
|
||||||
|
AKEYCODE_MOVE_HOME = 122,
|
||||||
|
AKEYCODE_MOVE_END = 123,
|
||||||
|
AKEYCODE_INSERT = 124,
|
||||||
|
AKEYCODE_FORWARD = 125,
|
||||||
|
AKEYCODE_MEDIA_PLAY = 126,
|
||||||
|
AKEYCODE_MEDIA_PAUSE = 127,
|
||||||
|
AKEYCODE_MEDIA_CLOSE = 128,
|
||||||
|
AKEYCODE_MEDIA_EJECT = 129,
|
||||||
|
AKEYCODE_MEDIA_RECORD = 130,
|
||||||
|
AKEYCODE_F1 = 131,
|
||||||
|
AKEYCODE_F2 = 132,
|
||||||
|
AKEYCODE_F3 = 133,
|
||||||
|
AKEYCODE_F4 = 134,
|
||||||
|
AKEYCODE_F5 = 135,
|
||||||
|
AKEYCODE_F6 = 136,
|
||||||
|
AKEYCODE_F7 = 137,
|
||||||
|
AKEYCODE_F8 = 138,
|
||||||
|
AKEYCODE_F9 = 139,
|
||||||
|
AKEYCODE_F10 = 140,
|
||||||
|
AKEYCODE_F11 = 141,
|
||||||
|
AKEYCODE_F12 = 142,
|
||||||
|
AKEYCODE_NUM_LOCK = 143,
|
||||||
|
AKEYCODE_NUMPAD_0 = 144,
|
||||||
|
AKEYCODE_NUMPAD_1 = 145,
|
||||||
|
AKEYCODE_NUMPAD_2 = 146,
|
||||||
|
AKEYCODE_NUMPAD_3 = 147,
|
||||||
|
AKEYCODE_NUMPAD_4 = 148,
|
||||||
|
AKEYCODE_NUMPAD_5 = 149,
|
||||||
|
AKEYCODE_NUMPAD_6 = 150,
|
||||||
|
AKEYCODE_NUMPAD_7 = 151,
|
||||||
|
AKEYCODE_NUMPAD_8 = 152,
|
||||||
|
AKEYCODE_NUMPAD_9 = 153,
|
||||||
|
AKEYCODE_NUMPAD_DIVIDE = 154,
|
||||||
|
AKEYCODE_NUMPAD_MULTIPLY = 155,
|
||||||
|
AKEYCODE_NUMPAD_SUBTRACT = 156,
|
||||||
|
AKEYCODE_NUMPAD_ADD = 157,
|
||||||
|
AKEYCODE_NUMPAD_DOT = 158,
|
||||||
|
AKEYCODE_NUMPAD_COMMA = 159,
|
||||||
|
AKEYCODE_NUMPAD_ENTER = 160,
|
||||||
|
AKEYCODE_NUMPAD_EQUALS = 161,
|
||||||
|
AKEYCODE_NUMPAD_LEFT_PAREN = 162,
|
||||||
|
AKEYCODE_NUMPAD_RIGHT_PAREN = 163,
|
||||||
|
AKEYCODE_VOLUME_MUTE = 164,
|
||||||
|
AKEYCODE_INFO = 165,
|
||||||
|
AKEYCODE_CHANNEL_UP = 166,
|
||||||
|
AKEYCODE_CHANNEL_DOWN = 167,
|
||||||
|
AKEYCODE_ZOOM_IN = 168,
|
||||||
|
AKEYCODE_ZOOM_OUT = 169,
|
||||||
|
AKEYCODE_TV = 170,
|
||||||
|
AKEYCODE_WINDOW = 171,
|
||||||
|
AKEYCODE_GUIDE = 172,
|
||||||
|
AKEYCODE_DVR = 173,
|
||||||
|
AKEYCODE_BOOKMARK = 174,
|
||||||
|
AKEYCODE_CAPTIONS = 175,
|
||||||
|
AKEYCODE_SETTINGS = 176,
|
||||||
|
AKEYCODE_TV_POWER = 177,
|
||||||
|
AKEYCODE_TV_INPUT = 178,
|
||||||
|
AKEYCODE_STB_POWER = 179,
|
||||||
|
AKEYCODE_STB_INPUT = 180,
|
||||||
|
AKEYCODE_AVR_POWER = 181,
|
||||||
|
AKEYCODE_AVR_INPUT = 182,
|
||||||
|
AKEYCODE_PROG_RED = 183,
|
||||||
|
AKEYCODE_PROG_GREEN = 184,
|
||||||
|
AKEYCODE_PROG_YELLOW = 185,
|
||||||
|
AKEYCODE_PROG_BLUE = 186,
|
||||||
|
AKEYCODE_APP_SWITCH = 187,
|
||||||
|
AKEYCODE_BUTTON_1 = 188,
|
||||||
|
AKEYCODE_BUTTON_2 = 189,
|
||||||
|
AKEYCODE_BUTTON_3 = 190,
|
||||||
|
AKEYCODE_BUTTON_4 = 191,
|
||||||
|
AKEYCODE_BUTTON_5 = 192,
|
||||||
|
AKEYCODE_BUTTON_6 = 193,
|
||||||
|
AKEYCODE_BUTTON_7 = 194,
|
||||||
|
AKEYCODE_BUTTON_8 = 195,
|
||||||
|
AKEYCODE_BUTTON_9 = 196,
|
||||||
|
AKEYCODE_BUTTON_10 = 197,
|
||||||
|
AKEYCODE_BUTTON_11 = 198,
|
||||||
|
AKEYCODE_BUTTON_12 = 199,
|
||||||
|
AKEYCODE_BUTTON_13 = 200,
|
||||||
|
AKEYCODE_BUTTON_14 = 201,
|
||||||
|
AKEYCODE_BUTTON_15 = 202,
|
||||||
|
AKEYCODE_BUTTON_16 = 203,
|
||||||
|
AKEYCODE_LANGUAGE_SWITCH = 204,
|
||||||
|
AKEYCODE_MANNER_MODE = 205,
|
||||||
|
AKEYCODE_3D_MODE = 206,
|
||||||
|
AKEYCODE_CONTACTS = 207,
|
||||||
|
AKEYCODE_CALENDAR = 208,
|
||||||
|
AKEYCODE_MUSIC = 209,
|
||||||
|
AKEYCODE_CALCULATOR = 210,
|
||||||
|
AKEYCODE_ZENKAKU_HANKAKU = 211,
|
||||||
|
AKEYCODE_EISU = 212,
|
||||||
|
AKEYCODE_MUHENKAN = 213,
|
||||||
|
AKEYCODE_HENKAN = 214,
|
||||||
|
AKEYCODE_KATAKANA_HIRAGANA = 215,
|
||||||
|
AKEYCODE_YEN = 216,
|
||||||
|
AKEYCODE_RO = 217,
|
||||||
|
AKEYCODE_KANA = 218,
|
||||||
|
AKEYCODE_ASSIST = 219,
|
||||||
|
AKEYCODE_BRIGHTNESS_DOWN = 220,
|
||||||
|
AKEYCODE_BRIGHTNESS_UP = 221,
|
||||||
|
AKEYCODE_MEDIA_AUDIO_TRACK = 222,
|
||||||
|
AKEYCODE_SLEEP = 223,
|
||||||
|
AKEYCODE_WAKEUP = 224,
|
||||||
|
AKEYCODE_PAIRING = 225,
|
||||||
|
AKEYCODE_MEDIA_TOP_MENU = 226,
|
||||||
|
AKEYCODE_11 = 227,
|
||||||
|
AKEYCODE_12 = 228,
|
||||||
|
AKEYCODE_LAST_CHANNEL = 229,
|
||||||
|
AKEYCODE_TV_DATA_SERVICE = 230,
|
||||||
|
AKEYCODE_VOICE_ASSIST = 231,
|
||||||
|
AKEYCODE_TV_RADIO_SERVICE = 232,
|
||||||
|
AKEYCODE_TV_TELETEXT = 233,
|
||||||
|
AKEYCODE_TV_NUMBER_ENTRY = 234,
|
||||||
|
AKEYCODE_TV_TERRESTRIAL_ANALOG = 235,
|
||||||
|
AKEYCODE_TV_TERRESTRIAL_DIGITAL = 236,
|
||||||
|
AKEYCODE_TV_SATELLITE = 237,
|
||||||
|
AKEYCODE_TV_SATELLITE_BS = 238,
|
||||||
|
AKEYCODE_TV_SATELLITE_CS = 239,
|
||||||
|
AKEYCODE_TV_SATELLITE_SERVICE = 240,
|
||||||
|
AKEYCODE_TV_NETWORK = 241,
|
||||||
|
AKEYCODE_TV_ANTENNA_CABLE = 242,
|
||||||
|
AKEYCODE_TV_INPUT_HDMI_1 = 243,
|
||||||
|
AKEYCODE_TV_INPUT_HDMI_2 = 244,
|
||||||
|
AKEYCODE_TV_INPUT_HDMI_3 = 245,
|
||||||
|
AKEYCODE_TV_INPUT_HDMI_4 = 246,
|
||||||
|
AKEYCODE_TV_INPUT_COMPOSITE_1 = 247,
|
||||||
|
AKEYCODE_TV_INPUT_COMPOSITE_2 = 248,
|
||||||
|
AKEYCODE_TV_INPUT_COMPONENT_1 = 249,
|
||||||
|
AKEYCODE_TV_INPUT_COMPONENT_2 = 250,
|
||||||
|
AKEYCODE_TV_INPUT_VGA_1 = 251,
|
||||||
|
AKEYCODE_TV_AUDIO_DESCRIPTION = 252,
|
||||||
|
AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP = 253,
|
||||||
|
AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN = 254,
|
||||||
|
AKEYCODE_TV_ZOOM_MODE = 255,
|
||||||
|
AKEYCODE_TV_CONTENTS_MENU = 256,
|
||||||
|
AKEYCODE_TV_MEDIA_CONTEXT_MENU = 257,
|
||||||
|
AKEYCODE_TV_TIMER_PROGRAMMING = 258,
|
||||||
|
AKEYCODE_HELP = 259,
|
||||||
|
AKEYCODE_NAVIGATE_PREVIOUS = 260,
|
||||||
|
AKEYCODE_NAVIGATE_NEXT = 261,
|
||||||
|
AKEYCODE_NAVIGATE_IN = 262,
|
||||||
|
AKEYCODE_NAVIGATE_OUT = 263,
|
||||||
|
AKEYCODE_STEM_PRIMARY = 264,
|
||||||
|
AKEYCODE_STEM_1 = 265,
|
||||||
|
AKEYCODE_STEM_2 = 266,
|
||||||
|
AKEYCODE_STEM_3 = 267,
|
||||||
|
AKEYCODE_DPAD_UP_LEFT = 268,
|
||||||
|
AKEYCODE_DPAD_DOWN_LEFT = 269,
|
||||||
|
AKEYCODE_DPAD_UP_RIGHT = 270,
|
||||||
|
AKEYCODE_DPAD_DOWN_RIGHT = 271,
|
||||||
|
AKEYCODE_MEDIA_SKIP_FORWARD = 272,
|
||||||
|
AKEYCODE_MEDIA_SKIP_BACKWARD = 273,
|
||||||
|
AKEYCODE_MEDIA_STEP_FORWARD = 274,
|
||||||
|
AKEYCODE_MEDIA_STEP_BACKWARD = 275,
|
||||||
|
AKEYCODE_SOFT_SLEEP = 276,
|
||||||
|
AKEYCODE_CUT = 277,
|
||||||
|
AKEYCODE_COPY = 278,
|
||||||
|
AKEYCODE_PASTE = 279,
|
||||||
|
AKEYCODE_SYSTEM_NAVIGATION_UP = 280,
|
||||||
|
AKEYCODE_SYSTEM_NAVIGATION_DOWN = 281,
|
||||||
|
AKEYCODE_SYSTEM_NAVIGATION_LEFT = 282,
|
||||||
|
AKEYCODE_SYSTEM_NAVIGATION_RIGHT = 283,
|
||||||
|
AKEYCODE_ALL_APPS = 284,
|
||||||
|
AKEYCODE_REFRESH = 285,
|
||||||
|
AKEYCODE_THUMBS_UP = 286,
|
||||||
|
AKEYCODE_THUMBS_DOWN = 287,
|
||||||
|
AKEYCODE_PROFILE_SWITCH = 288
|
||||||
|
};
|
||||||
|
|
||||||
|
// this sucks
|
||||||
|
#define AKEYCODE_ARROW_LEFT AKEYCODE_DPAD_LEFT
|
||||||
|
#define AKEYCODE_ARROW_RIGHT AKEYCODE_DPAD_RIGHT
|
||||||
|
|
||||||
|
#endif
|
||||||
30
compat/GL.hpp
Normal file
30
compat/GL.hpp
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef USE_OPENGL_2
|
||||||
|
|
||||||
|
#define xglBindBuffer glBindBuffer
|
||||||
|
#define xglBufferData glBufferData
|
||||||
|
#define xglGenBuffers glGenBuffers
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include "Utils.hpp"
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#include <GL/glu.h>
|
||||||
|
#include <GL/glext.h> // it'll include from a different dir, namely thirdparty/GL/glext.h
|
||||||
|
|
||||||
|
void xglInit();
|
||||||
|
bool xglInitted();
|
||||||
|
|
||||||
|
void xglBindBuffer(GLenum target, GLuint buffer);
|
||||||
|
void xglBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
|
||||||
|
void xglGenBuffers(GLsizei num, GLuint* buffers);
|
||||||
|
void xglDeleteBuffers(GLsizei num, GLuint* buffers);
|
||||||
|
void xglOrthof(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat nearpl, GLfloat farpl);
|
||||||
|
void xglSwapIntervalEXT(int interval);
|
||||||
|
|
||||||
|
// @TODO: not the right place, but er, it's ok
|
||||||
|
void drawArrayVT(GLuint buffer, int count, int stride);
|
||||||
|
void drawArrayVTC(GLuint buffer, int count, int stride);
|
||||||
|
|
||||||
|
#endif
|
||||||
69
compat/GLExt.cpp
Normal file
69
compat/GLExt.cpp
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#include "GL.hpp"
|
||||||
|
|
||||||
|
HWND GetHWND();
|
||||||
|
extern LPCTSTR g_GameTitle;
|
||||||
|
|
||||||
|
// this sucks... F* you Microsoft for making me do this hacky ass bullsh*t.
|
||||||
|
|
||||||
|
PFNGLBINDBUFFERPROC p_glBindBuffer;
|
||||||
|
PFNGLBUFFERDATAPROC p_glBufferData;
|
||||||
|
PFNGLGENBUFFERSPROC p_glGenBuffers;
|
||||||
|
PFNGLDELETEBUFFERSPROC p_glDeleteBuffers;
|
||||||
|
|
||||||
|
// this is stupidly hacky
|
||||||
|
typedef BOOL(WINAPI* PFNWGLSWAPINTERVALEXTPROC) (int interval);
|
||||||
|
|
||||||
|
PFNWGLSWAPINTERVALEXTPROC p_wglSwapIntervalEXT;
|
||||||
|
|
||||||
|
bool xglInitted()
|
||||||
|
{
|
||||||
|
return p_glBindBuffer && p_glBufferData && p_glGenBuffers && p_glDeleteBuffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xglInit()
|
||||||
|
{
|
||||||
|
p_glBindBuffer = (PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer");
|
||||||
|
p_glBufferData = (PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData");
|
||||||
|
p_glGenBuffers = (PFNGLGENBUFFERSPROC)wglGetProcAddress("glGenBuffers");
|
||||||
|
p_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)wglGetProcAddress("glDeleteBuffers");
|
||||||
|
|
||||||
|
p_wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
|
||||||
|
|
||||||
|
if (!xglInitted())
|
||||||
|
{
|
||||||
|
MessageBox(GetHWND(), TEXT("Error initializing GL extensions. Update your graphics drivers!"), g_GameTitle, MB_OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void xglBindBuffer(GLenum target, GLuint buffer)
|
||||||
|
{
|
||||||
|
p_glBindBuffer(target, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xglBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
|
||||||
|
{
|
||||||
|
p_glBufferData(target, size, data, usage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xglGenBuffers(GLsizei num, GLuint* buffers)
|
||||||
|
{
|
||||||
|
p_glGenBuffers(num, buffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xglDeleteBuffers(GLsizei num, GLuint* buffers)
|
||||||
|
{
|
||||||
|
p_glDeleteBuffers(num, buffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xglOrthof(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat nearpl, GLfloat farpl)
|
||||||
|
{
|
||||||
|
return glOrtho(GLdouble(left), GLdouble(right), GLdouble(bottom), GLfloat(top), GLdouble(nearpl), GLdouble(farpl));
|
||||||
|
}
|
||||||
|
|
||||||
|
void xglSwapIntervalEXT(int interval)
|
||||||
|
{
|
||||||
|
if (!p_wglSwapIntervalEXT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
p_wglSwapIntervalEXT(interval);
|
||||||
|
}
|
||||||
1
compat/readme.txt
Normal file
1
compat/readme.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
This folder contains compatibility crap since Microsoft never updated from OpenGL V1.2.
|
||||||
BIN
screenshots/ingame.png
Normal file
BIN
screenshots/ingame.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 278 KiB |
BIN
screenshots/inventory.png
Normal file
BIN
screenshots/inventory.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 270 KiB |
BIN
screenshots/loading.png
Normal file
BIN
screenshots/loading.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
BIN
screenshots/pause_screen.png
Normal file
BIN
screenshots/pause_screen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 158 KiB |
BIN
screenshots/title_screen.png
Normal file
BIN
screenshots/title_screen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
61
source/App/App.cpp
Normal file
61
source/App/App.cpp
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/********************************************************************
|
||||||
|
Minecraft: Pocket Edition - Decompilation Project
|
||||||
|
Copyright (C) 2023 iProgramInCpp
|
||||||
|
|
||||||
|
App.cpp
|
||||||
|
|
||||||
|
The following code is licensed under the following license:
|
||||||
|
< no license yet :( >
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include "App.hpp"
|
||||||
|
|
||||||
|
void App::destroy()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::draw()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool App::handleBack(bool b)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::init()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::loadState(void* a2, int a3)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
AppPlatform* App::platform()
|
||||||
|
{
|
||||||
|
return m_pPlatform;
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::quit()
|
||||||
|
{
|
||||||
|
m_bWantToQuit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool App::wantToQuit()
|
||||||
|
{
|
||||||
|
return m_bWantToQuit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::saveState(void**, int)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::update()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
40
source/App/App.hpp
Normal file
40
source/App/App.hpp
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/********************************************************************
|
||||||
|
Minecraft: Pocket Edition - Decompilation Project
|
||||||
|
Copyright (C) 2023 iProgramInCpp
|
||||||
|
|
||||||
|
App.hpp
|
||||||
|
|
||||||
|
The following code is licensed under the following license:
|
||||||
|
< no license yet :( >
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AppPlatform.hpp"
|
||||||
|
|
||||||
|
class App
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
void destroy();
|
||||||
|
void draw();
|
||||||
|
virtual bool handleBack(bool);
|
||||||
|
virtual void init();
|
||||||
|
void loadState(void*, int);
|
||||||
|
AppPlatform* platform();
|
||||||
|
void quit();
|
||||||
|
void saveState(void**, int);
|
||||||
|
virtual void update();
|
||||||
|
bool wantToQuit();
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool m_bWantToQuit = false;
|
||||||
|
|
||||||
|
// don't know what these are ...
|
||||||
|
int field_8;
|
||||||
|
int field_C;
|
||||||
|
int field_10;
|
||||||
|
|
||||||
|
AppPlatform* m_pPlatform = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
122
source/App/AppPlatform.cpp
Normal file
122
source/App/AppPlatform.cpp
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/********************************************************************
|
||||||
|
Minecraft: Pocket Edition - Decompilation Project
|
||||||
|
Copyright (C) 2023 iProgramInCpp
|
||||||
|
|
||||||
|
AppPlatform.cpp
|
||||||
|
|
||||||
|
The following code is licensed under the following license:
|
||||||
|
< no license yet :( >
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include "AppPlatform.hpp"
|
||||||
|
#include "Utils.hpp"
|
||||||
|
|
||||||
|
void AppPlatform::_tick()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPlatform::buyGame()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int AppPlatform::checkLicense()
|
||||||
|
{
|
||||||
|
return 0; // assume no license
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPlatform::createUserInput()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPlatform::finish()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AppPlatform::getDateString(int time)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ??? AppPlatform::getOptionStrings()
|
||||||
|
|
||||||
|
int AppPlatform::getScreenWidth() const
|
||||||
|
{
|
||||||
|
return C_DEFAULT_SCREEN_WIDTH; // default rez of the XPERIA PLAY?
|
||||||
|
}
|
||||||
|
|
||||||
|
int AppPlatform::getScreenHeight() const
|
||||||
|
{
|
||||||
|
return C_DEFAULT_SCREEN_HEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> AppPlatform::getUserInput()
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
int AppPlatform::getUserInputStatus()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AppPlatform::hasBuyButtonWhenInvalidLicense()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// void AppPlatform::loadTexture(const std::string&, bool);
|
||||||
|
|
||||||
|
void AppPlatform::saveScreenshot(const std::string&, int, int)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPlatform::showDialog(eDialogType type)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPlatform::uploadPlatformDependentData(int, void*)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Texture AppPlatform::loadTexture(const std::string&, bool)
|
||||||
|
{
|
||||||
|
return Texture(0, 0, nullptr, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> AppPlatform::getOptionStrings()
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPlatform::recenterMouse()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPlatform::setMouseGrabbed(bool b)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPlatform::getMouseDiff(int& x, int& y)
|
||||||
|
{
|
||||||
|
x = y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPlatform::clearDiff()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AppPlatform::shiftPressed()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
60
source/App/AppPlatform.hpp
Normal file
60
source/App/AppPlatform.hpp
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/********************************************************************
|
||||||
|
Minecraft: Pocket Edition - Decompilation Project
|
||||||
|
Copyright (C) 2023 iProgramInCpp
|
||||||
|
|
||||||
|
AppPlatform.hpp
|
||||||
|
|
||||||
|
The following code is licensed under the following license:
|
||||||
|
< no license yet :( >
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Texture.hpp"
|
||||||
|
|
||||||
|
class AppPlatform
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum eDialogType
|
||||||
|
{
|
||||||
|
DLG_CREATE_WORLD = 1,
|
||||||
|
DLG_CHAT,
|
||||||
|
DLG_OPTIONS,
|
||||||
|
DLG_RENAME_MP_WORLD,
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void buyGame();
|
||||||
|
virtual int checkLicense();
|
||||||
|
virtual void createUserInput();
|
||||||
|
virtual void finish();
|
||||||
|
virtual std::string getDateString(int);
|
||||||
|
virtual int getScreenWidth() const;
|
||||||
|
virtual int getScreenHeight() const;
|
||||||
|
virtual std::vector<std::string> getUserInput();
|
||||||
|
virtual int getUserInputStatus();
|
||||||
|
virtual bool hasBuyButtonWhenInvalidLicense();
|
||||||
|
virtual void saveScreenshot(const std::string&, int, int);
|
||||||
|
virtual void showDialog(eDialogType);
|
||||||
|
virtual void uploadPlatformDependentData(int, void*);
|
||||||
|
virtual Texture loadTexture(const std::string&, bool);
|
||||||
|
virtual std::vector<std::string> getOptionStrings();
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
// Also add these to allow proper turning within the game.
|
||||||
|
virtual void recenterMouse();
|
||||||
|
virtual void setMouseGrabbed(bool b);
|
||||||
|
virtual void getMouseDiff(int& x, int& y);
|
||||||
|
virtual void clearDiff();
|
||||||
|
// Also add this to allow proper text input within the game.
|
||||||
|
virtual bool shiftPressed();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void _tick();
|
||||||
|
};
|
||||||
|
|
||||||
244
source/App/AppPlatform_windows.cpp
Normal file
244
source/App/AppPlatform_windows.cpp
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
/********************************************************************
|
||||||
|
Minecraft: Pocket Edition - Decompilation Project
|
||||||
|
Copyright (C) 2023 iProgramInCpp
|
||||||
|
|
||||||
|
AppPlatform_windows.hpp
|
||||||
|
|
||||||
|
The following code is licensed under the following license:
|
||||||
|
< no license yet :( >
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include "AppPlatform_windows.hpp"
|
||||||
|
#include "Mouse.hpp"
|
||||||
|
|
||||||
|
#include "thirdparty/stb_image.h"
|
||||||
|
#include "thirdparty/stb_image_write.h"
|
||||||
|
|
||||||
|
extern LPCTSTR g_GameTitle;
|
||||||
|
|
||||||
|
void AppPlatform_windows::initConsts()
|
||||||
|
{
|
||||||
|
// just assume an 854x480 window for now:
|
||||||
|
m_ScreenWidth = C_DEFAULT_SCREEN_WIDTH;
|
||||||
|
m_ScreenHeight = C_DEFAULT_SCREEN_HEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AppPlatform_windows::checkLicense()
|
||||||
|
{
|
||||||
|
// we own the game!!
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPlatform_windows::buyGame()
|
||||||
|
{
|
||||||
|
MessageBox(GetHWND(), TEXT("Buying the game!"), g_GameTitle, MB_OK | MB_ICONINFORMATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPlatform_windows::saveScreenshot(const std::string& fileName, int width, int height)
|
||||||
|
{
|
||||||
|
int npixels = width * height;
|
||||||
|
uint32_t* pixels = new uint32_t[npixels];
|
||||||
|
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||||
|
|
||||||
|
stbi_flip_vertically_on_write(true);
|
||||||
|
stbi_write_png(fileName.c_str(), width, height, 4, pixels, width * 4);
|
||||||
|
|
||||||
|
delete[] pixels;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AppPlatform_windows::getScreenWidth() const
|
||||||
|
{
|
||||||
|
return m_ScreenWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AppPlatform_windows::getScreenHeight() const
|
||||||
|
{
|
||||||
|
return m_ScreenHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> AppPlatform_windows::getUserInput()
|
||||||
|
{
|
||||||
|
return m_UserInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AppPlatform_windows::getUserInputStatus()
|
||||||
|
{
|
||||||
|
return m_UserInputStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPlatform_windows::createUserInput()
|
||||||
|
{
|
||||||
|
m_UserInput.clear();
|
||||||
|
m_UserInputStatus = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPlatform_windows::showDialog(eDialogType type)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AppPlatform_windows::getDateString(int time)
|
||||||
|
{
|
||||||
|
time_t tt = time;
|
||||||
|
struct tm t;
|
||||||
|
// using the _s variant. For a different platform there's gmtime_r. This is not directly portable however.
|
||||||
|
gmtime_s(&t, &tt);
|
||||||
|
|
||||||
|
//format it with strftime
|
||||||
|
char buf[2048];
|
||||||
|
strftime(buf, sizeof buf, "%b %d %Y %H:%M:%S", &t);
|
||||||
|
//strftime(buf, sizeof buf, "%a %b %d %H:%M:%S %Z %Y", &t);
|
||||||
|
|
||||||
|
return std::string(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture AppPlatform_windows::loadTexture(const std::string& str, bool b)
|
||||||
|
{
|
||||||
|
std::string realPath = str;
|
||||||
|
if (realPath.size() && realPath[0] == '/')
|
||||||
|
// trim it off
|
||||||
|
realPath = realPath.substr(1);
|
||||||
|
|
||||||
|
realPath = "assets/" + realPath;
|
||||||
|
|
||||||
|
FILE* f = fopen(realPath.c_str(), "rb");
|
||||||
|
if (!f)
|
||||||
|
{
|
||||||
|
LogMsg("File %s couldn't be opened", realPath.c_str());
|
||||||
|
return Texture(0, 0, nullptr, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int width = 0, height = 0, channels = 0;
|
||||||
|
|
||||||
|
stbi_uc* img = stbi_load_from_file(f, &width, &height, &channels, STBI_rgb_alpha);
|
||||||
|
if (!img)
|
||||||
|
{
|
||||||
|
LogMsg("File %s couldn't be loaded via stb_image", realPath.c_str());
|
||||||
|
fclose(f);
|
||||||
|
return Texture(0, 0, nullptr, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
return Texture(width, height, (uint32_t*)img, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> AppPlatform_windows::getOptionStrings()
|
||||||
|
{
|
||||||
|
std::vector<std::string> o;
|
||||||
|
|
||||||
|
o.push_back("mp_username");
|
||||||
|
o.push_back("iProgramInCpp");
|
||||||
|
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPlatform_windows::setScreenSize(int width, int height)
|
||||||
|
{
|
||||||
|
m_ScreenWidth = width;
|
||||||
|
m_ScreenHeight = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPlatform_windows::recenterMouse()
|
||||||
|
{
|
||||||
|
// only recenter the mouse if it's grabbed
|
||||||
|
if (!m_bGrabbedMouse)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If we aren't the foreground window, return
|
||||||
|
if (GetForegroundWindow() != GetHWND())
|
||||||
|
{
|
||||||
|
m_bWasUnfocused = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
POINT oldPos{ 0, 0 };
|
||||||
|
GetCursorPos(&oldPos);
|
||||||
|
|
||||||
|
RECT rect;
|
||||||
|
GetClientRect(GetHWND(), &rect);
|
||||||
|
|
||||||
|
POINT offs { m_ScreenWidth / 2, m_ScreenHeight / 2 };
|
||||||
|
ClientToScreen(GetHWND(), &offs);
|
||||||
|
|
||||||
|
SetCursorPos(offs.x, offs.y);
|
||||||
|
|
||||||
|
// Note. The only reason we do it this way instead of
|
||||||
|
// using the Mouse class is because, after SetCursorPos,
|
||||||
|
// we'll get an event on our window telling us "hey, the
|
||||||
|
// user has moved their cursor back to the center! Move
|
||||||
|
// the camera back as well", causing a camera that just
|
||||||
|
// refuses to move
|
||||||
|
|
||||||
|
// If we were unfocused last frame, ignore the diff data we have.
|
||||||
|
if (!m_bWasUnfocused)
|
||||||
|
{
|
||||||
|
m_MouseDiffX -= offs.x - oldPos.x;
|
||||||
|
m_MouseDiffY -= offs.y - oldPos.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bWasUnfocused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPlatform_windows::setMouseGrabbed(bool b)
|
||||||
|
{
|
||||||
|
// only if stuff has changed do we update
|
||||||
|
if (m_bGrabbedMouse == b)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_bGrabbedMouse = b;
|
||||||
|
|
||||||
|
if (!b)
|
||||||
|
{
|
||||||
|
//show the cursor
|
||||||
|
ShowCursor(TRUE);
|
||||||
|
|
||||||
|
//unconfine it
|
||||||
|
ClipCursor(NULL);
|
||||||
|
|
||||||
|
clearDiff();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//hide the cursor
|
||||||
|
ShowCursor(FALSE);
|
||||||
|
|
||||||
|
//confine it to our client area
|
||||||
|
RECT rect;
|
||||||
|
GetClientRect(GetHWND(), &rect);
|
||||||
|
|
||||||
|
POINT offs{ 0, 0 };
|
||||||
|
ClientToScreen(GetHWND(), &offs);
|
||||||
|
rect.left += offs.x;
|
||||||
|
rect.top += offs.y;
|
||||||
|
rect.right += offs.x;
|
||||||
|
rect.bottom += offs.y;
|
||||||
|
|
||||||
|
ClipCursor(&rect);
|
||||||
|
|
||||||
|
// set the cursor pos to the middle of the screen
|
||||||
|
recenterMouse();
|
||||||
|
|
||||||
|
clearDiff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPlatform_windows::getMouseDiff(int& x, int& y)
|
||||||
|
{
|
||||||
|
x = m_MouseDiffX;
|
||||||
|
y = m_MouseDiffY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPlatform_windows::clearDiff()
|
||||||
|
{
|
||||||
|
m_MouseDiffX = m_MouseDiffY = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AppPlatform_windows::shiftPressed()
|
||||||
|
{
|
||||||
|
return m_bShiftPressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppPlatform_windows::setShiftPressed(bool b)
|
||||||
|
{
|
||||||
|
m_bShiftPressed = b;
|
||||||
|
}
|
||||||
67
source/App/AppPlatform_windows.hpp
Normal file
67
source/App/AppPlatform_windows.hpp
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/********************************************************************
|
||||||
|
Minecraft: Pocket Edition - Decompilation Project
|
||||||
|
Copyright (C) 2023 iProgramInCpp
|
||||||
|
|
||||||
|
AppPlatform_windows.hpp
|
||||||
|
|
||||||
|
The following code is licensed under the following license:
|
||||||
|
< no license yet :( >
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "compat/GL.hpp"
|
||||||
|
#include <ctime>
|
||||||
|
#include "Utils.hpp"
|
||||||
|
#include "AppPlatform.hpp"
|
||||||
|
|
||||||
|
#ifdef ORIGINAL_CODE
|
||||||
|
#error "This isn't original code. You probably shouldn't try to compile this"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// note: probably won't add AppPlatform_android until it's time
|
||||||
|
// to build an Android app
|
||||||
|
|
||||||
|
class AppPlatform_windows : public AppPlatform
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void initConsts();
|
||||||
|
void buyGame() override;
|
||||||
|
void saveScreenshot(const std::string& fileName, int width, int height) override;
|
||||||
|
int checkLicense() override;
|
||||||
|
void createUserInput() override;
|
||||||
|
std::vector<std::string> getUserInput() override;
|
||||||
|
int getUserInputStatus() override;
|
||||||
|
int getScreenWidth() const override;
|
||||||
|
int getScreenHeight() const override;
|
||||||
|
void showDialog(eDialogType) override;
|
||||||
|
std::string getDateString(int time) override;
|
||||||
|
Texture loadTexture(const std::string& str, bool b) override;
|
||||||
|
std::vector<std::string> getOptionStrings() override;
|
||||||
|
|
||||||
|
// Also add these to allow proper turning within the game.
|
||||||
|
void recenterMouse() override;
|
||||||
|
void setMouseGrabbed(bool b) override;
|
||||||
|
void getMouseDiff(int& x, int& y) override;
|
||||||
|
void clearDiff() override;
|
||||||
|
|
||||||
|
// Also add these to allow proper text input within the game.
|
||||||
|
bool shiftPressed() override;
|
||||||
|
void setShiftPressed(bool b);
|
||||||
|
|
||||||
|
void setScreenSize(int width, int height);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_ScreenWidth;
|
||||||
|
int m_ScreenHeight;
|
||||||
|
|
||||||
|
std::vector<std::string> m_UserInput;
|
||||||
|
int m_UserInputStatus = -1;
|
||||||
|
|
||||||
|
bool m_bGrabbedMouse = false;
|
||||||
|
bool m_bWasUnfocused = false;
|
||||||
|
bool m_bShiftPressed = false;
|
||||||
|
|
||||||
|
int m_MouseDiffX = 0, m_MouseDiffY = 0;
|
||||||
|
};
|
||||||
|
|
||||||
843
source/App/Minecraft.cpp
Normal file
843
source/App/Minecraft.cpp
Normal file
@@ -0,0 +1,843 @@
|
|||||||
|
#include "Minecraft.hpp"
|
||||||
|
#include "PauseScreen.hpp"
|
||||||
|
#include "StartMenuScreen.hpp"
|
||||||
|
#include "RenameMPLevelScreen.hpp"
|
||||||
|
#include "ServerSideNetworkHandler.hpp"
|
||||||
|
#include "ClientSideNetworkHandler.hpp"
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
#include "MouseTurnInput.hpp"
|
||||||
|
#else
|
||||||
|
#include "ControllerTurnInput.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// note: Nothing changes these, so it'll think we're always running at 854x480 even if not
|
||||||
|
int Minecraft::width = C_DEFAULT_SCREEN_WIDTH;
|
||||||
|
int Minecraft::height = C_DEFAULT_SCREEN_HEIGHT;
|
||||||
|
bool Minecraft::useAmbientOcclusion = false;
|
||||||
|
int Minecraft::customDebugId = 0;
|
||||||
|
|
||||||
|
//@HUH: For the demo, this is defined as TRUE.
|
||||||
|
//@HUH: deadmau5 had camera cheats? That's interesting.
|
||||||
|
const bool Minecraft::DEADMAU5_CAMERA_CHEATS = true;
|
||||||
|
|
||||||
|
const char* Minecraft::progressMessages[] =
|
||||||
|
{
|
||||||
|
"Locating server",
|
||||||
|
"Building terrain",
|
||||||
|
"Preparing",
|
||||||
|
"Saving chunks",
|
||||||
|
};
|
||||||
|
|
||||||
|
Minecraft::Minecraft() : m_gui(this)
|
||||||
|
{
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
m_pTurnInput = new MouseTurnInput(this);
|
||||||
|
#else
|
||||||
|
m_pTurnInput = new ControllerTurnInput;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_pRakNetInstance = new RakNetInstance;
|
||||||
|
|
||||||
|
m_pSoundEngine = new SoundEngine;
|
||||||
|
m_pSoundEngine->init(&m_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Minecraft::getLicenseId()
|
||||||
|
{
|
||||||
|
if (m_licenseID < 0)
|
||||||
|
m_licenseID = m_pPlatform->checkLicense();
|
||||||
|
|
||||||
|
return m_licenseID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::releaseMouse()
|
||||||
|
{
|
||||||
|
if (!m_bGrabbedMouse)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_pLocalPlayer)
|
||||||
|
m_pLocalPlayer->m_pKeyboardInput->releaseAllKeys();
|
||||||
|
|
||||||
|
m_bGrabbedMouse = false;
|
||||||
|
|
||||||
|
platform()->setMouseGrabbed(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::grabMouse()
|
||||||
|
{
|
||||||
|
if (m_bGrabbedMouse)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_bGrabbedMouse = true;
|
||||||
|
field_D20 = 0.0f;
|
||||||
|
field_D24 = 0.0f;
|
||||||
|
setScreen(nullptr);
|
||||||
|
|
||||||
|
platform()->setMouseGrabbed(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::setScreen(Screen* pScreen)
|
||||||
|
{
|
||||||
|
if (field_DB0)
|
||||||
|
{
|
||||||
|
field_DB1 = 1;
|
||||||
|
m_pScreen = pScreen; //@BUG: potential memory leak?
|
||||||
|
}
|
||||||
|
else if (!pScreen || !pScreen->isErrorScreen())
|
||||||
|
{
|
||||||
|
if (field_D14)
|
||||||
|
{
|
||||||
|
field_D14->removed();
|
||||||
|
delete field_D14;
|
||||||
|
}
|
||||||
|
|
||||||
|
field_D14 = pScreen;
|
||||||
|
if (pScreen)
|
||||||
|
{
|
||||||
|
releaseMouse();
|
||||||
|
pScreen->init(this, int(width * Gui::InvGuiScale), int(height * Gui::InvGuiScale));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
grabMouse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//@BUG: memory leak?
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// @NOTE: Added this to not leak screens. A good idea unless you use the screen instance after calling setScreen()
|
||||||
|
delete pScreen;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::onGraphicsReset()
|
||||||
|
{
|
||||||
|
m_pTextures->clear();
|
||||||
|
m_pFont->onGraphicsReset();
|
||||||
|
|
||||||
|
if (m_pLevelRenderer)
|
||||||
|
m_pLevelRenderer->onGraphicsReset();
|
||||||
|
|
||||||
|
if (m_pGameRenderer)
|
||||||
|
m_pGameRenderer->onGraphicsReset();
|
||||||
|
|
||||||
|
EntityRenderDispatcher::getInstance()->onGraphicsReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::reloadOptions()
|
||||||
|
{
|
||||||
|
m_options.update(platform()->getOptionStrings());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Minecraft::isLevelGenerated()
|
||||||
|
{
|
||||||
|
if (m_pLevel)
|
||||||
|
return !m_bPreparingLevel;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Minecraft::isOnline()
|
||||||
|
{
|
||||||
|
return m_pNetEventCallback != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Minecraft::isOnlineClient()
|
||||||
|
{
|
||||||
|
if (!m_pLevel)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return m_pLevel->field_11;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::handleMouseDown(int type, bool b)
|
||||||
|
{
|
||||||
|
if (!m_pGameMode->field_8 && (type != 1 || this->field_DA4 <= 0))
|
||||||
|
{
|
||||||
|
if (b && type == 1 && m_hitResult.m_hitType == HitResult::AABB && !m_hitResult.m_bUnk24)
|
||||||
|
{
|
||||||
|
m_pGameMode->continueDestroyBlock(m_hitResult.m_tileX, m_hitResult.m_tileY, m_hitResult.m_tileZ, m_hitResult.m_hitSide);
|
||||||
|
m_pParticleEngine->crack(m_hitResult.m_tileX, m_hitResult.m_tileY, m_hitResult.m_tileZ, m_hitResult.m_hitSide);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_pGameMode->stopDestroyBlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::handleMouseClick(int type)
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
|
||||||
|
HitResult& hr = m_hitResult;
|
||||||
|
|
||||||
|
// @TODO: fix goto hell
|
||||||
|
if (type == 1)
|
||||||
|
{
|
||||||
|
if (field_DA4 > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_pLocalPlayer->swing();
|
||||||
|
|
||||||
|
if (m_hitResult.m_hitType != HitResult::NONE)
|
||||||
|
goto label_3;
|
||||||
|
|
||||||
|
label_9:
|
||||||
|
if (type != 1)
|
||||||
|
goto label_5;
|
||||||
|
|
||||||
|
if (!m_pGameMode->isCreativeType())
|
||||||
|
field_DA4 = 10;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_hitResult.m_hitType == HitResult::NONE)
|
||||||
|
goto label_9;
|
||||||
|
|
||||||
|
label_3:
|
||||||
|
if (m_hitResult.m_hitType != HitResult::ENTITY)
|
||||||
|
{
|
||||||
|
if (m_hitResult.m_hitType != HitResult::AABB)
|
||||||
|
goto label_5;
|
||||||
|
|
||||||
|
// @NOTE: extra scope to avoid error
|
||||||
|
{
|
||||||
|
Tile* pTile = Tile::tiles[m_pLevel->getTile(hr.m_tileX, hr.m_tileY, hr.m_tileZ)];
|
||||||
|
|
||||||
|
if (type == 1)
|
||||||
|
{
|
||||||
|
if (pTile)
|
||||||
|
{
|
||||||
|
// @BUG: This is only done on the client side.
|
||||||
|
m_pLevel->extinguishFire(hr.m_tileX, hr.m_tileY, hr.m_tileZ, hr.m_hitSide);
|
||||||
|
|
||||||
|
if (pTile != Tile::unbreakable || m_pLocalPlayer->field_B94 > 99 && !hr.m_bUnk24)
|
||||||
|
{
|
||||||
|
m_pGameMode->startDestroyBlock(hr.m_tileX, hr.m_tileY, hr.m_tileZ, hr.m_hitSide);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemInstance item(m_pLocalPlayer->m_pInventory->getSelectedItemId(), 999, 0);
|
||||||
|
if (m_pGameMode->useItemOn(m_pLocalPlayer, m_pLevel, item.m_itemID < 0 ? nullptr : &item, hr.m_tileX, hr.m_tileY, hr.m_tileZ, hr.m_hitSide))
|
||||||
|
{
|
||||||
|
m_pLocalPlayer->swing();
|
||||||
|
if (!isOnline())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (item.m_itemID > C_MAX_TILES || item.m_itemID < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int dx = hr.m_tileX, dz = hr.m_tileZ;
|
||||||
|
uint8_t dy = uint8_t(hr.m_tileY);
|
||||||
|
|
||||||
|
if (m_pLevel->getTile(hr.m_tileX, hr.m_tileY, hr.m_tileZ) != Tile::topSnow->m_ID)
|
||||||
|
{
|
||||||
|
switch (hr.m_hitSide)
|
||||||
|
{
|
||||||
|
case DIR_YNEG: dy--; break;
|
||||||
|
case DIR_YPOS: dy++; break;
|
||||||
|
case DIR_ZNEG: dz--; break;
|
||||||
|
case DIR_ZPOS: dz++; break;
|
||||||
|
case DIR_XNEG: dx--; break;
|
||||||
|
case DIR_XPOS: dx++; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pRakNetInstance->send(new PlaceBlockPacket(m_pLocalPlayer->m_EntityID, dx, dy, dz, uint8_t(item.m_itemID), uint8_t(hr.m_hitSide)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
label_5:
|
||||||
|
if (type != 2)
|
||||||
|
return;
|
||||||
|
goto label_15;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == 1)
|
||||||
|
{
|
||||||
|
m_pGameMode->attack(m_pLocalPlayer, hr.m_pEnt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == 2)
|
||||||
|
{
|
||||||
|
a = hr.m_pEnt->interactPreventDefault();
|
||||||
|
m_pGameMode->interact(m_pLocalPlayer, hr.m_pEnt);
|
||||||
|
if (!a)
|
||||||
|
{
|
||||||
|
label_15:
|
||||||
|
int id = m_pLocalPlayer->m_pInventory->getSelectedItemId();
|
||||||
|
if (id >= 0)
|
||||||
|
{
|
||||||
|
ItemInstance item(m_pLocalPlayer->m_pInventory->getSelectedItemId(), 999, 0);
|
||||||
|
if (m_pGameMode->useItem(m_pLocalPlayer, m_pLevel, &item))
|
||||||
|
m_pGameRenderer->m_pItemInHandRenderer->itemUsed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::tickInput()
|
||||||
|
{
|
||||||
|
if (field_D14)
|
||||||
|
{
|
||||||
|
if (!field_D14->field_10)
|
||||||
|
{
|
||||||
|
field_DB0 = 1;
|
||||||
|
field_D14->updateEvents();
|
||||||
|
field_DB0 = false;
|
||||||
|
if (field_DB1)
|
||||||
|
{
|
||||||
|
setScreen(m_pScreen);
|
||||||
|
m_pScreen = NULL;
|
||||||
|
field_DB1 = false;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_pLocalPlayer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool bIsInGUI = m_gui.isInside(Mouse::_x, Mouse::_y);
|
||||||
|
|
||||||
|
while (Mouse::_index + 1 < Mouse::_inputs.size())
|
||||||
|
{
|
||||||
|
Mouse::_index++;
|
||||||
|
|
||||||
|
if (getTimeMs() - field_2B4 > 200)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (Mouse::_buttonStates[1])
|
||||||
|
m_gui.handleClick(1, Mouse::_x, Mouse::_y);
|
||||||
|
|
||||||
|
if (!bIsInGUI && m_options.field_19)
|
||||||
|
{
|
||||||
|
MouseInput& input = Mouse::_inputs[Mouse::_index];
|
||||||
|
|
||||||
|
if (input.field_0 == 1 && input.field_4 == 1)
|
||||||
|
{
|
||||||
|
handleMouseClick(1);
|
||||||
|
field_DAC = field_DA8;
|
||||||
|
}
|
||||||
|
if (input.field_0 == 2 && input.field_4 == 1)
|
||||||
|
{
|
||||||
|
handleMouseClick(2);
|
||||||
|
field_DAC = field_DA8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Keyboard::_index + 1 < Keyboard::_inputs.size())
|
||||||
|
{
|
||||||
|
Keyboard::_index++;
|
||||||
|
Keyboard::Input& input = Keyboard::_inputs[Keyboard::_index];
|
||||||
|
|
||||||
|
int keyCode = input.field_4;
|
||||||
|
bool bPressed = input.field_0 == 1;
|
||||||
|
|
||||||
|
m_pLocalPlayer->m_pKeyboardInput->setKey(keyCode, bPressed);
|
||||||
|
|
||||||
|
if (bPressed)
|
||||||
|
{
|
||||||
|
m_gui.handleKeyPressed(keyCode);
|
||||||
|
|
||||||
|
int index = keyCode - '1';
|
||||||
|
if (index <= 8 && index >= 0)
|
||||||
|
{
|
||||||
|
m_pLocalPlayer->m_pInventory->selectSlot(index);
|
||||||
|
}
|
||||||
|
else if (keyCode == AKEYCODE_SEARCH)
|
||||||
|
{
|
||||||
|
m_options.field_23D ^= 1;
|
||||||
|
}
|
||||||
|
else if (keyCode == AKEYCODE_MENU)
|
||||||
|
{
|
||||||
|
pauseGame();
|
||||||
|
}
|
||||||
|
#ifdef ENH_ALLOW_AO
|
||||||
|
else if (keyCode == AKEYCODE_F4)
|
||||||
|
{
|
||||||
|
// Toggle ambient occlusion.
|
||||||
|
m_options.field_18 ^= 1;
|
||||||
|
Minecraft::useAmbientOcclusion = m_options.field_18;
|
||||||
|
m_pLevelRenderer->allChanged();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_options.field_19)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (getTimeMs() - field_2B4 <= 200)
|
||||||
|
{
|
||||||
|
if (m_options.m_keyBinds[Options::DESTROY].value == keyCode && bPressed)
|
||||||
|
handleMouseClick(1);
|
||||||
|
if (m_options.m_keyBinds[Options::PLACE].value == keyCode && bPressed)
|
||||||
|
handleMouseClick(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @TODO: fix gotos
|
||||||
|
bool v12 = false;
|
||||||
|
|
||||||
|
if (m_options.field_19)
|
||||||
|
{
|
||||||
|
if (!Mouse::_buttonStates[1] || bIsInGUI)
|
||||||
|
goto label_12;
|
||||||
|
}
|
||||||
|
else if (Keyboard::_states[m_options.m_keyBinds[Options::DESTROY].value] != 1)
|
||||||
|
{
|
||||||
|
goto label_12;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!field_D14 && (field_DA8 - field_DAC) >= (m_timer.field_10 * 0.25f))
|
||||||
|
{
|
||||||
|
handleMouseClick(1);
|
||||||
|
field_DAC = field_DA8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_bGrabbedMouse)
|
||||||
|
{
|
||||||
|
v12 = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
label_12:
|
||||||
|
v12 = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMouseDown(1, v12);
|
||||||
|
|
||||||
|
field_2B4 = getTimeMs();
|
||||||
|
|
||||||
|
Keyboard::_inputs.clear();
|
||||||
|
Keyboard::_index = -1;
|
||||||
|
Mouse::_inputs.clear();
|
||||||
|
Mouse::_index = -1;
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
if (m_bGrabbedMouse)
|
||||||
|
{
|
||||||
|
platform()->recenterMouse();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::_levelGenerated()
|
||||||
|
{
|
||||||
|
if (m_pNetEventCallback)
|
||||||
|
m_pNetEventCallback->levelGenerated(m_pLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::tick()
|
||||||
|
{
|
||||||
|
if (field_DA4 > 0)
|
||||||
|
field_DA4--;
|
||||||
|
|
||||||
|
tickInput();
|
||||||
|
|
||||||
|
m_gui.tick();
|
||||||
|
|
||||||
|
// if the level has been prepared, delete the prep thread
|
||||||
|
if (!m_bPreparingLevel)
|
||||||
|
{
|
||||||
|
if (m_pPrepThread)
|
||||||
|
{
|
||||||
|
delete m_pPrepThread;
|
||||||
|
m_pPrepThread = nullptr;
|
||||||
|
_levelGenerated();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_pLevel && !field_288)
|
||||||
|
{
|
||||||
|
m_pGameRenderer->tick();
|
||||||
|
m_pLevelRenderer->tick();
|
||||||
|
m_pLevel->tickEntities();
|
||||||
|
m_pLevel->tick();
|
||||||
|
|
||||||
|
if (m_pLocalPlayer)
|
||||||
|
{
|
||||||
|
m_pLevel->animateTick(
|
||||||
|
Mth::floor(m_pLocalPlayer->m_pos.x),
|
||||||
|
Mth::floor(m_pLocalPlayer->m_pos.y),
|
||||||
|
Mth::floor(m_pLocalPlayer->m_pos.z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pTextures->loadAndBindTexture(C_TERRAIN_NAME);
|
||||||
|
|
||||||
|
if (!field_288)
|
||||||
|
{
|
||||||
|
m_pTextures->tick();
|
||||||
|
m_pParticleEngine->tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field_D14)
|
||||||
|
field_D14->tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::update()
|
||||||
|
{
|
||||||
|
if (field_288 && m_pLevel)
|
||||||
|
{
|
||||||
|
float x = m_timer.field_18;
|
||||||
|
m_timer.advanceTime();
|
||||||
|
m_timer.field_18 = x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_timer.advanceTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_pRakNetInstance)
|
||||||
|
{
|
||||||
|
m_pRakNetInstance->runEvents(m_pNetEventCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_timer.field_14 > 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < m_timer.field_14; i++)
|
||||||
|
{
|
||||||
|
tick();
|
||||||
|
field_DA8++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_pLevel && !m_bPreparingLevel)
|
||||||
|
{
|
||||||
|
m_pLevel->updateLights();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pGameRenderer->render(m_timer.field_18);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::init()
|
||||||
|
{
|
||||||
|
m_pTextures = new Textures(&m_options, platform());
|
||||||
|
m_pTextures->addDynamicTexture(new WaterTexture);
|
||||||
|
m_pTextures->addDynamicTexture(new WaterSideTexture);
|
||||||
|
m_pLevelRenderer = new LevelRenderer(this, m_pTextures);
|
||||||
|
m_pGameRenderer = new GameRenderer(this);
|
||||||
|
m_pParticleEngine = new ParticleEngine(m_pLevel, m_pTextures);
|
||||||
|
m_pUser = new User("TestUser", "");
|
||||||
|
m_pGameMode = new SurvivalMode(this);
|
||||||
|
|
||||||
|
reloadOptions();
|
||||||
|
|
||||||
|
m_pFont = new Font(&m_options, "font/default.png", m_pTextures);
|
||||||
|
}
|
||||||
|
|
||||||
|
Minecraft::~Minecraft()
|
||||||
|
{
|
||||||
|
SAFE_DELETE(m_pNetEventCallback);
|
||||||
|
SAFE_DELETE(m_pRakNetInstance);
|
||||||
|
SAFE_DELETE(m_pLevelRenderer);
|
||||||
|
SAFE_DELETE(m_pGameRenderer);
|
||||||
|
SAFE_DELETE(m_pParticleEngine);
|
||||||
|
SAFE_DELETE(m_pSoundEngine);
|
||||||
|
SAFE_DELETE(m_pGameMode);
|
||||||
|
SAFE_DELETE(m_pFont);
|
||||||
|
SAFE_DELETE(m_pTextures);
|
||||||
|
|
||||||
|
if (m_pLevel)
|
||||||
|
{
|
||||||
|
LevelStorage* pStor = m_pLevel->getLevelStorage();
|
||||||
|
if (pStor)
|
||||||
|
delete pStor;
|
||||||
|
if (m_pLevel)
|
||||||
|
delete m_pLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
SAFE_DELETE(m_pUser);
|
||||||
|
SAFE_DELETE(m_pLevelStorageSource);
|
||||||
|
SAFE_DELETE(m_pTurnInput);
|
||||||
|
|
||||||
|
//@BUG: potentially leaking a CThread instance if this is destroyed early?
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::prepareLevel(const std::string& unused)
|
||||||
|
{
|
||||||
|
field_DA0 = 1;
|
||||||
|
|
||||||
|
float startTime = getTimeS();
|
||||||
|
Level* pLevel = m_pLevel;
|
||||||
|
|
||||||
|
if (!pLevel->field_B0C)
|
||||||
|
{
|
||||||
|
pLevel->setUpdateLights(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 8, i2 = 0; i != 8 + C_MAX_CHUNKS_X * 16; i += 16)
|
||||||
|
{
|
||||||
|
for (int j = 8; j != 8 + C_MAX_CHUNKS_Z * 16; j += 16, i2 += 100)
|
||||||
|
{
|
||||||
|
// this looks like some kind of progress tracking
|
||||||
|
m_progressPercent = i2 / (C_MAX_CHUNKS_X * C_MAX_CHUNKS_Z);
|
||||||
|
|
||||||
|
float time1 = getTimeS();
|
||||||
|
|
||||||
|
// generating all the chunks at once
|
||||||
|
TileID unused = m_pLevel->getTile(i, (C_MAX_Y + C_MIN_Y) / 2, j);
|
||||||
|
|
||||||
|
if (time1 != -1.0f)
|
||||||
|
getTimeS();
|
||||||
|
|
||||||
|
float time2 = getTimeS();
|
||||||
|
if (m_pLevel->field_B0C)
|
||||||
|
{
|
||||||
|
while (m_pLevel->updateLights());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time2 != -1.0f)
|
||||||
|
getTimeS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startTime != -1.0f)
|
||||||
|
getTimeS();
|
||||||
|
|
||||||
|
m_pLevel->setUpdateLights(1);
|
||||||
|
|
||||||
|
startTime = getTimeS();
|
||||||
|
|
||||||
|
for (int x = 0; x < C_MAX_CHUNKS_X; x++)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < C_MAX_CHUNKS_Z; z++)
|
||||||
|
{
|
||||||
|
LevelChunk* pChunk = m_pLevel->getChunk(x, z);
|
||||||
|
if (!pChunk)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pChunk->field_237)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pChunk->m_bUnsaved = false;
|
||||||
|
pChunk->clearUpdateMap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startTime != -1.0f)
|
||||||
|
getTimeS();
|
||||||
|
|
||||||
|
field_DA0 = 3;
|
||||||
|
|
||||||
|
if (m_pLevel->field_B0C)
|
||||||
|
{
|
||||||
|
m_pLevel->setInitialSpawn();
|
||||||
|
m_pLevel->saveLevelData();
|
||||||
|
m_pLevel->getChunkSource()->saveAll();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_pLevel->saveLevelData();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_progressPercent = -1;
|
||||||
|
field_DA0 = 2;
|
||||||
|
|
||||||
|
startTime = getTimeS();
|
||||||
|
|
||||||
|
m_pLevel->prepare();
|
||||||
|
|
||||||
|
if (startTime != -1.0f)
|
||||||
|
getTimeS();
|
||||||
|
|
||||||
|
// These strings are initialized and then removed quickly afterwards. Probably some debug leftover
|
||||||
|
// "Generate level:";
|
||||||
|
// " - light: ";
|
||||||
|
// " - getTl: ";
|
||||||
|
// " - clear: ";
|
||||||
|
// " - prepr: ";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::generateLevel(const std::string& unused, Level* pLevel)
|
||||||
|
{
|
||||||
|
float time = getTimeS(); //@UNUSED
|
||||||
|
|
||||||
|
prepareLevel(unused);
|
||||||
|
|
||||||
|
if (time != -1.0f)
|
||||||
|
getTimeS(); //@QUIRK: unused return value
|
||||||
|
|
||||||
|
#pragma warning(disable : 26444) // C26444: Don't try to declare a local variable with no name.
|
||||||
|
std::string("Level generated: "); //@QUIRK: unused string instance
|
||||||
|
|
||||||
|
LocalPlayer* pLocalPlayer = m_pLocalPlayer;
|
||||||
|
if (!pLocalPlayer)
|
||||||
|
{
|
||||||
|
pLocalPlayer = m_pGameMode->createPlayer(pLevel);
|
||||||
|
m_pLocalPlayer = pLocalPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pLocalPlayer)
|
||||||
|
{
|
||||||
|
pLocalPlayer->m_pKeyboardInput = new KeyboardInput(&m_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_pLevelRenderer)
|
||||||
|
m_pLevelRenderer->setLevel(pLevel);
|
||||||
|
|
||||||
|
if (m_pParticleEngine)
|
||||||
|
m_pParticleEngine->setLevel(pLevel);
|
||||||
|
|
||||||
|
m_pGameMode->adjustPlayer(m_pLocalPlayer);
|
||||||
|
|
||||||
|
pLevel->validateSpawn();
|
||||||
|
pLevel->loadPlayer(m_pLocalPlayer);
|
||||||
|
|
||||||
|
if (m_pLocalPlayer)
|
||||||
|
{
|
||||||
|
m_pLocalPlayer->resetPos();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pMobPersp = m_pLocalPlayer;
|
||||||
|
m_pLevel = pLevel;
|
||||||
|
|
||||||
|
m_bPreparingLevel = false;
|
||||||
|
|
||||||
|
if (m_pRakNetInstance->m_bIsHost)
|
||||||
|
m_pRakNetInstance->announceServer(m_pUser->field_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* Minecraft::prepareLevel_tspawn(void* ptr)
|
||||||
|
{
|
||||||
|
Minecraft* pMinecraft = (Minecraft*)ptr;
|
||||||
|
|
||||||
|
pMinecraft->generateLevel("Currently not used", pMinecraft->m_pLevel);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::pauseGame()
|
||||||
|
{
|
||||||
|
if (field_D14) return;
|
||||||
|
m_pLevel->savePlayerData();
|
||||||
|
setScreen(new PauseScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::setLevel(Level* pLevel, const std::string& text, LocalPlayer* pLocalPlayer)
|
||||||
|
{
|
||||||
|
m_pMobPersp = nullptr;
|
||||||
|
|
||||||
|
if (pLevel)
|
||||||
|
{
|
||||||
|
m_pGameMode->initLevel(pLevel);
|
||||||
|
|
||||||
|
if (pLocalPlayer && m_pLocalPlayer == nullptr)
|
||||||
|
{
|
||||||
|
m_pLocalPlayer = pLocalPlayer;
|
||||||
|
pLocalPlayer->resetPos();
|
||||||
|
}
|
||||||
|
else if (m_pLocalPlayer)
|
||||||
|
{
|
||||||
|
m_pLocalPlayer->resetPos();
|
||||||
|
pLevel->addEntity(m_pLocalPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pLevel = pLevel;
|
||||||
|
m_bPreparingLevel = true;
|
||||||
|
m_pPrepThread = new CThread(&Minecraft::prepareLevel_tspawn, this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_pLocalPlayer = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::selectLevel(const std::string& a, const std::string& b, int c)
|
||||||
|
{
|
||||||
|
LevelStorage* pStor = m_pLevelStorageSource->selectLevel(a, false);
|
||||||
|
Dimension* pDim = Dimension::getNew(0);
|
||||||
|
|
||||||
|
m_pLevel = new Level(pStor, b, c, 1, pDim);
|
||||||
|
setLevel(m_pLevel, "Generating level", nullptr);
|
||||||
|
|
||||||
|
field_D9C = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* Minecraft::getProgressMessage()
|
||||||
|
{
|
||||||
|
return progressMessages[field_DA0];
|
||||||
|
}
|
||||||
|
|
||||||
|
LevelStorageSource* Minecraft::getLevelSource()
|
||||||
|
{
|
||||||
|
return m_pLevelStorageSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::leaveGame(bool bCopyMap)
|
||||||
|
{
|
||||||
|
m_bPreparingLevel = false;
|
||||||
|
m_pRakNetInstance->disconnect();
|
||||||
|
m_pMobPersp = nullptr;
|
||||||
|
m_pLevelRenderer->setLevel(nullptr);
|
||||||
|
m_pParticleEngine->setLevel(nullptr);
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
// @BUG: Deleting ServerSideNetworkHandler too late! This causes
|
||||||
|
// access to invalid memory in the destructor seeing as we already deleted the level.
|
||||||
|
delete m_pNetEventCallback;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (m_pLevel)
|
||||||
|
{
|
||||||
|
LevelStorage* pStorage = m_pLevel->getLevelStorage();
|
||||||
|
SAFE_DELETE(pStorage);
|
||||||
|
SAFE_DELETE(m_pLevel);
|
||||||
|
|
||||||
|
m_pLevel = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ORIGINAL_CODE
|
||||||
|
delete m_pNetEventCallback;
|
||||||
|
#endif
|
||||||
|
m_pLocalPlayer = nullptr;
|
||||||
|
m_pNetEventCallback = nullptr;
|
||||||
|
field_D9C = 0;
|
||||||
|
|
||||||
|
if (bCopyMap)
|
||||||
|
setScreen(new RenameMPLevelScreen("_LastJoinedServer"));
|
||||||
|
else
|
||||||
|
setScreen(new StartMenuScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::hostMultiplayer()
|
||||||
|
{
|
||||||
|
m_pRakNetInstance->host(m_pUser->field_0, C_DEFAULT_PORT, C_MAX_CONNECTIONS);
|
||||||
|
m_pNetEventCallback = new ServerSideNetworkHandler(this, m_pRakNetInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::joinMultiplayer(const PingedCompatibleServer& serverInfo)
|
||||||
|
{
|
||||||
|
if (field_18 && m_pNetEventCallback)
|
||||||
|
{
|
||||||
|
field_18 = false;
|
||||||
|
m_pRakNetInstance->connect(serverInfo.m_address.ToString(), serverInfo.m_address.GetPort());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::cancelLocateMultiplayer()
|
||||||
|
{
|
||||||
|
field_18 = false;
|
||||||
|
m_pRakNetInstance->stopPingForHosts();
|
||||||
|
delete m_pNetEventCallback;
|
||||||
|
m_pNetEventCallback = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Minecraft::locateMultiplayer()
|
||||||
|
{
|
||||||
|
field_18 = true;
|
||||||
|
m_pRakNetInstance->pingForHosts(C_DEFAULT_PORT);
|
||||||
|
m_pNetEventCallback = new ClientSideNetworkHandler(this, m_pRakNetInstance);
|
||||||
|
}
|
||||||
114
source/App/Minecraft.hpp
Normal file
114
source/App/Minecraft.hpp
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "App.hpp"
|
||||||
|
#include "Mth.hpp"
|
||||||
|
#include "Gui.hpp"
|
||||||
|
#include "Screen.hpp"
|
||||||
|
#include "Timer.hpp"
|
||||||
|
#include "GameRenderer.hpp"
|
||||||
|
#include "LevelRenderer.hpp"
|
||||||
|
#include "Level.hpp"
|
||||||
|
#include "CThread.hpp"
|
||||||
|
#include "LocalPlayer.hpp"
|
||||||
|
#include "SurvivalMode.hpp"
|
||||||
|
#include "ITurnInput.hpp"
|
||||||
|
#include "EntityRenderDispatcher.hpp"
|
||||||
|
#include "ParticleEngine.hpp"
|
||||||
|
#include "SoundEngine.hpp"
|
||||||
|
#include "RakNetInstance.hpp"
|
||||||
|
#include "NetEventCallback.hpp"
|
||||||
|
|
||||||
|
class Screen; // in case we're included from Screen.hpp
|
||||||
|
|
||||||
|
class Minecraft : public App
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Minecraft();
|
||||||
|
virtual ~Minecraft();
|
||||||
|
|
||||||
|
int getLicenseId();
|
||||||
|
void setScreen(Screen * pScreen);
|
||||||
|
void releaseMouse();
|
||||||
|
void grabMouse();
|
||||||
|
void tick();
|
||||||
|
void tickInput();
|
||||||
|
void reloadOptions();
|
||||||
|
void handleMouseClick(int type);
|
||||||
|
void handleMouseDown(int type, bool b);
|
||||||
|
bool isLevelGenerated();
|
||||||
|
void selectLevel(const std::string&, const std::string&, int);
|
||||||
|
void setLevel(Level*, const std::string&, LocalPlayer*);
|
||||||
|
void pauseGame();
|
||||||
|
void leaveGame(bool bCopyMap);
|
||||||
|
void hostMultiplayer();
|
||||||
|
void joinMultiplayer(const PingedCompatibleServer& serverInfo);
|
||||||
|
void cancelLocateMultiplayer();
|
||||||
|
void locateMultiplayer();
|
||||||
|
|
||||||
|
virtual void onGraphicsReset();
|
||||||
|
virtual void update() override;
|
||||||
|
virtual void init() override;
|
||||||
|
|
||||||
|
static void* prepareLevel_tspawn(void* pMinecraft);
|
||||||
|
void generateLevel(const std::string& unused, Level* pLevel);
|
||||||
|
void prepareLevel(const std::string& unused);
|
||||||
|
void _levelGenerated();
|
||||||
|
bool isOnline();
|
||||||
|
bool isOnlineClient();
|
||||||
|
|
||||||
|
const char* getProgressMessage();
|
||||||
|
LevelStorageSource* getLevelSource();
|
||||||
|
|
||||||
|
public:
|
||||||
|
static int width, height;
|
||||||
|
static bool useAmbientOcclusion;
|
||||||
|
static const char* progressMessages[];
|
||||||
|
static const bool DEADMAU5_CAMERA_CHEATS;
|
||||||
|
static int customDebugId;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool field_18 = false;
|
||||||
|
Options m_options;
|
||||||
|
bool field_288 = false;
|
||||||
|
LevelRenderer* m_pLevelRenderer = nullptr;
|
||||||
|
GameRenderer* m_pGameRenderer = nullptr;
|
||||||
|
ParticleEngine* m_pParticleEngine = nullptr;
|
||||||
|
SoundEngine* m_pSoundEngine = nullptr;
|
||||||
|
GameMode* m_pGameMode = nullptr;
|
||||||
|
Textures* m_pTextures = nullptr;
|
||||||
|
Font* m_pFont = nullptr;
|
||||||
|
RakNetInstance* m_pRakNetInstance = nullptr;
|
||||||
|
NetEventCallback* m_pNetEventCallback = nullptr;
|
||||||
|
int field_2B0 = 0;
|
||||||
|
int field_2B4;
|
||||||
|
int field_2B8;
|
||||||
|
User* m_pUser = nullptr;
|
||||||
|
Level* m_pLevel = nullptr;
|
||||||
|
LocalPlayer* m_pLocalPlayer = nullptr;
|
||||||
|
Mob* m_pMobPersp = nullptr; // why is there a duplicate?
|
||||||
|
Gui m_gui;
|
||||||
|
int field_D0C = 0;
|
||||||
|
CThread* m_pPrepThread = nullptr;
|
||||||
|
Screen* field_D14 = nullptr;
|
||||||
|
int field_D18 = 10;
|
||||||
|
ITurnInput* m_pTurnInput = nullptr;
|
||||||
|
float field_D20 = 0.0f;
|
||||||
|
float field_D24 = 0.0f;
|
||||||
|
bool m_bGrabbedMouse = true;
|
||||||
|
HitResult m_hitResult;
|
||||||
|
int m_progressPercent = 0;
|
||||||
|
std::string field_D58;
|
||||||
|
Timer m_timer;
|
||||||
|
bool m_bPreparingLevel = false;
|
||||||
|
LevelStorageSource* m_pLevelStorageSource = nullptr; // TODO
|
||||||
|
int field_D9C = 0;
|
||||||
|
int field_DA0 = 0;
|
||||||
|
int field_DA4 = 0;
|
||||||
|
int field_DA8 = 0;
|
||||||
|
int field_DAC = 0;
|
||||||
|
bool field_DB0 = 0;
|
||||||
|
bool field_DB1 = 0;
|
||||||
|
Screen* m_pScreen = nullptr;
|
||||||
|
int m_licenseID = -2;
|
||||||
|
};
|
||||||
|
|
||||||
118
source/App/NinecraftApp.cpp
Normal file
118
source/App/NinecraftApp.cpp
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
#include "NinecraftApp.hpp"
|
||||||
|
#include "StartMenuScreen.hpp"
|
||||||
|
#include "MemoryLevelStorageSource.hpp"
|
||||||
|
#include "Item.hpp"
|
||||||
|
|
||||||
|
bool NinecraftApp::_hasInitedStatics;
|
||||||
|
|
||||||
|
bool NinecraftApp::handleBack(bool b)
|
||||||
|
{
|
||||||
|
if (m_bPreparingLevel)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!m_pLevel)
|
||||||
|
{
|
||||||
|
if (!field_D14)
|
||||||
|
return false;
|
||||||
|
return field_D14->handleBackEvent(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!field_D14) return false;
|
||||||
|
|
||||||
|
if (field_D14->handleBackEvent(b))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
setScreen(nullptr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NinecraftApp::initGLStates()
|
||||||
|
{
|
||||||
|
GL_TEXTURE_2D;
|
||||||
|
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glDepthFunc(GL_LEQUAL);
|
||||||
|
glEnable(GL_ALPHA_TEST);
|
||||||
|
glAlphaFunc(GL_GREATER, 0.1f);
|
||||||
|
glCullFace(GL_NONE);
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NinecraftApp::init()
|
||||||
|
{
|
||||||
|
Mth::initMth();
|
||||||
|
|
||||||
|
if (!_hasInitedStatics)
|
||||||
|
{
|
||||||
|
_hasInitedStatics = true;
|
||||||
|
Material::initMaterials();
|
||||||
|
Tile::initTiles();
|
||||||
|
Item::initItems();
|
||||||
|
Biome::initBiomes();
|
||||||
|
}
|
||||||
|
|
||||||
|
initGLStates();
|
||||||
|
Tesselator::instance.init();
|
||||||
|
Minecraft::init();
|
||||||
|
m_pLevelStorageSource = new MemoryLevelStorageSource;
|
||||||
|
field_D9C = 0;
|
||||||
|
|
||||||
|
setScreen(new StartMenuScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NinecraftApp::onGraphicsReset()
|
||||||
|
{
|
||||||
|
initGLStates();
|
||||||
|
Tesselator::instance.init();
|
||||||
|
Minecraft::onGraphicsReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NinecraftApp::teardown()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void NinecraftApp::update()
|
||||||
|
{
|
||||||
|
++m_fps;
|
||||||
|
Minecraft::update();
|
||||||
|
|
||||||
|
#ifdef ORIGINAL_CODE
|
||||||
|
eglSwapBuffers(field_8, field_10);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Mouse::_xOld = Mouse::_x;
|
||||||
|
Mouse::_yOld = Mouse::_y;
|
||||||
|
updateStats();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NinecraftApp::updateStats()
|
||||||
|
{
|
||||||
|
int timeMs = getTimeMs();
|
||||||
|
if (timeMs > field_2B0 + 999)
|
||||||
|
{
|
||||||
|
if (m_pLocalPlayer)
|
||||||
|
{
|
||||||
|
Vec3 &pos = m_pLocalPlayer->m_pos;
|
||||||
|
printf("%d fps\t%3d chunk updates. (%.2f, %.2f, %.2f)\n", m_fps, Chunk::updates, pos.x, pos.y, pos.z);
|
||||||
|
printf("%s", m_pLevelRenderer->gatherStats1());
|
||||||
|
Chunk::updates = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("%d fps\n", m_fps);
|
||||||
|
}
|
||||||
|
|
||||||
|
field_2B0 = timeMs;
|
||||||
|
m_fps = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NinecraftApp::~NinecraftApp()
|
||||||
|
{
|
||||||
|
teardown();
|
||||||
|
}
|
||||||
29
source/App/NinecraftApp.hpp
Normal file
29
source/App/NinecraftApp.hpp
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Minecraft.hpp"
|
||||||
|
#include "Level.hpp"
|
||||||
|
#include "Tile.hpp"
|
||||||
|
|
||||||
|
//@TYPO: This is probably meant to say "MinecraftApp". Still not fixed in V0.3.0 though so not sure
|
||||||
|
class NinecraftApp : public Minecraft
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~NinecraftApp();
|
||||||
|
|
||||||
|
bool handleBack(bool) override;
|
||||||
|
void init() override;
|
||||||
|
void update() override;
|
||||||
|
void onGraphicsReset() override;
|
||||||
|
void teardown();
|
||||||
|
|
||||||
|
void updateStats();
|
||||||
|
void initGLStates();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int field_DBC = 0;
|
||||||
|
bool field_DC0 = 1;
|
||||||
|
int m_fps = 0;
|
||||||
|
|
||||||
|
static bool _hasInitedStatics;
|
||||||
|
};
|
||||||
|
|
||||||
200
source/Base/AABB.cpp
Normal file
200
source/Base/AABB.cpp
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
/********************************************************************
|
||||||
|
Minecraft: Pocket Edition - Decompilation Project
|
||||||
|
Copyright (C) 2023 iProgramInCpp
|
||||||
|
|
||||||
|
AABB.cpp
|
||||||
|
|
||||||
|
The following code is licensed under the following license:
|
||||||
|
< no license yet :( >
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include "AABB.hpp"
|
||||||
|
|
||||||
|
AABB::AABB()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AABB::AABB(Vec3 _min, Vec3 _max) :
|
||||||
|
min(_min), max(_max)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AABB::AABB(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) :
|
||||||
|
min(minX, minY, minZ), max(maxX, maxY, maxZ)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
HitResult AABB::clip(const Vec3& vec1, const Vec3& vec2)
|
||||||
|
{
|
||||||
|
Vec3 clipMinX, clipMinY, clipMinZ;
|
||||||
|
Vec3 clipMaxX, clipMaxY, clipMaxZ;
|
||||||
|
bool bClipMinX, bClipMinY, bClipMinZ;
|
||||||
|
bool bClipMaxX, bClipMaxY, bClipMaxZ;
|
||||||
|
|
||||||
|
bClipMinX = vec1.clipX(vec2, min.x, clipMinX);
|
||||||
|
bClipMaxX = vec1.clipX(vec2, max.x, clipMaxX);
|
||||||
|
bClipMinY = vec1.clipX(vec2, min.y, clipMinY);
|
||||||
|
bClipMaxY = vec1.clipX(vec2, max.y, clipMaxY);
|
||||||
|
bClipMinZ = vec1.clipX(vec2, min.z, clipMinZ);
|
||||||
|
bClipMaxZ = vec1.clipX(vec2, max.z, clipMaxZ);
|
||||||
|
|
||||||
|
// <sigh>
|
||||||
|
if (bClipMinX)
|
||||||
|
{
|
||||||
|
if (clipMinX.y < this->min.y || clipMinX.y > this->max.y || clipMinX.z < this->min.z)
|
||||||
|
bClipMinX = 0;
|
||||||
|
else
|
||||||
|
bClipMinX = clipMinX.z <= this->max.z;
|
||||||
|
}
|
||||||
|
if (bClipMaxX)
|
||||||
|
{
|
||||||
|
if (clipMaxX.y < this->min.y || clipMaxX.y > this->max.y || clipMaxX.z < this->min.z)
|
||||||
|
bClipMaxX = 0;
|
||||||
|
else
|
||||||
|
bClipMaxX = clipMaxX.z <= this->max.z;
|
||||||
|
}
|
||||||
|
if (bClipMinY)
|
||||||
|
{
|
||||||
|
if (clipMinY.x < this->min.x || clipMinY.x > this->max.x || clipMinY.z < this->min.z)
|
||||||
|
bClipMinY = 0;
|
||||||
|
else
|
||||||
|
bClipMinY = clipMinY.z <= this->max.z;
|
||||||
|
}
|
||||||
|
if (bClipMaxY)
|
||||||
|
{
|
||||||
|
if (clipMaxY.x < this->min.x || clipMaxY.x > this->max.x || clipMaxY.z < this->min.z)
|
||||||
|
bClipMaxY = 0;
|
||||||
|
else
|
||||||
|
bClipMaxY = clipMaxY.z <= this->max.z;
|
||||||
|
}
|
||||||
|
if (bClipMinZ)
|
||||||
|
{
|
||||||
|
if (clipMinZ.x < this->min.x || clipMinZ.x > this->max.x || clipMinZ.y < this->min.y)
|
||||||
|
bClipMinZ = 0;
|
||||||
|
else
|
||||||
|
bClipMinZ = clipMinZ.y <= this->max.y;
|
||||||
|
}
|
||||||
|
if (bClipMaxZ)
|
||||||
|
{
|
||||||
|
if (clipMaxZ.x < this->min.x || clipMaxZ.x > this->max.x || clipMaxZ.y < this->min.y)
|
||||||
|
bClipMaxZ = 0;
|
||||||
|
else
|
||||||
|
bClipMaxZ = clipMaxZ.y <= this->max.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the collided side of our AABB
|
||||||
|
HitResult::eHitSide collType = HitResult::NOHIT;
|
||||||
|
|
||||||
|
// the preferred vector for our collision
|
||||||
|
Vec3* pVec = nullptr;
|
||||||
|
if (bClipMinX)
|
||||||
|
pVec = &clipMinX, collType = HitResult::MINX;
|
||||||
|
|
||||||
|
if (bClipMaxX)
|
||||||
|
{
|
||||||
|
if (!pVec || clipMinZ.distanceToSqr(vec1) < pVec->distanceToSqr(vec1))
|
||||||
|
pVec = &clipMaxX, collType = HitResult::MAXX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bClipMinY)
|
||||||
|
{
|
||||||
|
if (!pVec || clipMinY.distanceToSqr(vec1) < pVec->distanceToSqr(vec1))
|
||||||
|
pVec = &clipMinY, collType = HitResult::MINY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bClipMaxY)
|
||||||
|
{
|
||||||
|
if (!pVec || clipMaxY.distanceToSqr(vec1) < pVec->distanceToSqr(vec1))
|
||||||
|
pVec = &clipMaxY, collType = HitResult::MAXY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bClipMinZ)
|
||||||
|
{
|
||||||
|
if (!pVec || clipMinZ.distanceToSqr(vec1) < pVec->distanceToSqr(vec1))
|
||||||
|
pVec = &clipMinZ, collType = HitResult::MINZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bClipMaxZ)
|
||||||
|
{
|
||||||
|
if (!pVec || clipMinZ.distanceToSqr(vec1) < pVec->distanceToSqr(vec1))
|
||||||
|
pVec = &clipMaxZ, collType = HitResult::MAXZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pVec)
|
||||||
|
{
|
||||||
|
// return a nothing burger
|
||||||
|
return HitResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
return HitResult(0, 0, 0, collType, *pVec);
|
||||||
|
}
|
||||||
|
|
||||||
|
float AABB::clipXCollide(const AABB& bud, float f) const
|
||||||
|
{
|
||||||
|
if (bud.max.y > min.y && bud.min.y < max.y && bud.max.z > min.z && bud.min.z < max.z)
|
||||||
|
{
|
||||||
|
if (f > 0.0f)
|
||||||
|
{
|
||||||
|
if (bud.max.x <= min.x)
|
||||||
|
f = Mth::Min(min.x - bud.max.x, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f < 0.0f)
|
||||||
|
{
|
||||||
|
if (bud.min.x >= max.x)
|
||||||
|
f = Mth::Max(max.x - bud.min.x, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float AABB::clipYCollide(const AABB& bud, float f) const
|
||||||
|
{
|
||||||
|
if (bud.max.x > min.x && bud.min.x < max.x && bud.max.z > min.z && bud.min.z < max.z)
|
||||||
|
{
|
||||||
|
if (f > 0.0f)
|
||||||
|
{
|
||||||
|
if (bud.max.y <= min.y)
|
||||||
|
f = Mth::Min(min.y - bud.max.y, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f < 0.0f)
|
||||||
|
{
|
||||||
|
if (bud.min.y >= max.y)
|
||||||
|
f = Mth::Max(max.y - bud.min.y, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float AABB::clipZCollide(const AABB& bud, float f) const
|
||||||
|
{
|
||||||
|
if (bud.max.x > min.x && bud.min.x < max.x && bud.max.y > min.y && bud.min.y < max.y)
|
||||||
|
{
|
||||||
|
if (f > 0.0f)
|
||||||
|
{
|
||||||
|
if (bud.max.z <= min.z)
|
||||||
|
f = Mth::Min(min.z - bud.max.z, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f < 0.0f)
|
||||||
|
{
|
||||||
|
if (bud.min.z >= max.z)
|
||||||
|
f = Mth::Max(max.z - bud.min.z, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AABB::intersect(const AABB& other) const
|
||||||
|
{
|
||||||
|
return max.x > other.min.x
|
||||||
|
&& min.x < other.max.x
|
||||||
|
&& max.y > other.min.y
|
||||||
|
&& min.y < other.max.y
|
||||||
|
&& max.z > other.min.z
|
||||||
|
&& min.z < other.max.z;
|
||||||
|
}
|
||||||
69
source/Base/AABB.hpp
Normal file
69
source/Base/AABB.hpp
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/********************************************************************
|
||||||
|
Minecraft: Pocket Edition - Decompilation Project
|
||||||
|
Copyright (C) 2023 iProgramInCpp
|
||||||
|
|
||||||
|
AABB.hpp
|
||||||
|
|
||||||
|
The following code is licensed under the following license:
|
||||||
|
< no license yet :( >
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Vec3.hpp"
|
||||||
|
#include "HitResult.hpp"
|
||||||
|
|
||||||
|
class AABB
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Vec3 min, max;
|
||||||
|
|
||||||
|
AABB();
|
||||||
|
AABB(Vec3 min, Vec3 max);
|
||||||
|
AABB(float minX, float minY, float minZ, float maxX, float maxY, float maxZ);
|
||||||
|
|
||||||
|
public:
|
||||||
|
HitResult clip(const Vec3&, const Vec3&);
|
||||||
|
float clipXCollide(const AABB& bud, float f) const;
|
||||||
|
float clipYCollide(const AABB& bud, float f) const;
|
||||||
|
float clipZCollide(const AABB& bud, float f) const;
|
||||||
|
|
||||||
|
bool intersect(const AABB& other) const;
|
||||||
|
|
||||||
|
// @NOTE: Names for `move`, `grow` and `expand` were taken from really early minecraft (rd-132211 to be exact).
|
||||||
|
void move(float x, float y, float z)
|
||||||
|
{
|
||||||
|
min += Vec3(x, y, z);
|
||||||
|
max += Vec3(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// same thing
|
||||||
|
void grow(float x, float y, float z)
|
||||||
|
{
|
||||||
|
min -= Vec3(x, y, z);
|
||||||
|
max += Vec3(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// same thing
|
||||||
|
void grow(float x)
|
||||||
|
{
|
||||||
|
min -= Vec3(x, x, x);
|
||||||
|
max += Vec3(x, x, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void expand(float x, float y, float z)
|
||||||
|
{
|
||||||
|
if (x < 0) min.x += x;
|
||||||
|
if (x > 0) max.x += x;
|
||||||
|
if (y < 0) min.y += y;
|
||||||
|
if (y > 0) max.y += y;
|
||||||
|
if (z < 0) min.z += z;
|
||||||
|
if (z > 0) max.z += z;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(const Vec3& v) const
|
||||||
|
{
|
||||||
|
return v.x > min.x && v.x < max.x && v.y > min.y && v.y < max.y && v.z > min.z && v.z < max.z;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
41
source/Base/CThread.cpp
Normal file
41
source/Base/CThread.cpp
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#include "CThread.hpp"
|
||||||
|
#include "Utils.hpp"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <Windows.h> // for Sleep()
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void CThread::sleep(uint32_t ms)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
Sleep(ms);
|
||||||
|
#else
|
||||||
|
usleep(1000 * ms);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
CThread::CThread(CThreadFunction func, void* parm)
|
||||||
|
{
|
||||||
|
m_func = func;
|
||||||
|
|
||||||
|
#ifdef USE_CPP11_THREADS
|
||||||
|
std::thread thr(func, parm);
|
||||||
|
m_thrd.swap(thr);
|
||||||
|
#else
|
||||||
|
pthread_attr_init(&m_thrd_attr);
|
||||||
|
pthread_attr_setdetachstate(&m_thrd_attr, 1);
|
||||||
|
pthread_create(&m_thrd, &m_thrd_attr, m_func, parm);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
CThread::~CThread()
|
||||||
|
{
|
||||||
|
#ifdef USE_CPP11_THREADS
|
||||||
|
m_thrd.join();
|
||||||
|
#else
|
||||||
|
pthread_join(m_thrd, 0);
|
||||||
|
pthread_attr_destroy(&m_thrd_attr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
33
source/Base/CThread.hpp
Normal file
33
source/Base/CThread.hpp
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// CThread - Object oriented pthread wrapper
|
||||||
|
#define USE_CPP11_THREADS
|
||||||
|
|
||||||
|
// USE_CPP11_THREADS - Use a C++11 implementation of threads instead of using pthread
|
||||||
|
#ifdef USE_CPP11_THREADS
|
||||||
|
#include <thread>
|
||||||
|
#else
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef void* (*CThreadFunction)(void*);
|
||||||
|
|
||||||
|
class CThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CThread(CThreadFunction, void* parm);
|
||||||
|
~CThread();
|
||||||
|
|
||||||
|
static void sleep(uint32_t ms);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CThreadFunction m_func;
|
||||||
|
|
||||||
|
#ifdef USE_CPP11_THREADS
|
||||||
|
std::thread m_thrd;
|
||||||
|
#else
|
||||||
|
pthread_t m_thrd;
|
||||||
|
pthread_attr_t m_thrd_attr;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
30
source/Base/HitResult.cpp
Normal file
30
source/Base/HitResult.cpp
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/********************************************************************
|
||||||
|
Minecraft: Pocket Edition - Decompilation Project
|
||||||
|
Copyright (C) 2023 iProgramInCpp
|
||||||
|
|
||||||
|
HitResult.cpp
|
||||||
|
|
||||||
|
The following code is licensed under the following license:
|
||||||
|
< no license yet :( >
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include "HitResult.hpp"
|
||||||
|
|
||||||
|
HitResult::HitResult() {}
|
||||||
|
|
||||||
|
HitResult::HitResult(int x, int y, int z, eHitSide hitSide, const Vec3& vec)
|
||||||
|
{
|
||||||
|
m_hitType = AABB;
|
||||||
|
m_hitSide = hitSide;
|
||||||
|
m_tileX = x;
|
||||||
|
m_tileY = y;
|
||||||
|
m_tileZ = z;
|
||||||
|
m_bUnk24 = false;
|
||||||
|
m_hitPos = vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
HitResult::HitResult(Entity* pEnt)
|
||||||
|
{
|
||||||
|
m_hitType = ENTITY;
|
||||||
|
m_pEnt = pEnt;
|
||||||
|
}
|
||||||
59
source/Base/HitResult.hpp
Normal file
59
source/Base/HitResult.hpp
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/********************************************************************
|
||||||
|
Minecraft: Pocket Edition - Decompilation Project
|
||||||
|
Copyright (C) 2023 iProgramInCpp
|
||||||
|
|
||||||
|
HitResult.cpp
|
||||||
|
|
||||||
|
The following code is licensed under the following license:
|
||||||
|
< no license yet :( >
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Vec3.hpp"
|
||||||
|
|
||||||
|
class Entity;
|
||||||
|
|
||||||
|
class HitResult
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// looks ass backwards, but what can you do about it
|
||||||
|
enum eHitResultType
|
||||||
|
{
|
||||||
|
AABB,
|
||||||
|
ENTITY,
|
||||||
|
NONE,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum eHitSide
|
||||||
|
{
|
||||||
|
NOHIT = -1,
|
||||||
|
MINY = 0,
|
||||||
|
MAXY, // 1
|
||||||
|
MINZ, // 2
|
||||||
|
MAXZ, // 3
|
||||||
|
MINX, // 4
|
||||||
|
MAXX, // 5
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
HitResult();
|
||||||
|
HitResult(Entity*);
|
||||||
|
HitResult(int x, int y, int z, eHitSide hitSide, const Vec3&);
|
||||||
|
|
||||||
|
public:
|
||||||
|
eHitResultType m_hitType = NONE;
|
||||||
|
// block coords?
|
||||||
|
int m_tileX = 0;
|
||||||
|
int m_tileY = 0;
|
||||||
|
int m_tileZ = 0;
|
||||||
|
|
||||||
|
eHitSide m_hitSide = MINY;
|
||||||
|
|
||||||
|
// hit position
|
||||||
|
Vec3 m_hitPos;
|
||||||
|
|
||||||
|
Entity* m_pEnt = nullptr;
|
||||||
|
bool m_bUnk24 = 0;
|
||||||
|
};
|
||||||
|
|
||||||
206
source/Base/ImprovedNoise.cpp
Normal file
206
source/Base/ImprovedNoise.cpp
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
#include "ImprovedNoise.hpp"
|
||||||
|
#include "Mth.hpp"
|
||||||
|
|
||||||
|
ImprovedNoise::ImprovedNoise()
|
||||||
|
{
|
||||||
|
Random random(1);
|
||||||
|
init(&random);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImprovedNoise::ImprovedNoise(Random* pRandom)
|
||||||
|
{
|
||||||
|
init(pRandom);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImprovedNoise::init(Random* pRandom)
|
||||||
|
{
|
||||||
|
m_offsetX = pRandom->nextFloat() * 256.0f;
|
||||||
|
m_offsetY = pRandom->nextFloat() * 256.0f;
|
||||||
|
m_offsetZ = pRandom->nextFloat() * 256.0f;
|
||||||
|
|
||||||
|
for (int i = 0; i < 256; i++)
|
||||||
|
m_permutation[i] = i;
|
||||||
|
|
||||||
|
for (int i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
int x = pRandom->nextInt(256 - i) + i;
|
||||||
|
int t = m_permutation[i];
|
||||||
|
m_permutation[i] = m_permutation[x];
|
||||||
|
m_permutation[x] = t;
|
||||||
|
m_permutation[256 + i] = m_permutation[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float ImprovedNoise::getValue(float x, float y)
|
||||||
|
{
|
||||||
|
return getValue(x, y, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float ImprovedNoise::getValue(float x, float y, float z)
|
||||||
|
{
|
||||||
|
return noise(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
float ImprovedNoise::lerp(float prog, float a, float b)
|
||||||
|
{
|
||||||
|
return a + (b - a) * prog;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ImprovedNoise::grad(int hash, float x, float y, float z)
|
||||||
|
{
|
||||||
|
int h = hash & 0xF;
|
||||||
|
float u = h < 8 ? x : y;
|
||||||
|
float v = h < 4 ? y : h == 12 || h == 14 ? x : z;
|
||||||
|
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
|
||||||
|
}
|
||||||
|
|
||||||
|
float ImprovedNoise::grad2(int hash, float x, float z)
|
||||||
|
{
|
||||||
|
return grad(hash, x, 0.0f, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
float ImprovedNoise::fade(float x)
|
||||||
|
{
|
||||||
|
return x * x * x * (x * (x * 6.0f - 15.0f) + 10.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float ImprovedNoise::noise(float x, float y, float z)
|
||||||
|
{
|
||||||
|
// couldn't figure out how to get it to work well enough so I just decided to port the original implementation from:
|
||||||
|
// https://cs.nyu.edu/~perlin/noise/
|
||||||
|
x += m_offsetX;
|
||||||
|
y += m_offsetY;
|
||||||
|
z += m_offsetZ;
|
||||||
|
|
||||||
|
int X = Mth::floor(x) & 255,
|
||||||
|
Y = Mth::floor(y) & 255,
|
||||||
|
Z = Mth::floor(z) & 255;
|
||||||
|
|
||||||
|
x -= Mth::floor(x);
|
||||||
|
y -= Mth::floor(y);
|
||||||
|
z -= Mth::floor(z);
|
||||||
|
|
||||||
|
float u = fade(x),
|
||||||
|
v = fade(y),
|
||||||
|
w = fade(z);
|
||||||
|
|
||||||
|
int* p = m_permutation;
|
||||||
|
int A = p[X ] + Y, AA = p[A] + Z, AB = p[A + 1] + Z,
|
||||||
|
B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z;
|
||||||
|
|
||||||
|
return lerp(w, lerp(v, lerp(u, grad(p[AA ], x , y , z ),
|
||||||
|
grad(p[BA ], x-1, y , z )),
|
||||||
|
lerp(u, grad(p[AB ], x , y-1, z ),
|
||||||
|
grad(p[BB ], x-1, y-1, z ))),
|
||||||
|
lerp(v, lerp(u, grad(p[AA+1], x , y , z-1 ),
|
||||||
|
grad(p[BA+1], x-1, y , z-1 )),
|
||||||
|
lerp(u, grad(p[AB+1], x , y-1, z-1 ),
|
||||||
|
grad(p[BB+1], x-1, y-1, z-1 ))));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImprovedNoise::add(float* a2, float a3, float a4, float a5, int a6, int a7, int a8, float a9, float a10, float a11, float a12)
|
||||||
|
{
|
||||||
|
// @TODO: clean this up
|
||||||
|
if (a7 == 1)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < a6; i++)
|
||||||
|
{
|
||||||
|
float x2 = m_offsetX + a9 * (i + a3);
|
||||||
|
int x3 = Mth::floor(x2);
|
||||||
|
float x4 = float(x3);
|
||||||
|
float x5 = x2 - x4;
|
||||||
|
|
||||||
|
int* x6 = &m_permutation[uint8_t(x3)];
|
||||||
|
int* x8 = &m_permutation[uint8_t(x3 + 1)];
|
||||||
|
float* x7 = &a2[a8 * i];
|
||||||
|
|
||||||
|
for (int j = 0; j < a8; j++)
|
||||||
|
{
|
||||||
|
float x9 = m_offsetZ + a11 * (j + a5);
|
||||||
|
int x10 = Mth::floor(x9);
|
||||||
|
float x11 = float(x10);
|
||||||
|
float x12 = x9 - x11;
|
||||||
|
|
||||||
|
int* x13 = &m_permutation[uint8_t(x10) + m_permutation[*x6]];
|
||||||
|
int* x15 = &m_permutation[uint8_t(x10) + m_permutation[*x8]];
|
||||||
|
int* x14 = x8;
|
||||||
|
|
||||||
|
float x16 = grad2(*x13, x5, x12);
|
||||||
|
float x17 = grad(*x15, x5 - 1, 0, x12);
|
||||||
|
float x18 = lerp(fade(x5), x16, x17);
|
||||||
|
float x19 = grad(x13[1], x5, 0, x12 - 1);
|
||||||
|
float x20 = grad(x15[1], x5 - 1, 0, x12 - 1);
|
||||||
|
float x21 = lerp(fade(x5), x19, x20);
|
||||||
|
|
||||||
|
*x7 += (1.0f / a12) * lerp(fade(x12), x18, x21);
|
||||||
|
x7++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float x30 = 0, x31 = 0, x32 = 0, x33 = 0;
|
||||||
|
int x34 = -1, x35 = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < a6; i++)
|
||||||
|
{
|
||||||
|
float x36 = m_offsetX + a9 * (i + a3);
|
||||||
|
int x37 = Mth::floor(x36);
|
||||||
|
float x38 = float(x37);
|
||||||
|
float x39 = x36 - x38;
|
||||||
|
float x40 = fade(x39);
|
||||||
|
if (a8 <= 0) continue;
|
||||||
|
|
||||||
|
int* x42 = &m_permutation[uint8_t(x37)];
|
||||||
|
int* x43 = &m_permutation[uint8_t(x37) + 1];
|
||||||
|
for (int j = 0; j < a8; j++)
|
||||||
|
{
|
||||||
|
float x44 = m_offsetZ + a11 * (j + a5);
|
||||||
|
int x45 = Mth::floor(x44);
|
||||||
|
float x46 = float(x45);
|
||||||
|
float x47 = x44 - x46;
|
||||||
|
uint8_t x48 = uint8_t(x45);
|
||||||
|
if (a7 <= 0) continue;
|
||||||
|
|
||||||
|
float* x49 = &a2[x35];
|
||||||
|
for (int k = 0; k < a7; k++)
|
||||||
|
{
|
||||||
|
float x50 = m_offsetY + a10 * (k + a4);
|
||||||
|
int x51 = Mth::floor(x50);
|
||||||
|
float x52 = float(x51);
|
||||||
|
float x53 = x50 - x52;
|
||||||
|
uint8_t bx51 = uint8_t(x51);
|
||||||
|
|
||||||
|
if (k == 0 || bx51 != x34)
|
||||||
|
{
|
||||||
|
int* x54 = &m_permutation[bx51 + *x42];
|
||||||
|
int x55 = x54[0] + x48;
|
||||||
|
int x56 = x54[1] + x48;
|
||||||
|
int* x57 = &m_permutation[bx51 + *x43];
|
||||||
|
int x58 = x57[1] + x48;
|
||||||
|
int* x59 = &m_permutation[*x57 + x48];
|
||||||
|
float x60 = grad(m_permutation[x55], x39, x53, x47);
|
||||||
|
float x61 = grad(*x59, x39 - 1, x53, x47);
|
||||||
|
x33 = lerp(x40, x60, x61);
|
||||||
|
float x62 = grad(m_permutation[x56], x39, x53 - 1, x47);
|
||||||
|
float x63 = grad(m_permutation[x58], x39 - 1, x53 - 1, x47);
|
||||||
|
x32 = lerp(x40, x62, x63);
|
||||||
|
float x64 = grad(m_permutation[x55 + 1], x39, x53, x47 - 1);
|
||||||
|
float x65 = grad(x59[1], x39 - 1, x53, x47 - 1);
|
||||||
|
x31 = lerp(x40, x64, x65);
|
||||||
|
float x66 = grad(m_permutation[x56 + 1], x39, x53 - 1, x47 - 1);
|
||||||
|
float x67 = grad(m_permutation[x58 + 1], x39 - 1, x53 - 1, x47 - 1);
|
||||||
|
x34 = bx51;
|
||||||
|
x30 = lerp(x40, x66, x67);
|
||||||
|
}
|
||||||
|
|
||||||
|
float x68 = lerp(fade(x53), x33, x32);
|
||||||
|
float x69 = lerp(fade(x53), x31, x30);
|
||||||
|
*x49 += (1.0f / a12) * lerp(fade(x47), x68, x69);
|
||||||
|
x49++;
|
||||||
|
}
|
||||||
|
x35 += a7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
source/Base/ImprovedNoise.hpp
Normal file
32
source/Base/ImprovedNoise.hpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Random.hpp"
|
||||||
|
#include "Synth.hpp"
|
||||||
|
|
||||||
|
// note: appears to maybe inherit from a class called Synth?
|
||||||
|
// the only purpose that it serves I guess is to provide
|
||||||
|
// a virtual getValue
|
||||||
|
class ImprovedNoise : public Synth
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
float getValue(float, float) override;
|
||||||
|
|
||||||
|
ImprovedNoise();
|
||||||
|
ImprovedNoise(Random* pRandom);
|
||||||
|
|
||||||
|
void init(Random* pRandom);
|
||||||
|
float getValue(float, float, float);
|
||||||
|
float noise(float, float, float);
|
||||||
|
float grad(int, float, float, float);
|
||||||
|
float grad2(int, float, float);
|
||||||
|
float lerp(float prog, float a, float b);
|
||||||
|
float fade(float x); // inlined in the code
|
||||||
|
void add(float* a2, float a3, float a4, float a5, int a6, int a7, int a8, float a9, float a10, float a11, float a12);
|
||||||
|
|
||||||
|
public:
|
||||||
|
float m_offsetX;
|
||||||
|
float m_offsetY;
|
||||||
|
float m_offsetZ;
|
||||||
|
int m_permutation[512];
|
||||||
|
};
|
||||||
|
|
||||||
52
source/Base/Matrix.cpp
Normal file
52
source/Base/Matrix.cpp
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#include "Matrix.hpp"
|
||||||
|
|
||||||
|
Matrix::Matrix()
|
||||||
|
{
|
||||||
|
memset(c, 0, sizeof c);
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix::Matrix(float x)
|
||||||
|
{
|
||||||
|
memset(c, 0, sizeof c);
|
||||||
|
c[0] = c[4 * 1 + 1] = c[4 * 2 + 2] = c[4 * 3 + 3] = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix::Matrix(float* p)
|
||||||
|
{
|
||||||
|
memcpy(c, p, sizeof c);
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix::Matrix(float a, float b, float q, float d, float e, float f, float g, float h, float i, float j, float k, float l, float m, float n, float o, float p)
|
||||||
|
{
|
||||||
|
c[0] = a, c[1] = b, c[2] = q, c[3] = d, c[4] = e, c[5] = f, c[6] = g, c[7] = h, c[8] = i, c[9] = j, c[10] = k, c[11] = l, c[12] = m, c[13] = n, c[14] = o, c[15] = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Matrix::fetchGL(GLenum pname)
|
||||||
|
{
|
||||||
|
glGetFloatv(pname, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix operator*(const Matrix& a, const Matrix& b)
|
||||||
|
{
|
||||||
|
Matrix result;
|
||||||
|
|
||||||
|
//this is ugly
|
||||||
|
result.c[0] = a.c[0] * b.c[0] + a.c[1] * b.c[4] + a.c[2] * b.c[8] + a.c[3] * b.c[12];
|
||||||
|
result.c[1] = a.c[0] * b.c[1] + a.c[1] * b.c[5] + a.c[2] * b.c[9] + a.c[3] * b.c[13];
|
||||||
|
result.c[2] = a.c[0] * b.c[2] + a.c[1] * b.c[6] + a.c[2] * b.c[10] + a.c[3] * b.c[14];
|
||||||
|
result.c[3] = a.c[0] * b.c[3] + a.c[1] * b.c[7] + a.c[2] * b.c[11] + a.c[3] * b.c[15];
|
||||||
|
result.c[4] = a.c[4] * b.c[0] + a.c[5] * b.c[4] + a.c[6] * b.c[8] + a.c[7] * b.c[12];
|
||||||
|
result.c[5] = a.c[4] * b.c[1] + a.c[5] * b.c[5] + a.c[6] * b.c[9] + a.c[7] * b.c[13];
|
||||||
|
result.c[6] = a.c[4] * b.c[2] + a.c[5] * b.c[6] + a.c[6] * b.c[10] + a.c[7] * b.c[14];
|
||||||
|
result.c[7] = a.c[4] * b.c[3] + a.c[5] * b.c[7] + a.c[6] * b.c[11] + a.c[7] * b.c[15];
|
||||||
|
result.c[8] = a.c[8] * b.c[0] + a.c[9] * b.c[4] + a.c[10] * b.c[8] + a.c[11] * b.c[12];
|
||||||
|
result.c[9] = a.c[8] * b.c[1] + a.c[9] * b.c[5] + a.c[10] * b.c[9] + a.c[11] * b.c[13];
|
||||||
|
result.c[10] = a.c[8] * b.c[2] + a.c[9] * b.c[6] + a.c[10] * b.c[10] + a.c[11] * b.c[14];
|
||||||
|
result.c[11] = a.c[8] * b.c[3] + a.c[9] * b.c[7] + a.c[10] * b.c[11] + a.c[11] * b.c[15];
|
||||||
|
result.c[12] = a.c[12] * b.c[0] + a.c[13] * b.c[4] + a.c[14] * b.c[8] + a.c[15] * b.c[12];
|
||||||
|
result.c[13] = a.c[12] * b.c[1] + a.c[13] * b.c[5] + a.c[14] * b.c[9] + a.c[15] * b.c[13];
|
||||||
|
result.c[14] = a.c[12] * b.c[2] + a.c[13] * b.c[6] + a.c[14] * b.c[10] + a.c[15] * b.c[14];
|
||||||
|
result.c[15] = a.c[12] * b.c[3] + a.c[13] * b.c[7] + a.c[14] * b.c[11] + a.c[15] * b.c[15];
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
22
source/Base/Matrix.hpp
Normal file
22
source/Base/Matrix.hpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "compat/GL.hpp"
|
||||||
|
#include "Mth.hpp"
|
||||||
|
|
||||||
|
class Matrix
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Matrix(); // create an empty matrix
|
||||||
|
Matrix(float a); // create an identity matrix
|
||||||
|
Matrix(float* p); // load matrix from memory
|
||||||
|
Matrix(float a, float b, float c, float d, float e, float f, float g, float h, float i, float j, float k, float l, float m, float n, float o, float p);
|
||||||
|
void fetchGL(GLenum pname);
|
||||||
|
|
||||||
|
friend Matrix operator*(const Matrix& a, const Matrix& b);
|
||||||
|
|
||||||
|
public:
|
||||||
|
float c[16] = { 0.0f };
|
||||||
|
};
|
||||||
|
|
||||||
|
Matrix operator*(const Matrix& a, const Matrix& b);
|
||||||
|
|
||||||
160
source/Base/Mth.cpp
Normal file
160
source/Base/Mth.cpp
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
/********************************************************************
|
||||||
|
Minecraft: Pocket Edition - Decompilation Project
|
||||||
|
Copyright (C) 2023 iProgramInCpp
|
||||||
|
|
||||||
|
Mth.cpp
|
||||||
|
|
||||||
|
The following code is licensed under the following license:
|
||||||
|
< no license yet :( >
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "Mth.hpp"
|
||||||
|
|
||||||
|
#define C_SIN_TABLE_MULTIPLIER (10430.0f) // (3320.0f * 3.14156f)
|
||||||
|
|
||||||
|
#define ANG_TO_SIN_TABLE_INDEX(ang) ((int) ((ang) * C_SIN_TABLE_MULTIPLIER))
|
||||||
|
#define SIN_TABLE_INDEX_TO_ANG(ang) ((float)((ang) / C_SIN_TABLE_MULTIPLIER))
|
||||||
|
|
||||||
|
float g_SinTable[65536];
|
||||||
|
|
||||||
|
Random Mth::g_Random;
|
||||||
|
|
||||||
|
void Mth::initMth()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 65536; i++)
|
||||||
|
{
|
||||||
|
g_SinTable[i] = sinf(SIN_TABLE_INDEX_TO_ANG(i)); // value is 10430
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Mth::intFloorDiv(int a2, int a3)
|
||||||
|
{
|
||||||
|
if (a2 < 0)
|
||||||
|
return ~(~a2 / a3);
|
||||||
|
|
||||||
|
return a2 / a3;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Mth::invSqrt(float number)
|
||||||
|
{
|
||||||
|
// It looks familiar. With IDA I get a convoluted mess. I'm going to assume
|
||||||
|
// they just stole it from Quake.
|
||||||
|
|
||||||
|
int32_t i;
|
||||||
|
float x2, y;
|
||||||
|
const float threehalfs = 1.5F;
|
||||||
|
|
||||||
|
x2 = number * 0.5F;
|
||||||
|
y = number;
|
||||||
|
i = * ( int32_t * ) &y; // evil floating point bit level hacking
|
||||||
|
i = 0x5f3759df - ( i >> 1 ); // what the fuck?
|
||||||
|
y = * ( float * ) &i;
|
||||||
|
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
|
||||||
|
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
|
||||||
|
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Mth::sin(float a2)
|
||||||
|
{
|
||||||
|
int angle = ANG_TO_SIN_TABLE_INDEX(a2) & 0xFFFF;
|
||||||
|
|
||||||
|
return g_SinTable[angle];
|
||||||
|
}
|
||||||
|
|
||||||
|
float Mth::cos(float a2)
|
||||||
|
{
|
||||||
|
int angle = (ANG_TO_SIN_TABLE_INDEX(a2) + 16384) & 0xFFFF;
|
||||||
|
|
||||||
|
return g_SinTable[angle];
|
||||||
|
}
|
||||||
|
|
||||||
|
float Mth::sqrt(float a2)
|
||||||
|
{
|
||||||
|
return sqrtf(a2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Mth::floor(float f)
|
||||||
|
{
|
||||||
|
int result = int(f);
|
||||||
|
|
||||||
|
if (result > f)
|
||||||
|
result--;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Mth::atan(float f)
|
||||||
|
{
|
||||||
|
return atanf(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float Mth::atan2(float y, float x)
|
||||||
|
{
|
||||||
|
return atan2f(y, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
float Mth::Min(float a, float b)
|
||||||
|
{
|
||||||
|
return a < b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Mth::Min(int a, int b)
|
||||||
|
{
|
||||||
|
return a < b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Mth::Max(float a, float b)
|
||||||
|
{
|
||||||
|
return a > b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Mth::Max(int a, int b)
|
||||||
|
{
|
||||||
|
return a > b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Mth::abs(float f)
|
||||||
|
{
|
||||||
|
if (f < 0)
|
||||||
|
f = -f;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Mth::abs(int d)
|
||||||
|
{
|
||||||
|
return ::abs(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
float Mth::absMax(float a2, float a3)
|
||||||
|
{
|
||||||
|
if (a2 < 0)
|
||||||
|
a2 = -a2;
|
||||||
|
if (a3 < 0)
|
||||||
|
a3 = -a3;
|
||||||
|
if (a2 <= a3)
|
||||||
|
a2 = a3;
|
||||||
|
return a2;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Mth::absMaxSigned(float a2, float a3)
|
||||||
|
{
|
||||||
|
if (abs(a2) <= abs(a2))
|
||||||
|
a2 = a3;
|
||||||
|
return a2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Mth::random(int max)
|
||||||
|
{
|
||||||
|
return int(g_Random.nextInt(max));
|
||||||
|
}
|
||||||
|
|
||||||
|
float Mth::random()
|
||||||
|
{
|
||||||
|
return g_Random.genrand_int32() * (1.0f / 4294967295.0f);
|
||||||
|
// divided by 2^32-1
|
||||||
|
}
|
||||||
|
|
||||||
42
source/Base/Mth.hpp
Normal file
42
source/Base/Mth.hpp
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/********************************************************************
|
||||||
|
Minecraft: Pocket Edition - Decompilation Project
|
||||||
|
Copyright (C) 2023 iProgramInCpp
|
||||||
|
|
||||||
|
Mth.hpp
|
||||||
|
|
||||||
|
The following code is licensed under the following license:
|
||||||
|
< no license yet :( >
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "Random.hpp"
|
||||||
|
|
||||||
|
class Mth
|
||||||
|
{
|
||||||
|
static Random g_Random;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static float Max(float, float);
|
||||||
|
static int Max(int, int);
|
||||||
|
static float Min(float, float);
|
||||||
|
static int Min(int, int);
|
||||||
|
static float abs(float);
|
||||||
|
static int abs(int);
|
||||||
|
static float absMax(float, float);
|
||||||
|
static float absMaxSigned(float, float);
|
||||||
|
static float atan(float);
|
||||||
|
static float atan2(float y, float x);
|
||||||
|
static float cos(float);
|
||||||
|
static int floor(float);
|
||||||
|
static void initMth();
|
||||||
|
static int intFloorDiv(int, int);
|
||||||
|
static float invSqrt(float);
|
||||||
|
static int random(int);
|
||||||
|
static float random(void);
|
||||||
|
static float sin(float);
|
||||||
|
static float sqrt(float);
|
||||||
|
};
|
||||||
|
|
||||||
93
source/Base/PerlinNoise.cpp
Normal file
93
source/Base/PerlinNoise.cpp
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
#include "PerlinNoise.hpp"
|
||||||
|
#include "Utils.hpp"
|
||||||
|
|
||||||
|
PerlinNoise::PerlinNoise(int nOctaves)
|
||||||
|
{
|
||||||
|
m_pRandom = &m_random;
|
||||||
|
init(nOctaves);
|
||||||
|
}
|
||||||
|
|
||||||
|
PerlinNoise::PerlinNoise(Random* pRandom, int nOctaves)
|
||||||
|
{
|
||||||
|
m_pRandom = pRandom;
|
||||||
|
|
||||||
|
if (nOctaves == 10)
|
||||||
|
{
|
||||||
|
LogMsg("Ok");
|
||||||
|
}
|
||||||
|
|
||||||
|
init(nOctaves);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PerlinNoise::init(int nOctaves)
|
||||||
|
{
|
||||||
|
m_nOctaves = nOctaves;
|
||||||
|
m_pImprovedNoise = new ImprovedNoise * [nOctaves];
|
||||||
|
|
||||||
|
for (int i = 0; i < nOctaves; i++)
|
||||||
|
{
|
||||||
|
m_pImprovedNoise[i] = new ImprovedNoise(m_pRandom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PerlinNoise::~PerlinNoise()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < m_nOctaves; i++)
|
||||||
|
delete[] m_pImprovedNoise[i];
|
||||||
|
|
||||||
|
delete[] m_pImprovedNoise;
|
||||||
|
}
|
||||||
|
|
||||||
|
float PerlinNoise::getValue(float x, float y)
|
||||||
|
{
|
||||||
|
if (m_nOctaves <= 0) return 0.0f;
|
||||||
|
|
||||||
|
float result = 0.0f, x1 = 1.0f;
|
||||||
|
|
||||||
|
for (int i = 0; i < m_nOctaves; i++)
|
||||||
|
{
|
||||||
|
result += m_pImprovedNoise[i]->getValue(x * x1, y * x1) / x1;
|
||||||
|
x1 /= 2.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float PerlinNoise::getValue(float x, float y, float z)
|
||||||
|
{
|
||||||
|
if (m_nOctaves <= 0) return 0.0f;
|
||||||
|
|
||||||
|
float result = 0.0f, x1 = 1.0f;
|
||||||
|
|
||||||
|
for (int i = 0; i < m_nOctaves; i++)
|
||||||
|
{
|
||||||
|
result += m_pImprovedNoise[i]->getValue(x * x1, y * x1, z * x1) / x1;
|
||||||
|
x1 /= 2.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float* PerlinNoise::getRegion(float* a2, int a3, int a4, int a5, int a6, float a7, float a8, float a9)
|
||||||
|
{
|
||||||
|
return getRegion(a2, float(a3), 10.0f, float(a4), a5, 1, a6, a7, 1.0f, a8);
|
||||||
|
}
|
||||||
|
|
||||||
|
float* PerlinNoise::getRegion(float* pMem, float a3, float a4, float a5, int a6, int a7, int a8, float a9, float a10, float a11)
|
||||||
|
{
|
||||||
|
int amt = a6 * a7 * a8;
|
||||||
|
if (!pMem)
|
||||||
|
pMem = new float[amt];
|
||||||
|
|
||||||
|
for (int i = 0; i < amt; i++)
|
||||||
|
pMem[i] = 0;
|
||||||
|
|
||||||
|
float x = 1.0f;
|
||||||
|
for (int i = 0; i < m_nOctaves; i++)
|
||||||
|
{
|
||||||
|
m_pImprovedNoise[i]->add(pMem, a3, a4, a5, a6, a7, a8, a9 * x, a10 * x, a11 * x, x);
|
||||||
|
x /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pMem;
|
||||||
|
}
|
||||||
25
source/Base/PerlinNoise.hpp
Normal file
25
source/Base/PerlinNoise.hpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ImprovedNoise.hpp"
|
||||||
|
|
||||||
|
class PerlinNoise : public Synth
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PerlinNoise(int nOctaves);
|
||||||
|
PerlinNoise(Random*, int nOctaves);
|
||||||
|
virtual ~PerlinNoise();
|
||||||
|
void init(int nOctaves);
|
||||||
|
|
||||||
|
float getValue(float, float) override;
|
||||||
|
float getValue(float, float, float);
|
||||||
|
|
||||||
|
float* getRegion(float*, int, int, int, int, float, float, float);
|
||||||
|
float* getRegion(float*, float, float , float, int, int, int, float, float, float);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ImprovedNoise** m_pImprovedNoise;
|
||||||
|
int m_nOctaves;
|
||||||
|
Random m_random;
|
||||||
|
Random* m_pRandom; // random for seeding, I assume
|
||||||
|
};
|
||||||
|
|
||||||
110
source/Base/Random.cpp
Normal file
110
source/Base/Random.cpp
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
/********************************************************************
|
||||||
|
Minecraft: Pocket Edition - Decompilation Project
|
||||||
|
Copyright (C) 2023 iProgramInCpp
|
||||||
|
|
||||||
|
Random.cpp
|
||||||
|
|
||||||
|
The following code is licensed under the following license:
|
||||||
|
< no license yet :( >
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include "Utils.hpp"
|
||||||
|
#include "Random.hpp"
|
||||||
|
|
||||||
|
/* Period parameters */
|
||||||
|
#define N 624
|
||||||
|
#define M 397
|
||||||
|
#define MATRIX_A 0x9908b0dfUL /* constant vector a */
|
||||||
|
#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
|
||||||
|
#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
|
||||||
|
|
||||||
|
Random::Random(long seed)
|
||||||
|
{
|
||||||
|
setSeed(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Random::setSeed(long seed)
|
||||||
|
{
|
||||||
|
rseed = seed;
|
||||||
|
mti = N + 1;
|
||||||
|
init_genrand(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initializes mt[N] with a seed */
|
||||||
|
void Random::init_genrand(unsigned long s)
|
||||||
|
{
|
||||||
|
mt[0] = s & 0xffffffffUL;
|
||||||
|
for (mti = 1; mti < N; mti++) {
|
||||||
|
mt[mti] =
|
||||||
|
(1812433253UL * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti);
|
||||||
|
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
|
||||||
|
/* In the previous versions, MSBs of the seed affect */
|
||||||
|
/* only MSBs of the array mt[]. */
|
||||||
|
/* 2002/01/09 modified by Makoto Matsumoto */
|
||||||
|
mt[mti] &= 0xffffffffUL;
|
||||||
|
/* for >32 bit machines */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Random::nextInt(int max)
|
||||||
|
{
|
||||||
|
return int(genrand_int32() % unsigned(max));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a number from 0 to n (excluding n)
|
||||||
|
unsigned int Random::genrand_int32()
|
||||||
|
{
|
||||||
|
unsigned long y;
|
||||||
|
static unsigned long mag01[2]={0x0UL, MATRIX_A};
|
||||||
|
/* mag01[x] = x * MATRIX_A for x=0,1 */
|
||||||
|
|
||||||
|
if (mti >= N) { /* generate N words at one time */
|
||||||
|
int kk;
|
||||||
|
|
||||||
|
if (mti == N+1) /* if init_genrand() has not been called, */
|
||||||
|
init_genrand(5489UL); /* a default initial seed is used */
|
||||||
|
|
||||||
|
for (kk=0;kk<N-M;kk++) {
|
||||||
|
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
||||||
|
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||||
|
}
|
||||||
|
for (;kk<N-1;kk++) {
|
||||||
|
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
||||||
|
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||||
|
}
|
||||||
|
y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
|
||||||
|
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||||
|
|
||||||
|
mti = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
y = mt[mti++];
|
||||||
|
|
||||||
|
/* Tempering */
|
||||||
|
y ^= (y >> 11);
|
||||||
|
y ^= (y << 7) & 0x9d2c5680UL;
|
||||||
|
y ^= (y << 15) & 0xefc60000UL;
|
||||||
|
y ^= (y >> 18);
|
||||||
|
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Random::nextFloat()
|
||||||
|
{
|
||||||
|
return float(genrand_real2());
|
||||||
|
}
|
||||||
|
|
||||||
|
double Random::genrand_real2()
|
||||||
|
{
|
||||||
|
return double(genrand_int32()) * (1.0 / 4294967296.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
long Random::nextLong()
|
||||||
|
{
|
||||||
|
return long(genrand_int32() >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Random::nextInt()
|
||||||
|
{
|
||||||
|
return int(genrand_int32() >> 1);
|
||||||
|
}
|
||||||
56
source/Base/Random.hpp
Normal file
56
source/Base/Random.hpp
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/********************************************************************
|
||||||
|
Minecraft: Pocket Edition - Decompilation Project
|
||||||
|
Copyright (C) 2023 iProgramInCpp
|
||||||
|
|
||||||
|
Random.hpp
|
||||||
|
|
||||||
|
The following code is licensed under the following license:
|
||||||
|
< no license yet :( >
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
// This appears to be VERY similar to https://github.com/SethRobinson/proton/blob/master/shared/util/CRandom.h#L10
|
||||||
|
// It turns out, RTsoft, Mojang, and the author of Game Coding Complete used the same reference implementation of
|
||||||
|
// the Mersenne Twister:
|
||||||
|
// http://www.math.sci.hiroshima-u.ac.jp/m-mat/MT/MT2002/CODES/mt19937ar.c
|
||||||
|
|
||||||
|
//A random generator based on the Mersenne Twister originally developed by Takuji Nishimura and Makoto Matsumoto.
|
||||||
|
// From the book GameCoding Complete by Mike McShaffry
|
||||||
|
|
||||||
|
/* Period parameters */
|
||||||
|
#define CMATH_N 624
|
||||||
|
#define CMATH_M 397
|
||||||
|
#define CMATH_MATRIX_A 0x9908b0df /* constant vector a */
|
||||||
|
#define CMATH_UPPER_MASK 0x80000000 /* most significant w-r bits */
|
||||||
|
#define CMATH_LOWER_MASK 0x7fffffff /* least significant r bits */
|
||||||
|
|
||||||
|
/* Tempering parameters */
|
||||||
|
#define CMATH_TEMPERING_MASK_B 0x9d2c5680
|
||||||
|
#define CMATH_TEMPERING_MASK_C 0xefc60000
|
||||||
|
#define CMATH_TEMPERING_SHIFT_U(y) (y >> 11)
|
||||||
|
#define CMATH_TEMPERING_SHIFT_S(y) (y << 7)
|
||||||
|
#define CMATH_TEMPERING_SHIFT_T(y) (y << 15)
|
||||||
|
#define CMATH_TEMPERING_SHIFT_L(y) (y >> 18)
|
||||||
|
|
||||||
|
int getTimeMs();
|
||||||
|
|
||||||
|
class Random
|
||||||
|
{
|
||||||
|
unsigned int rseed;
|
||||||
|
unsigned long mt[CMATH_N]; // the array for the state vector
|
||||||
|
int mti; // mti==N+1 means mt[N] is not initialized
|
||||||
|
|
||||||
|
public:
|
||||||
|
Random(long seed = getTimeMs());
|
||||||
|
void setSeed(long seed);
|
||||||
|
void init_genrand(unsigned long);
|
||||||
|
int nextInt(int max);
|
||||||
|
unsigned genrand_int32();
|
||||||
|
float nextFloat();
|
||||||
|
double genrand_real2();
|
||||||
|
long nextLong();
|
||||||
|
int nextInt();
|
||||||
|
};
|
||||||
1
source/Base/Synth.cpp
Normal file
1
source/Base/Synth.cpp
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#include "Synth.hpp"
|
||||||
8
source/Base/Synth.hpp
Normal file
8
source/Base/Synth.hpp
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class Synth
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual float getValue(float, float) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
39
source/Base/Timer.cpp
Normal file
39
source/Base/Timer.cpp
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#include "Timer.hpp"
|
||||||
|
#include "Utils.hpp"
|
||||||
|
|
||||||
|
void Timer::advanceTime()
|
||||||
|
{
|
||||||
|
int timeMs = getTimeMs();
|
||||||
|
if (timeMs - field_4 <= 1000)
|
||||||
|
{
|
||||||
|
if (timeMs - field_4 < 0)
|
||||||
|
{
|
||||||
|
field_4 = field_8 = timeMs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int diff1 = timeMs - field_4;
|
||||||
|
int diff2 = timeMs - field_8;
|
||||||
|
field_C += ((float(diff1) / float(diff2)) - field_C) * 0.2f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float diff = float(timeMs) / 1000.0f - field_0;
|
||||||
|
field_0 = float(timeMs) / 1000.0f;
|
||||||
|
|
||||||
|
float x1 = diff * field_C;
|
||||||
|
if (x1 > 1) x1 = 1;
|
||||||
|
if (x1 < 0) x1 = 0;
|
||||||
|
|
||||||
|
float x2 = field_20 + x1 * field_1C * field_10;
|
||||||
|
field_14 = int(x2);
|
||||||
|
field_20 = x2 - field_14;
|
||||||
|
field_18 = x2 - field_14;
|
||||||
|
if (field_14 > 10)
|
||||||
|
field_14 = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer::Timer()
|
||||||
|
{
|
||||||
|
field_4 = field_8 = getTimeMs();
|
||||||
|
}
|
||||||
21
source/Base/Timer.hpp
Normal file
21
source/Base/Timer.hpp
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class Timer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Timer();
|
||||||
|
|
||||||
|
void advanceTime();
|
||||||
|
|
||||||
|
public:
|
||||||
|
float field_0 = 0;
|
||||||
|
int field_4 = 0;
|
||||||
|
int field_8 = 0;
|
||||||
|
float field_C = 1.0f;
|
||||||
|
float field_10 = 20.0f;
|
||||||
|
int field_14 = 0;
|
||||||
|
float field_18 = 0;
|
||||||
|
float field_1C = 1.0f;
|
||||||
|
float field_20 = 0;
|
||||||
|
};
|
||||||
|
|
||||||
83
source/Base/Util.cpp
Normal file
83
source/Base/Util.cpp
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
/********************************************************************
|
||||||
|
Minecraft: Pocket Edition - Decompilation Project
|
||||||
|
Copyright (C) 2023 iProgramInCpp
|
||||||
|
|
||||||
|
Util.cpp
|
||||||
|
|
||||||
|
The following code is licensed under the following license:
|
||||||
|
< no license yet :( >
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include "Util.hpp"
|
||||||
|
|
||||||
|
std::string Util::stringTrim(const std::string& str, const std::string& filter, bool a4, bool a5)
|
||||||
|
{
|
||||||
|
if (str.empty() || filter.empty())
|
||||||
|
return "";
|
||||||
|
|
||||||
|
// don't know what the fuck this does. TODO: clean this crap up
|
||||||
|
if (!a4 && !a5)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
int v12, strIndex = 0, v13, v17, strLength = int(str.size()), filterLength = int(filter.size());
|
||||||
|
|
||||||
|
if (a4)
|
||||||
|
{
|
||||||
|
v12 = strLength - 1;
|
||||||
|
if (strLength > 0)
|
||||||
|
{
|
||||||
|
v17 = strLength - 1;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
const void* v14 = memchr(filter.c_str(), str[strIndex], filterLength);
|
||||||
|
if (!v14)
|
||||||
|
{
|
||||||
|
v13 = strIndex;
|
||||||
|
v12 = v17;
|
||||||
|
goto label_12;
|
||||||
|
}
|
||||||
|
|
||||||
|
++strIndex;
|
||||||
|
} while (strIndex != strLength);
|
||||||
|
|
||||||
|
v12 = strLength - 1;
|
||||||
|
v13 = strIndex;
|
||||||
|
}
|
||||||
|
else v13 = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (a5)
|
||||||
|
{
|
||||||
|
v12 = strLength - 1;
|
||||||
|
strIndex = 0;
|
||||||
|
v13 = 0;
|
||||||
|
|
||||||
|
goto label_19;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
label_12:
|
||||||
|
if (a5)
|
||||||
|
{
|
||||||
|
v13 = strIndex;
|
||||||
|
label_19:
|
||||||
|
while (v12 >= strIndex)
|
||||||
|
{
|
||||||
|
const void* v15 = memchr(filter.c_str(), str[strIndex], filterLength);
|
||||||
|
if (!v15)
|
||||||
|
break;
|
||||||
|
--v12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string(str, v13, v12 - 1 + strIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Util::stringTrim(const std::string& str)
|
||||||
|
{
|
||||||
|
return stringTrim(str, " \t\n\r", true, true);
|
||||||
|
}
|
||||||
|
|
||||||
72
source/Base/Util.hpp
Normal file
72
source/Base/Util.hpp
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/********************************************************************
|
||||||
|
Minecraft: Pocket Edition - Decompilation Project
|
||||||
|
Copyright (C) 2023 iProgramInCpp
|
||||||
|
|
||||||
|
Util.cpp
|
||||||
|
|
||||||
|
The following code is licensed under the following license:
|
||||||
|
< no license yet :( >
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class Util
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::string stringTrim(const std::string &, const std::string &, bool, bool);
|
||||||
|
static std::string stringTrim(const std::string &);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static bool remove(std::vector<T>& vec, const T& t)
|
||||||
|
{
|
||||||
|
auto iter = std::find(vec.begin(), vec.end(), t);
|
||||||
|
if (iter == vec.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
vec.erase(iter);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static int removeAll(std::vector<T>& vec, const std::vector<T>& toRemove)
|
||||||
|
{
|
||||||
|
int removed = 0;
|
||||||
|
|
||||||
|
for (auto rem : toRemove)
|
||||||
|
{
|
||||||
|
if (remove(vec, rem))
|
||||||
|
removed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @TODO: reverse the actual thing? This is something different, but I'm lazy. It uses std::string::replace
|
||||||
|
static void stringReplace(std::string& in, const std::string& what, const std::string& with)
|
||||||
|
{
|
||||||
|
//snippet from Zahlman's post on gamedev: http://www.gamedev.net/community/forums/topic.asp?topic_id=372125
|
||||||
|
size_t pos = 0;
|
||||||
|
size_t whatLen = what.length();
|
||||||
|
size_t withLen = with.length();
|
||||||
|
while ((pos = in.find(what, pos)) != std::string::npos)
|
||||||
|
{
|
||||||
|
in.replace(pos, whatLen, with);
|
||||||
|
pos += withLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static long hashCode(const std::string& str)
|
||||||
|
{
|
||||||
|
long result = 0;
|
||||||
|
|
||||||
|
for (auto chr : str)
|
||||||
|
{
|
||||||
|
result = result * 31 + chr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
218
source/Base/Utils.cpp
Normal file
218
source/Base/Utils.cpp
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
/********************************************************************
|
||||||
|
Minecraft: Pocket Edition - Decompilation Project
|
||||||
|
Copyright (C) 2023 iProgramInCpp
|
||||||
|
|
||||||
|
Utils.cpp
|
||||||
|
|
||||||
|
The following code is licensed under the following license:
|
||||||
|
< no license yet :( >
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
// note: not an official file name
|
||||||
|
|
||||||
|
#include "Utils.hpp"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
// Why are we not using GetTickCount64()? It's simple -- getTimeMs has the exact same problem as using regular old GetTickCount.
|
||||||
|
#pragma warning(disable : 28159)
|
||||||
|
#else
|
||||||
|
#include <sys/time.h>
|
||||||
|
#endif
|
||||||
|
#include "compat/GL.hpp"
|
||||||
|
|
||||||
|
int g_TimeSecondsOnInit = 0;
|
||||||
|
|
||||||
|
const char* GetTerrainName()
|
||||||
|
{
|
||||||
|
return "terrain.png";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* GetItemsName()
|
||||||
|
{
|
||||||
|
return "gui/items.png";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* GetGUIBlocksName()
|
||||||
|
{
|
||||||
|
return "gui/gui_blocks.png";
|
||||||
|
}
|
||||||
|
|
||||||
|
// In regular mode, getTimeMs depends on getTimeS.
|
||||||
|
// In Win32 mode, it's vice versa. Cool
|
||||||
|
|
||||||
|
int getTimeMs();
|
||||||
|
|
||||||
|
float getTimeS()
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
return float(getTimeMs()) / 1000.0f;
|
||||||
|
#else
|
||||||
|
// variant implemented by Mojang. This does not work on MSVC
|
||||||
|
timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
|
||||||
|
if (g_TimeSecondsOnInit == 0)
|
||||||
|
g_TimeSecondsOnInit = tv.tv_sec;
|
||||||
|
|
||||||
|
return float(tv.tv_sec - g_TimeSecondsOnInit) + float(tv.tv_usec) / 1000000.0f;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int getTimeMs()
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
// just return GetTickCount
|
||||||
|
int time = GetTickCount();
|
||||||
|
|
||||||
|
if (g_TimeSecondsOnInit == 0)
|
||||||
|
g_TimeSecondsOnInit = time;
|
||||||
|
|
||||||
|
return time - g_TimeSecondsOnInit;
|
||||||
|
#else
|
||||||
|
return int(getTimeS() * 1000.0f);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t getRawTimeS()
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
return time_t(GetTickCount() / 1000);
|
||||||
|
#else
|
||||||
|
timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
|
||||||
|
return tv.tv_sec;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t getEpochTimeS()
|
||||||
|
{
|
||||||
|
return time(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
HINSTANCE g_hInstance = NULL;
|
||||||
|
HWND g_hWnd = NULL;
|
||||||
|
|
||||||
|
void SetInstance(HINSTANCE hinst)
|
||||||
|
{
|
||||||
|
g_hInstance = hinst;
|
||||||
|
}
|
||||||
|
|
||||||
|
HINSTANCE GetInstance()
|
||||||
|
{
|
||||||
|
return g_hInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetHWND(HWND hwnd)
|
||||||
|
{
|
||||||
|
g_hWnd = hwnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
HWND GetHWND()
|
||||||
|
{
|
||||||
|
return g_hWnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CenterWindow(HWND hWnd)
|
||||||
|
{
|
||||||
|
RECT r, desk;
|
||||||
|
GetWindowRect(hWnd, &r);
|
||||||
|
GetWindowRect(GetDesktopWindow(), &desk);
|
||||||
|
|
||||||
|
int wa, ha, wb, hb;
|
||||||
|
|
||||||
|
wa = (r.right - r.left) / 2;
|
||||||
|
ha = (r.bottom - r.top) / 2;
|
||||||
|
|
||||||
|
wb = (desk.right - desk.left) / 2;
|
||||||
|
hb = (desk.bottom - desk.top) / 2;
|
||||||
|
|
||||||
|
SetWindowPos(hWnd, NULL, wb - wa, hb - ha, r.right - r.left, r.bottom - r.top, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnableOpenGL(HWND hwnd, HDC* hDC, HGLRC* hRC)
|
||||||
|
{
|
||||||
|
PIXELFORMATDESCRIPTOR pfd;
|
||||||
|
|
||||||
|
int iFormat;
|
||||||
|
|
||||||
|
/* get the device context (DC) */
|
||||||
|
*hDC = GetDC(hwnd);
|
||||||
|
|
||||||
|
/* set the pixel format for the DC */
|
||||||
|
ZeroMemory(&pfd, sizeof(pfd));
|
||||||
|
|
||||||
|
pfd.nSize = sizeof(pfd);
|
||||||
|
pfd.nVersion = 1;
|
||||||
|
pfd.dwFlags = PFD_DRAW_TO_WINDOW |
|
||||||
|
PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
||||||
|
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||||
|
pfd.cColorBits = 24;
|
||||||
|
pfd.cDepthBits = 16;
|
||||||
|
pfd.iLayerType = PFD_MAIN_PLANE;
|
||||||
|
|
||||||
|
iFormat = ChoosePixelFormat(*hDC, &pfd);
|
||||||
|
|
||||||
|
SetPixelFormat(*hDC, iFormat, &pfd);
|
||||||
|
|
||||||
|
/* create and enable the render context (RC) */
|
||||||
|
*hRC = wglCreateContext(*hDC);
|
||||||
|
|
||||||
|
wglMakeCurrent(*hDC, *hRC);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisableOpenGL(HWND hwnd, HDC hDC, HGLRC hRC)
|
||||||
|
{
|
||||||
|
wglMakeCurrent(NULL, NULL);
|
||||||
|
wglDeleteContext(hRC);
|
||||||
|
ReleaseDC(hwnd, hDC);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sleepMs(int ms)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
Sleep(ms);
|
||||||
|
#else
|
||||||
|
usleep(1000 * ms);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void drawArrayVT(GLuint buffer, int count, int stride)
|
||||||
|
{
|
||||||
|
xglBindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, stride, (void*)12);
|
||||||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glVertexPointer(3, GL_FLOAT, stride, nullptr);
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, count);
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawArrayVTC(GLuint buffer, int count, int stride)
|
||||||
|
{
|
||||||
|
xglBindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||||
|
glVertexPointer(3, GL_FLOAT, stride, nullptr);
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, stride, (void*)12);
|
||||||
|
glColorPointer(4, GL_UNSIGNED_BYTE, stride, (void*)20);
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, count);
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glDisableClientState(GL_COLOR_ARRAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
float Max(float a, float b)
|
||||||
|
{
|
||||||
|
if (a < b)
|
||||||
|
a = b;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
568
source/Base/Utils.hpp
Normal file
568
source/Base/Utils.hpp
Normal file
@@ -0,0 +1,568 @@
|
|||||||
|
/********************************************************************
|
||||||
|
Minecraft: Pocket Edition - Decompilation Project
|
||||||
|
Copyright (C) 2023 iProgramInCpp
|
||||||
|
|
||||||
|
Utils.hpp
|
||||||
|
|
||||||
|
The following code is licensed under the following license:
|
||||||
|
< no license yet :( >
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
#include <cstdio> // have to include this to avoid it being included again later from being a problem
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
// @HACK: Include WinSock2.h also
|
||||||
|
#include <WinSock2.h>
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <WS2tcpip.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "compat/AKeyCodes.hpp"
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
// Enhancements
|
||||||
|
//#define ENH_ENTITY_SHADING // Allows shading of entities
|
||||||
|
//#define ENH_SHADE_HELD_TILES // Allows shading of the item in hand
|
||||||
|
//#define ENH_FIX_INVIS_STAIRS // Fixes a bug wherein a 16x16x16 chunk in the world that contains only stairs is invisible
|
||||||
|
//#define ENH_ALLOW_AO // Allows using the F4 key to toggle ambient occlusion (buggy)
|
||||||
|
//#define ENH_TRANSPARENT_HOTBAR // Allows the hotbar to be transparent. Due to a bug in the code, it is not.
|
||||||
|
//#define ENH_INSTA_BREAK // Allows instant breaking of blocks. @TODO: Fix the mode without this
|
||||||
|
//#define ENH_CAMERA_NO_PARTICLES // Hide particles from the view of a camera, such as smoke, that would otherwise render the resulting image useless.
|
||||||
|
//#define ENH_USE_JAVA_LIGHT_RAMP // Use Java Beta 1.3 light ramp instead of flawed PE one
|
||||||
|
//#define ENH_RUN_DAY_NIGHT_CYCLE // Allow the day/night cycle to run.
|
||||||
|
//#define ENH_ENABLE_9TH_SLOT // Enable the 9th hotbar slot, instead of it being a "..." placeholder
|
||||||
|
//#define ENH_USE_OWN_AO // Use own ambient occlusion engine - looks pretty much the same except it fixes the corners
|
||||||
|
//#define ENH_ADD_OPTIONS_PAUSE // Add an 'options' button in the pause menu
|
||||||
|
//#define ENH_EXTRA_ITEMS_IN_INV // Add extra items in a new 5th row in the inventory.
|
||||||
|
//#define ENH_HIGHLIGHT_BY_HOVER // Highlight buttons by hovering them instead of the usual way.
|
||||||
|
//#define ENH_ALLOW_SAND_GRAVITY // Allow sand to fall.
|
||||||
|
//#define ENH_USE_GUI_SCALE_2 // Use a 2x GUI scale instead of 3x. Looks better on PC
|
||||||
|
|
||||||
|
// Mods
|
||||||
|
//#define MOD_USE_FLAT_WORLD // Use a flat world instead of the regular world generation
|
||||||
|
//#define MOD_USE_BIGGER_SCREEN_SIZE // Use a bigger screen size instead of 854x480
|
||||||
|
//#define MOD_DONT_COLOR_GRASS // Don't give the top of grass tiles a different color. (like Classic)
|
||||||
|
|
||||||
|
// Tests
|
||||||
|
//#define TEST_DROPPED_ITEMS // Allow dropped items to be dropped and collected.
|
||||||
|
|
||||||
|
// Toggle Demo Mode
|
||||||
|
#define DEMO
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define DEMO
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// don't know where to declare these:
|
||||||
|
|
||||||
|
#ifndef MOD_USE_BIGGER_SCREEN_SIZE
|
||||||
|
#define C_DEFAULT_SCREEN_WIDTH (854)
|
||||||
|
#define C_DEFAULT_SCREEN_HEIGHT (480)
|
||||||
|
#else
|
||||||
|
#define C_DEFAULT_SCREEN_WIDTH (1280)
|
||||||
|
#define C_DEFAULT_SCREEN_HEIGHT (720)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define C_MAX_TILES (256)
|
||||||
|
|
||||||
|
#define C_DEFAULT_PORT (19132)
|
||||||
|
#define C_MAX_CONNECTIONS (4) // pitiful
|
||||||
|
|
||||||
|
constexpr int C_MIN_X = -32000000, C_MAX_X = 32000000;
|
||||||
|
constexpr int C_MIN_Z = -32000000, C_MAX_Z = 32000000;
|
||||||
|
constexpr int C_MIN_Y = 0, C_MAX_Y = 128;
|
||||||
|
|
||||||
|
const char* GetTerrainName();
|
||||||
|
const char* GetItemsName();
|
||||||
|
const char* GetGUIBlocksName();
|
||||||
|
|
||||||
|
#ifdef ORIGINAL_CODE
|
||||||
|
#define C_TERRAIN_NAME "terrain.png"
|
||||||
|
#define C_ITEMS_NAME "gui/items.png"
|
||||||
|
#define C_BLOCKS_NAME "gui/gui_blocks.png"
|
||||||
|
#else
|
||||||
|
#define C_TERRAIN_NAME GetTerrainName()
|
||||||
|
#define C_ITEMS_NAME "gui/items.png"
|
||||||
|
#define C_BLOCKS_NAME "gui/gui_blocks.png"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define C_MAX_CHUNKS_X (16)
|
||||||
|
#define C_MAX_CHUNKS_Z (16)
|
||||||
|
|
||||||
|
// 9 chunks around a player things will tick
|
||||||
|
#define C_TICK_DISTANCE_CHKS (9)
|
||||||
|
|
||||||
|
enum eTileID
|
||||||
|
{
|
||||||
|
TILE_AIR,
|
||||||
|
TILE_STONE,
|
||||||
|
TILE_GRASS,
|
||||||
|
TILE_DIRT,
|
||||||
|
TILE_STONEBRICK,
|
||||||
|
TILE_WOOD,
|
||||||
|
|
||||||
|
TILE_BEDROCK = 7,
|
||||||
|
|
||||||
|
TILE_WATER = 8,
|
||||||
|
TILE_WATER_CALM,
|
||||||
|
TILE_LAVA,
|
||||||
|
TILE_LAVA_CALM,
|
||||||
|
|
||||||
|
TILE_SAND = 12,
|
||||||
|
TILE_GRAVEL,
|
||||||
|
TILE_ORE_GOLD,
|
||||||
|
TILE_ORE_IRON,
|
||||||
|
TILE_ORE_COAL,
|
||||||
|
|
||||||
|
TILE_TREE_TRUNK = 17,
|
||||||
|
TILE_LEAVES,
|
||||||
|
|
||||||
|
TILE_GLASS = 20,
|
||||||
|
TILE_ORE_LAPIS,
|
||||||
|
|
||||||
|
TILE_SANDSTONE = 24,
|
||||||
|
|
||||||
|
TILE_CLOTH = 35,
|
||||||
|
|
||||||
|
TILE_FLOWER = 37,
|
||||||
|
TILE_ROSE,
|
||||||
|
TILE_MUSHROOM_1,
|
||||||
|
TILE_MUSHROOM_2,
|
||||||
|
|
||||||
|
TILE_BLOCK_GOLD = 41,
|
||||||
|
TILE_BLOCK_IRON,
|
||||||
|
TILE_STONESLAB_FULL,
|
||||||
|
TILE_STONESLAB_HALF,
|
||||||
|
TILE_BRICKS,
|
||||||
|
TILE_TNT,
|
||||||
|
|
||||||
|
TILE_OBSIDIAN = 49,
|
||||||
|
TILE_TORCH,
|
||||||
|
TILE_FIRE,
|
||||||
|
|
||||||
|
TILE_STAIRS_WOOD = 53,
|
||||||
|
|
||||||
|
TILE_ORE_EMERALD = 56,
|
||||||
|
TILE_BLOCK_EMERALD,
|
||||||
|
|
||||||
|
TILE_FARMLAND = 60,
|
||||||
|
|
||||||
|
TILE_DOOR_WOOD = 64,
|
||||||
|
TILE_LADDER,
|
||||||
|
|
||||||
|
TILE_STAIRS_STONE = 67,
|
||||||
|
|
||||||
|
TILE_DOOR_IRON = 71,
|
||||||
|
|
||||||
|
TILE_ORE_REDSTONE = 73,
|
||||||
|
TILE_ORE_REDSTONE_LIT,
|
||||||
|
|
||||||
|
TILE_TOPSNOW = 78,
|
||||||
|
TILE_ICE,
|
||||||
|
|
||||||
|
TILE_CLAY = 82,
|
||||||
|
TILE_REEDS,
|
||||||
|
|
||||||
|
TILE_INVISIBLE = 95,
|
||||||
|
|
||||||
|
TILE_CLOTH_00 = 101,
|
||||||
|
TILE_CLOTH_10,
|
||||||
|
TILE_CLOTH_20,
|
||||||
|
TILE_CLOTH_30,
|
||||||
|
TILE_CLOTH_40,
|
||||||
|
TILE_CLOTH_50,
|
||||||
|
TILE_CLOTH_60,
|
||||||
|
TILE_CLOTH_70,
|
||||||
|
TILE_CLOTH_01,
|
||||||
|
TILE_CLOTH_11,
|
||||||
|
TILE_CLOTH_21,
|
||||||
|
TILE_CLOTH_31,
|
||||||
|
TILE_CLOTH_41,
|
||||||
|
TILE_CLOTH_51,
|
||||||
|
TILE_CLOTH_61,
|
||||||
|
|
||||||
|
ITEM_SHOVEL_IRON = 256,
|
||||||
|
ITEM_PICKAXE_IRON,
|
||||||
|
ITEM_HATCHET_IRON,
|
||||||
|
ITEM_FLINT_AND_STEEL,
|
||||||
|
ITEM_APPLE,
|
||||||
|
ITEM_BOW,
|
||||||
|
ITEM_ARROW,
|
||||||
|
ITEM_COAL,
|
||||||
|
ITEM_EMERALD,
|
||||||
|
ITEM_INGOT_IRON,
|
||||||
|
ITEM_INGOT_GOLD,
|
||||||
|
ITEM_SWORD_IRON,
|
||||||
|
ITEM_SWORD_WOOD,
|
||||||
|
ITEM_SHOVEL_WOOD,
|
||||||
|
ITEM_PICKAXE_WOOD,
|
||||||
|
ITEM_HATCHET_WOOD,
|
||||||
|
ITEM_SWORD_STONE,
|
||||||
|
ITEM_SHOVEL_STONE,
|
||||||
|
ITEM_PICKAXE_STONE,
|
||||||
|
ITEM_HATCHET_STONE,
|
||||||
|
ITEM_SWORD_EMERALD,
|
||||||
|
ITEM_SHOVEL_EMERALD,
|
||||||
|
ITEM_PICKAXE_EMERALD,
|
||||||
|
ITEM_HATCHET_EMERALD,
|
||||||
|
ITEM_STICK,
|
||||||
|
ITEM_BOWL,
|
||||||
|
ITEM_STEW_MUSHROOM,
|
||||||
|
ITEM_SWORD_GOLD,
|
||||||
|
ITEM_SHOVEL_GOLD,
|
||||||
|
ITEM_PICKAXE_GOLD,
|
||||||
|
ITEM_HATCHET_GOLD,
|
||||||
|
ITEM_STRING,
|
||||||
|
ITEM_FEATHER,
|
||||||
|
ITEM_SULPHUR,
|
||||||
|
ITEM_HOE_WOOD,
|
||||||
|
ITEM_HOE_STONE,
|
||||||
|
ITEM_HOE_IRON,
|
||||||
|
ITEM_HOE_EMERALD,
|
||||||
|
ITEM_HOE_GOLD,
|
||||||
|
ITEM_SEEDS,
|
||||||
|
ITEM_WHEAT,
|
||||||
|
ITEM_BREAD,
|
||||||
|
ITEM_HELMET_CLOTH,
|
||||||
|
ITEM_CHESTPLATE_CLOTH,
|
||||||
|
ITEM_LEGGINGS_CLOTH,
|
||||||
|
ITEM_BOOTS_CLOTH,
|
||||||
|
ITEM_HELMET_CHAIN,
|
||||||
|
ITEM_CHESTPLATE_CHAIN,
|
||||||
|
ITEM_LEGGINGS_CHAIN,
|
||||||
|
ITEM_BOOTS_CHAIN,
|
||||||
|
ITEM_HELMET_IRON,
|
||||||
|
ITEM_CHESTPLATE_IRON,
|
||||||
|
ITEM_LEGGINGS_IRON,
|
||||||
|
ITEM_BOOTS_IRON,
|
||||||
|
ITEM_HELMET_EMERALD,
|
||||||
|
ITEM_CHESTPLATE_EMERALD,
|
||||||
|
ITEM_LEGGINGS_EMERALD,
|
||||||
|
ITEM_BOOTS_EMERALD,
|
||||||
|
ITEM_HELMET_GOLD,
|
||||||
|
ITEM_CHESTPLATE_GOLD,
|
||||||
|
ITEM_LEGGINGS_GOLD,
|
||||||
|
ITEM_BOOTS_GOLD,
|
||||||
|
ITEM_FLINT,
|
||||||
|
ITEM_PORKCHOP_RAW,
|
||||||
|
ITEM_PORKCHOP_COOKED,
|
||||||
|
ITEM_PAINTING,
|
||||||
|
ITEM_APPLE_GOLD,
|
||||||
|
ITEM_SIGN,
|
||||||
|
ITEM_DOOR_WOOD,
|
||||||
|
ITEM_BUCKET,
|
||||||
|
ITEM_BUCKET_WATER,
|
||||||
|
ITEM_BUCKET_LAVA,
|
||||||
|
ITEM_MINECART,
|
||||||
|
ITEM_SADDLE,
|
||||||
|
ITEM_DOOR_IRON,
|
||||||
|
ITEM_REDSTONE,
|
||||||
|
ITEM_SNOWBALL,
|
||||||
|
ITEM_BOAT,
|
||||||
|
ITEM_LEATHER,
|
||||||
|
ITEM_BUCKET_MILK,
|
||||||
|
ITEM_BRICK,
|
||||||
|
ITEM_CLAY,
|
||||||
|
ITEM_REEDS,
|
||||||
|
ITEM_PAPER,
|
||||||
|
ITEM_BOOK,
|
||||||
|
ITEM_SLIME_BALL,
|
||||||
|
ITEM_MINECART_CHEST,
|
||||||
|
ITEM_MINECART_FURNACE,
|
||||||
|
ITEM_EGG,
|
||||||
|
ITEM_COMPASS,
|
||||||
|
ITEM_FISHING_ROD,
|
||||||
|
ITEM_CLOCK,
|
||||||
|
ITEM_YELLOW_DUST,
|
||||||
|
ITEM_FISH_RAW,
|
||||||
|
ITEM_FISH_COOKED,
|
||||||
|
ITEM_DYE_POWDER,
|
||||||
|
ITEM_BONE,
|
||||||
|
ITEM_SUGAR,
|
||||||
|
ITEM_CAKE,
|
||||||
|
ITEM_BED,
|
||||||
|
ITEM_DIODE,
|
||||||
|
ITEM_COOKIE,
|
||||||
|
ITEM_RECORD_01,
|
||||||
|
ITEM_RECORD_02,
|
||||||
|
ITEM_CAMERA = 456,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum // Textures
|
||||||
|
{
|
||||||
|
TEXTURE_GRASS_TOP = 0,
|
||||||
|
TEXTURE_STONE,
|
||||||
|
TEXTURE_DIRT,
|
||||||
|
TEXTURE_GRASS_SIDE,
|
||||||
|
TEXTURE_PLANKS,
|
||||||
|
TEXTURE_STONE_SLAB_SIDE,
|
||||||
|
TEXTURE_STONE_SLAB_TOP,
|
||||||
|
TEXTURE_BRICKS,
|
||||||
|
TEXTURE_TNT_SIDE,
|
||||||
|
TEXTURE_TNT_TOP,
|
||||||
|
TEXTURE_TNT_BOTTOM,
|
||||||
|
TEXTURE_COBWEB,
|
||||||
|
TEXTURE_ROSE,
|
||||||
|
TEXTURE_FLOWER,
|
||||||
|
TEXTURE_WATER_STATIC,
|
||||||
|
TEXTURE_SAPLING,
|
||||||
|
TEXTURE_STONEBRICK,
|
||||||
|
TEXTURE_BEDROCK,
|
||||||
|
TEXTURE_SAND,
|
||||||
|
TEXTURE_GRAVEL,
|
||||||
|
TEXTURE_LOG_SIDE,
|
||||||
|
TEXTURE_LOG_TOP,
|
||||||
|
TEXTURE_IRON,
|
||||||
|
TEXTURE_GOLD,
|
||||||
|
TEXTURE_EMERALD,
|
||||||
|
TEXTURE_CHEST_ONE_TOP,
|
||||||
|
TEXTURE_CHEST_ONE_SIDE,
|
||||||
|
TEXTURE_CHEST_ONE_FRONT,
|
||||||
|
TEXTURE_MUSHROOM_RED,
|
||||||
|
TEXTURE_MUSHROOM_BROWN,
|
||||||
|
TEXTURE_NONE30,
|
||||||
|
TEXTURE_FIRE1,
|
||||||
|
TEXTURE_ORE_GOLD,
|
||||||
|
TEXTURE_ORE_IRON,
|
||||||
|
TEXTURE_ORE_COAL,
|
||||||
|
TEXTURE_BOOKSHELF,
|
||||||
|
TEXTURE_MOSSY_STONE,
|
||||||
|
TEXTURE_OBSIDIAN,
|
||||||
|
TEXTURE_OBSIDIAN_CRYING,
|
||||||
|
TEXTURE_NONE39,
|
||||||
|
TEXTURE_NONE40,
|
||||||
|
TEXTURE_CHEST_TWO_FRONT_LEFT,
|
||||||
|
TEXTURE_CHEST_TWO_FRONT_RIGHT,
|
||||||
|
TEXTURE_WORKBENCH_TOP,
|
||||||
|
TEXTURE_FURNACE_FRONT,
|
||||||
|
TEXTURE_FURNACE_SIDE,
|
||||||
|
TEXTURE_DISPENSER_SIDE,
|
||||||
|
TEXTURE_FIRE2,
|
||||||
|
TEXTURE_SPONGE,
|
||||||
|
TEXTURE_GLASS,
|
||||||
|
TEXTURE_ORE_EMERALD,
|
||||||
|
TEXTURE_ORE_RED_STONE,
|
||||||
|
TEXTURE_LEAVES_TRANSPARENT,
|
||||||
|
TEXTURE_LEAVES_OPAQUE,
|
||||||
|
TEXTURE_NONE54,
|
||||||
|
TEXTURE_NONE55,
|
||||||
|
TEXTURE_NONE56,
|
||||||
|
TEXTURE_CHEST_TWO_BACK_LEFT,
|
||||||
|
TEXTURE_CHEST_TWO_BACK_RIGHT,
|
||||||
|
TEXTURE_WORKBENCH_SIDE_1,
|
||||||
|
TEXTURE_WORKBENCH_SIDE_2,
|
||||||
|
TEXTURE_FURNACE_LIT,
|
||||||
|
TEXTURE_FURNACE_TOP,
|
||||||
|
TEXTURE_NONE63,
|
||||||
|
TEXTURE_CLOTH_64,
|
||||||
|
TEXTURE_SPAWNER,
|
||||||
|
TEXTURE_SNOW,
|
||||||
|
TEXTURE_ICE,
|
||||||
|
TEXTURE_GRASS_SIDE_SNOW,
|
||||||
|
TEXTURE_CACTUS_TOP,
|
||||||
|
TEXTURE_CACTUS_SIDE,
|
||||||
|
TEXTURE_CACTUS_BOTTOM,
|
||||||
|
TEXTURE_CLAY,
|
||||||
|
TEXTURE_REEDS,
|
||||||
|
TEXTURE_JUKEBOX_SIDE,
|
||||||
|
TEXTURE_JUKEBOX_TOP,
|
||||||
|
TEXTURE_NONE76,
|
||||||
|
TEXTURE_NONE77,
|
||||||
|
TEXTURE_NONE78,
|
||||||
|
TEXTURE_NONE79,
|
||||||
|
TEXTURE_TORCH_LIT,
|
||||||
|
TEXTURE_DOOR_TOP,
|
||||||
|
TEXTURE_DOOR_IRON_TOP,
|
||||||
|
TEXTURE_LADDER,
|
||||||
|
TEXTURE_NONE84,
|
||||||
|
TEXTURE_NONE85,
|
||||||
|
TEXTURE_FARMLAND,
|
||||||
|
TEXTURE_FARMLAND_DRY,
|
||||||
|
TEXTURE_WHEAT_0,
|
||||||
|
TEXTURE_WHEAT_1,
|
||||||
|
TEXTURE_WHEAT_2,
|
||||||
|
TEXTURE_WHEAT_3,
|
||||||
|
TEXTURE_WHEAT_4,
|
||||||
|
TEXTURE_WHEAT_5,
|
||||||
|
TEXTURE_WHEAT_6,
|
||||||
|
TEXTURE_WHEAT_7,
|
||||||
|
TEXTURE_LEVER,
|
||||||
|
TEXTURE_DOOR_BOTTOM,
|
||||||
|
TEXTURE_DOOR_IRON_BOTTOM,
|
||||||
|
TEXTURE_TORCH_RED_STONE,
|
||||||
|
TEXTURE_NONE100,
|
||||||
|
TEXTURE_NONE101,
|
||||||
|
TEXTURE_PUMPKIN_TOP,
|
||||||
|
TEXTURE_BLOODSTONE,
|
||||||
|
TEXTURE_SOULSAND,
|
||||||
|
TEXTURE_GLOWSTONE,
|
||||||
|
TEXTURE_NONE106,
|
||||||
|
TEXTURE_NONE107,
|
||||||
|
TEXTURE_NONE108,
|
||||||
|
TEXTURE_NONE109,
|
||||||
|
TEXTURE_NONE110,
|
||||||
|
TEXTURE_NONE111,
|
||||||
|
TEXTURE_RAIL_CURVED,
|
||||||
|
TEXTURE_CLOTH_112,
|
||||||
|
TEXTURE_CLOTH_113,
|
||||||
|
TEXTURE_TORCH_RED_STONE_OFF,
|
||||||
|
TEXTURE_LOG_SPRUCE,
|
||||||
|
TEXTURE_LOG_BIRCH,
|
||||||
|
TEXTURE_PUMPKIN_SIDE,
|
||||||
|
TEXTURE_PUMPKIN_FACE,
|
||||||
|
TEXTURE_PUMPKIN_FACE_LIT,
|
||||||
|
TEXTURE_CAKE_TOP,
|
||||||
|
TEXTURE_CAKE_SIDE,
|
||||||
|
TEXTURE_CAKE_SIDE_BIT,
|
||||||
|
TEXTURE_CAKE_BOTTOM,
|
||||||
|
TEXTURE_NONE125,
|
||||||
|
TEXTURE_NONE126,
|
||||||
|
TEXTURE_NONE127,
|
||||||
|
|
||||||
|
TEXTURE_ORE_LAPIS = 160,
|
||||||
|
|
||||||
|
TEXTURE_SANDSTONE_TOP = 176,
|
||||||
|
TEXTURE_SANDSTONE_SIDE = 192,
|
||||||
|
TEXTURE_WATER = 205,
|
||||||
|
TEXTURE_SANDSTONE_BOTTOM = 208,
|
||||||
|
|
||||||
|
TEXTURE_LAVA = 237,
|
||||||
|
|
||||||
|
TEXTURE_LAVA_PLACEHOLDER = 255,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum eRenderShape
|
||||||
|
{
|
||||||
|
SHAPE_NONE = -1,
|
||||||
|
SHAPE_SOLID,
|
||||||
|
SHAPE_CROSS,
|
||||||
|
SHAPE_TORCH,
|
||||||
|
SHAPE_FIRE,
|
||||||
|
SHAPE_WATER,
|
||||||
|
SHAPE_UNK5,
|
||||||
|
SHAPE_UNK6,
|
||||||
|
SHAPE_DOOR,
|
||||||
|
SHAPE_LADDER,
|
||||||
|
SHAPE_UNK9,
|
||||||
|
SHAPE_STAIRS,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum eRenderLayer
|
||||||
|
{
|
||||||
|
LAYER_OPAQUE,
|
||||||
|
LAYER_ALPHA
|
||||||
|
};
|
||||||
|
|
||||||
|
enum eDirection
|
||||||
|
{
|
||||||
|
DIR_YNEG,
|
||||||
|
DIR_YPOS,
|
||||||
|
DIR_ZNEG, // North
|
||||||
|
DIR_ZPOS, // South
|
||||||
|
DIR_XNEG, // West
|
||||||
|
DIR_XPOS, // East
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChunkPos
|
||||||
|
{
|
||||||
|
int x = 0, z = 0;
|
||||||
|
ChunkPos() {}
|
||||||
|
ChunkPos(int _x, int _z) : x(_x), z(_z) {}
|
||||||
|
|
||||||
|
bool operator<(const ChunkPos& b) const
|
||||||
|
{
|
||||||
|
if (x != b.x)
|
||||||
|
return x < b.x;
|
||||||
|
|
||||||
|
return z < b.z;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Pos
|
||||||
|
{
|
||||||
|
int x = 0, y = 0, z = 0;
|
||||||
|
Pos() {}
|
||||||
|
Pos(int _x, int _y, int _z) : x(_x), y(_y), z(_z) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// @NOTE: Duplicate?
|
||||||
|
struct TilePos
|
||||||
|
{
|
||||||
|
int x = 0, y = 0, z = 0;
|
||||||
|
TilePos() {}
|
||||||
|
TilePos(int _x, int _y, int _z) : x(_x), y(_y), z(_z) {}
|
||||||
|
|
||||||
|
bool operator<(const TilePos& b) const
|
||||||
|
{
|
||||||
|
if (x != b.x)
|
||||||
|
return x < b.x;
|
||||||
|
if (y != b.y)
|
||||||
|
return y < b.y;
|
||||||
|
|
||||||
|
return z < b.z;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SAFE_DELETE(ptr) do { if (ptr) delete ptr; } while (0)
|
||||||
|
#define SAFE_DELETE_ARRAY(ptr) do { if (ptr) delete[] ptr; } while (0)
|
||||||
|
|
||||||
|
typedef uint8_t TileID;
|
||||||
|
|
||||||
|
// functions from Mojang
|
||||||
|
time_t getEpochTimeS();
|
||||||
|
time_t getRawTimeS();
|
||||||
|
float getTimeS();
|
||||||
|
int getTimeMs();
|
||||||
|
|
||||||
|
float Max(float a, float b);
|
||||||
|
|
||||||
|
void sleepMs(int ms);
|
||||||
|
|
||||||
|
// @NOTE: This is inlined.
|
||||||
|
constexpr float Lerp(float a, float b, float progress)
|
||||||
|
{
|
||||||
|
return a + progress * (b - a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// things that we added:
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
|
||||||
|
void LogMsg(const char* fmt, ...); // not part of actual Minecraft (they use printf), but useful
|
||||||
|
void LogMsgNoCR(const char* fmt, ...); // not part of actual Minecraft (they use printf), but useful
|
||||||
|
|
||||||
|
#ifdef printf
|
||||||
|
#error "printf is defined. Why?"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define printf LogMsgNoCR
|
||||||
|
#define puts(str) LogMsg("%s", str);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
HINSTANCE GetInstance();
|
||||||
|
HWND GetHWND();
|
||||||
|
void CenterWindow(HWND hWnd);
|
||||||
|
void EnableOpenGL(HWND hwnd, HDC*, HGLRC*);
|
||||||
|
void DisableOpenGL(HWND, HDC, HGLRC);
|
||||||
|
|
||||||
|
void SetInstance(HINSTANCE hinst);
|
||||||
|
void SetHWND(HWND hwnd);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define LogMsg(...)
|
||||||
|
#define LogMsgNoCR(...)
|
||||||
|
|
||||||
|
#endif
|
||||||
91
source/Base/Vec3.cpp
Normal file
91
source/Base/Vec3.cpp
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
/********************************************************************
|
||||||
|
Minecraft: Pocket Edition - Decompilation Project
|
||||||
|
Copyright (C) 2023 iProgramInCpp
|
||||||
|
|
||||||
|
Vec3.cpp
|
||||||
|
|
||||||
|
The following code is licensed under the following license:
|
||||||
|
< no license yet :( >
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include "Vec3.hpp"
|
||||||
|
|
||||||
|
Vec3::Vec3() {}
|
||||||
|
|
||||||
|
Vec3::Vec3(float x, float y, float z)
|
||||||
|
{
|
||||||
|
this->x = x;
|
||||||
|
this->y = y;
|
||||||
|
this->z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 Vec3::normalize()
|
||||||
|
{
|
||||||
|
float dist = Mth::sqrt(x * x + y * y + z * z);
|
||||||
|
if (dist < 0.0001f)
|
||||||
|
return Vec3(0, 0, 0);
|
||||||
|
|
||||||
|
return Vec3(x / dist, y / dist, z / dist);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vec3::clipX(const Vec3& a2, float a3, Vec3& a4) const
|
||||||
|
{
|
||||||
|
float crap = a2.x - this->x;
|
||||||
|
if (crap * crap < 0.000001f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
float crap2 = (a3 - this->x) / crap;
|
||||||
|
if (crap2 < 0.0f || crap2 > 1.0f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
a4.x = x + (a2.x - x) * crap2;
|
||||||
|
a4.y = y + (a2.y - y) * crap2;
|
||||||
|
a4.z = z + (a2.z - z) * crap2;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vec3::clipY(const Vec3& a2, float a3, Vec3& a4) const
|
||||||
|
{
|
||||||
|
float crap = a2.y - this->y;
|
||||||
|
if (crap * crap < 0.000001f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
float crap2 = (a3 - this->y) / crap;
|
||||||
|
if (crap2 < 0.0f || crap2 > 1.0f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
a4.x = x + (a2.x - x) * crap2;
|
||||||
|
a4.y = y + (a2.y - y) * crap2;
|
||||||
|
a4.z = z + (a2.z - z) * crap2;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vec3::clipZ(const Vec3& a2, float a3, Vec3& a4) const
|
||||||
|
{
|
||||||
|
float crap = a2.z - this->z;
|
||||||
|
if (crap * crap < 0.000001f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
float crap2 = (a3 - this->z) / crap;
|
||||||
|
if (crap2 < 0.0f || crap2 > 1.0f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
a4.x = x + (a2.x - x) * crap2;
|
||||||
|
a4.y = y + (a2.y - y) * crap2;
|
||||||
|
a4.z = z + (a2.z - z) * crap2;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Vec3::distanceToSqr(const Vec3& b) const
|
||||||
|
{
|
||||||
|
float xd = (x-b.x);
|
||||||
|
float yd = (y-b.y);
|
||||||
|
float zd = (z-b.z);
|
||||||
|
|
||||||
|
return xd * xd + yd * yd + zd * zd;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Vec3::distanceTo(const Vec3& b) const
|
||||||
|
{
|
||||||
|
return Mth::sqrt(distanceToSqr(b));
|
||||||
|
}
|
||||||
81
source/Base/Vec3.hpp
Normal file
81
source/Base/Vec3.hpp
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/********************************************************************
|
||||||
|
Minecraft: Pocket Edition - Decompilation Project
|
||||||
|
Copyright (C) 2023 iProgramInCpp
|
||||||
|
|
||||||
|
Vec3.hpp
|
||||||
|
|
||||||
|
The following code is licensed under the following license:
|
||||||
|
< no license yet :( >
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Mth.hpp"
|
||||||
|
|
||||||
|
class Vec3
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
float x = 0;
|
||||||
|
float y = 0;
|
||||||
|
float z = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool clipX(const Vec3& a2, float a3, Vec3& a4) const;
|
||||||
|
bool clipY(const Vec3& a2, float a3, Vec3& a4) const;
|
||||||
|
bool clipZ(const Vec3& a2, float a3, Vec3& a4) const;
|
||||||
|
Vec3 normalize();
|
||||||
|
|
||||||
|
// this constructor is nice to have, but it's probably inlined
|
||||||
|
Vec3();
|
||||||
|
Vec3(float x, float y, float z);
|
||||||
|
|
||||||
|
// these are likely inlined
|
||||||
|
float distanceTo(const Vec3& b) const;
|
||||||
|
float distanceToSqr(const Vec3& b) const;
|
||||||
|
|
||||||
|
// these are also likely inlined, but I'll declare them in the header
|
||||||
|
Vec3 operator+(const Vec3& b)
|
||||||
|
{
|
||||||
|
return Vec3(x + b.x, y + b.y, z + b.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 operator-(const Vec3& b)
|
||||||
|
{
|
||||||
|
return Vec3(x - b.x, y - b.y, z - b.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator+=(const Vec3& b)
|
||||||
|
{
|
||||||
|
x += b.x;
|
||||||
|
y += b.y;
|
||||||
|
z += b.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator-=(const Vec3& b)
|
||||||
|
{
|
||||||
|
(*this) += -b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator*=(float f)
|
||||||
|
{
|
||||||
|
x *= f;
|
||||||
|
y *= f;
|
||||||
|
z *= f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 operator-() const
|
||||||
|
{
|
||||||
|
return Vec3(-x, -y, -z);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 operator*(float f) const
|
||||||
|
{
|
||||||
|
return Vec3(f * x, f * y, f * z);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 translate(float tx, float ty, float tz) const
|
||||||
|
{
|
||||||
|
return Vec3(x + tx, y + ty, z + tz);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
31
source/GUI/AvailableGamesList.cpp
Normal file
31
source/GUI/AvailableGamesList.cpp
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#include "AvailableGamesList.hpp"
|
||||||
|
|
||||||
|
AvailableGamesList::AvailableGamesList(Minecraft* a, int b, int c, int d, int e, int f) :
|
||||||
|
ScrolledSelectionList(a, b, c, d, e, f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int AvailableGamesList::getNumberOfItems()
|
||||||
|
{
|
||||||
|
return int(m_games.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AvailableGamesList::isSelectedItem(int i)
|
||||||
|
{
|
||||||
|
return m_selectedIndex == i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvailableGamesList::renderBackground()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvailableGamesList::renderItem(int idx, int x, int y, int width, Tesselator& t)
|
||||||
|
{
|
||||||
|
drawString(m_pMinecraft->m_pFont, std::string(m_games[idx].m_name.C_String()), x, y + 2, 0xFFFFA0);
|
||||||
|
drawString(m_pMinecraft->m_pFont, std::string(m_games[idx].m_address.ToString()), x, y + 16, 0xFFFFA0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvailableGamesList::selectItem(int index, bool b)
|
||||||
|
{
|
||||||
|
m_selectedIndex = index;
|
||||||
|
}
|
||||||
20
source/GUI/AvailableGamesList.hpp
Normal file
20
source/GUI/AvailableGamesList.hpp
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ScrolledSelectionList.hpp"
|
||||||
|
#include "PingedCompatibleServer.hpp"
|
||||||
|
|
||||||
|
class AvailableGamesList : public ScrolledSelectionList
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AvailableGamesList(Minecraft*, int, int, int, int, int);
|
||||||
|
int getNumberOfItems() override;
|
||||||
|
bool isSelectedItem(int i) override;
|
||||||
|
void renderBackground() override;
|
||||||
|
void renderItem(int, int, int, int, Tesselator& t) override;
|
||||||
|
void selectItem(int, bool) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
int m_selectedIndex;
|
||||||
|
std::vector<PingedCompatibleServer> m_games;
|
||||||
|
};
|
||||||
|
|
||||||
89
source/GUI/Button.cpp
Normal file
89
source/GUI/Button.cpp
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
#include "Button.hpp"
|
||||||
|
|
||||||
|
Button::Button(int a2, int xPos, int yPos, int btnWidth, int btnHeight, const std::string& text)
|
||||||
|
{
|
||||||
|
field_30 = a2;
|
||||||
|
m_xPos = xPos;
|
||||||
|
m_yPos = yPos;
|
||||||
|
field_18 = text;
|
||||||
|
m_width = btnWidth;
|
||||||
|
m_height = btnHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
Button::Button(int a2, int xPos, int yPos, const std::string& text)
|
||||||
|
{
|
||||||
|
field_30 = a2;
|
||||||
|
m_xPos = xPos;
|
||||||
|
m_yPos = yPos;
|
||||||
|
field_18 = text;
|
||||||
|
m_width = 200;
|
||||||
|
m_height = 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
Button::Button(int a2, const std::string& text)
|
||||||
|
{
|
||||||
|
field_30 = a2;
|
||||||
|
field_18 = text;
|
||||||
|
m_width = 200;
|
||||||
|
m_height = 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Button::clicked(Minecraft* pMinecraft, int xPos, int yPos)
|
||||||
|
{
|
||||||
|
if (!m_bEnabled) return false;
|
||||||
|
if (xPos < m_xPos) return false;
|
||||||
|
if (yPos < m_yPos) return false;
|
||||||
|
if (xPos >= m_xPos + m_width) return false;
|
||||||
|
if (yPos >= m_yPos + m_height) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Button::getYImage(bool bHovered)
|
||||||
|
{
|
||||||
|
if (!m_bEnabled) return 0;
|
||||||
|
if (bHovered) return 2;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::released(int xPos, int yPos)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::renderBg(Minecraft*, int, int)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::render(Minecraft* pMinecraft, int xPos, int yPos)
|
||||||
|
{
|
||||||
|
if (!m_bVisible) return;
|
||||||
|
|
||||||
|
#ifdef ENH_HIGHLIGHT_BY_HOVER
|
||||||
|
field_36 = clicked(pMinecraft, xPos, yPos);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Font* pFont = pMinecraft->m_pFont;
|
||||||
|
Textures* pTexs = pMinecraft->m_pTextures;
|
||||||
|
|
||||||
|
pTexs->loadAndBindTexture("gui/gui.png");
|
||||||
|
|
||||||
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
int iYPos = 20 * getYImage(field_36) + 46;
|
||||||
|
|
||||||
|
blit(m_xPos, m_yPos, 0, iYPos, m_width / 2, m_height, 0, 20);
|
||||||
|
blit(m_xPos + m_width / 2, m_yPos, 200 - m_width / 2, iYPos, m_width / 2, m_height, 0, 20);
|
||||||
|
|
||||||
|
renderBg(pMinecraft, xPos, yPos);
|
||||||
|
|
||||||
|
int textColor;
|
||||||
|
if (!m_bEnabled)
|
||||||
|
textColor = int(0xFFA0A0A0U);
|
||||||
|
else if (field_36)
|
||||||
|
textColor = int(0xFFFFA0U);
|
||||||
|
else
|
||||||
|
textColor = int(0xE0E0E0U);
|
||||||
|
|
||||||
|
drawCenteredString(pFont, field_18, m_xPos + m_width / 2, m_yPos + (m_height - 8) / 2, textColor);
|
||||||
|
}
|
||||||
38
source/GUI/Button.hpp
Normal file
38
source/GUI/Button.hpp
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "GuiComponent.hpp"
|
||||||
|
#include "Minecraft.hpp"
|
||||||
|
|
||||||
|
class Screen;
|
||||||
|
|
||||||
|
class Button : public GuiComponent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Button(int, int x, int y, int width, int height, const std::string&);
|
||||||
|
Button(int, int x, int y, const std::string&);
|
||||||
|
Button(int, const std::string&);
|
||||||
|
|
||||||
|
// I can't possibly explain why Minecraft is referenced here
|
||||||
|
bool clicked(Minecraft*, int xPos, int yPos);
|
||||||
|
int getYImage(bool bHovered);
|
||||||
|
void released(int xPos, int yPos);
|
||||||
|
void renderBg(Minecraft*, int, int);
|
||||||
|
void render(Minecraft*, int xPos, int yPos);
|
||||||
|
|
||||||
|
public:
|
||||||
|
int m_width = 0;
|
||||||
|
int m_height = 0;
|
||||||
|
int m_xPos = 0;
|
||||||
|
int m_yPos = 0;
|
||||||
|
std::string field_18 = "";
|
||||||
|
int field_30;
|
||||||
|
bool m_bEnabled = true;
|
||||||
|
bool m_bVisible = true;
|
||||||
|
bool field_36 = false;
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
int m_lastX = 0;
|
||||||
|
int m_lastY = 0;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
402
source/GUI/Gui.cpp
Normal file
402
source/GUI/Gui.cpp
Normal file
@@ -0,0 +1,402 @@
|
|||||||
|
#include "Minecraft.hpp"
|
||||||
|
#include "IngameBlockSelectionScreen.hpp"
|
||||||
|
#include "ItemRenderer.hpp"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#pragma warning(disable : 4244)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENH_USE_GUI_SCALE_2
|
||||||
|
float Gui::InvGuiScale = 0.5f;
|
||||||
|
#else
|
||||||
|
float Gui::InvGuiScale = 0.333333f;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Gui::Gui(Minecraft* pMinecraft)
|
||||||
|
{
|
||||||
|
m_pMinecraft = pMinecraft;
|
||||||
|
|
||||||
|
xglGenBuffers(1, &m_renderChunk.field_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::addMessage(const std::string& s)
|
||||||
|
{
|
||||||
|
std::string str = s;
|
||||||
|
|
||||||
|
while (m_pMinecraft->m_pFont->width(str) > 320)
|
||||||
|
{
|
||||||
|
int i = 2;
|
||||||
|
for (; i < int(str.size()); i++)
|
||||||
|
{
|
||||||
|
std::string sstr = str.substr(0, i);
|
||||||
|
|
||||||
|
// this sucks
|
||||||
|
if (m_pMinecraft->m_pFont->width(sstr) > 320)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string sstr = str.substr(0, i - 1);
|
||||||
|
addMessage(sstr);
|
||||||
|
str = str.substr(i - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_guiMessages.size() > 50)
|
||||||
|
{
|
||||||
|
m_guiMessages.erase(m_guiMessages.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
m_guiMessages.insert(m_guiMessages.begin(), GuiMessage(str, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::setNowPlaying(const std::string& str)
|
||||||
|
{
|
||||||
|
field_A00 = "Now playing: " + str;
|
||||||
|
field_A18 = 60;
|
||||||
|
field_A1C = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::renderVignette(float a2, int a3, int a4)
|
||||||
|
{
|
||||||
|
a2 = 1.0f - a2;
|
||||||
|
if (a2 > 1.0f)
|
||||||
|
a2 = 1.0f;
|
||||||
|
if (a2 < 0.0f)
|
||||||
|
a2 = 0.0f;
|
||||||
|
|
||||||
|
field_A20 += ((a2 - field_A20) * 0.01f);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDepthMask(false);
|
||||||
|
glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
|
||||||
|
glColor4f(field_A20, field_A20, field_A20, 1.0f);
|
||||||
|
|
||||||
|
//! @BUG: No misc/vignette.png to be found in the original.
|
||||||
|
//! This function is unused anyways
|
||||||
|
m_pMinecraft->m_pTextures->loadAndBindTexture("misc/vignette.png");
|
||||||
|
|
||||||
|
Tesselator& t = Tesselator::instance;
|
||||||
|
t.begin();
|
||||||
|
t.vertexUV(0.0f, a4, -90.0f, 0.0f, 1.0f);
|
||||||
|
t.vertexUV(a3, a4, -90.0f, 1.0f, 1.0f);
|
||||||
|
t.vertexUV(a3, 0.0f, -90.0f, 1.0f, 0.0f);
|
||||||
|
t.vertexUV(0.0f, 0.0f, -90.0f, 0.0f, 0.0f);
|
||||||
|
t.draw();
|
||||||
|
|
||||||
|
glDepthMask(true);
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::inventoryUpdated()
|
||||||
|
{
|
||||||
|
field_A3C = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::render(float f, bool bHaveScreen, int mouseX, int mouseY)
|
||||||
|
{
|
||||||
|
Minecraft* m = m_pMinecraft;
|
||||||
|
|
||||||
|
m->m_pGameRenderer->setupGuiScreen();
|
||||||
|
|
||||||
|
if (!m->m_pLevel || !m->m_pLocalPlayer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
field_4 = -90.0f;
|
||||||
|
|
||||||
|
#ifndef ENH_TRANSPARENT_HOTBAR
|
||||||
|
glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
|
||||||
|
#else
|
||||||
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m->m_pTextures->loadAndBindTexture("gui/gui.png");
|
||||||
|
|
||||||
|
Inventory* pInventory = m->m_pLocalPlayer->m_pInventory;
|
||||||
|
|
||||||
|
field_4 = -90.0f;
|
||||||
|
|
||||||
|
int width = Minecraft::width * InvGuiScale,
|
||||||
|
height = Minecraft::height * InvGuiScale;
|
||||||
|
|
||||||
|
#ifdef ENH_TRANSPARENT_HOTBAR
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// hotbar
|
||||||
|
int cenX = width / 2;
|
||||||
|
blit(cenX - 182 / 2, height - 22, 0, 0, 182, 22, 0, 0);
|
||||||
|
|
||||||
|
// selection mark
|
||||||
|
blit(cenX - 92 + 20 * pInventory->m_SelectedHotbarSlot, height - 23, 0, 22, 24, 22, 0, 0);
|
||||||
|
|
||||||
|
m->m_pTextures->loadAndBindTexture("gui/icons.png");
|
||||||
|
|
||||||
|
#ifndef ENH_TRANSPARENT_HOTBAR
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR);
|
||||||
|
|
||||||
|
// crosshair
|
||||||
|
blit(cenX - 8, height / 2 - 8, 0, 0, 16, 16, 0, 0);
|
||||||
|
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
|
if (m_pMinecraft->m_pGameMode->canHurtPlayer())
|
||||||
|
{
|
||||||
|
LocalPlayer* pLP = m_pMinecraft->m_pLocalPlayer;
|
||||||
|
|
||||||
|
// why??
|
||||||
|
m_random.init_genrand(312871 * field_9FC);
|
||||||
|
|
||||||
|
int emptyHeartX = 16;
|
||||||
|
bool b1 = false;
|
||||||
|
if (pLP->field_B8 < 10)
|
||||||
|
{
|
||||||
|
b1 = pLP->field_B8 / 3 % 2;
|
||||||
|
emptyHeartX += 9 * b1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @NOTE: At the default scale, this would go off screen.
|
||||||
|
|
||||||
|
int heartX = cenX - 191; // why?
|
||||||
|
int heartYStart = height - 10;
|
||||||
|
|
||||||
|
//@NOTE: Alpha-style health UI. I'll probably remove this on release.
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
heartX = cenX - 91;
|
||||||
|
heartYStart = height - 32;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int playerHealth = pLP->m_health;
|
||||||
|
|
||||||
|
for (int healthNo = 1; healthNo <= C_MAX_MOB_HEALTH; healthNo += 2)
|
||||||
|
{
|
||||||
|
int heartY = heartYStart;
|
||||||
|
|
||||||
|
if (playerHealth <= 4 && m_random.genrand_int32() % 2)
|
||||||
|
heartY++;
|
||||||
|
|
||||||
|
blit(heartX, heartY, emptyHeartX, 0, 9, 9, 0, 0);
|
||||||
|
|
||||||
|
if (b1)
|
||||||
|
{
|
||||||
|
if (healthNo < pLP->field_100)
|
||||||
|
blit(heartX, heartY, 70, 0, 9, 9, 0, 0);
|
||||||
|
else if (healthNo == pLP->field_100)
|
||||||
|
blit(heartX, heartY, 79, 0, 9, 9, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (healthNo < playerHealth)
|
||||||
|
blit(heartX, heartY, 52, 0, 9, 9, 0, 0);
|
||||||
|
else if (healthNo == playerHealth)
|
||||||
|
blit(heartX, heartY, 61, 0, 9, 9, 0, 0);
|
||||||
|
|
||||||
|
heartX += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m->m_pLocalPlayer->isUnderLiquid(Material::water))
|
||||||
|
{
|
||||||
|
int breathRaw = m->m_pLocalPlayer->field_BC;
|
||||||
|
int breathFull = int(ceilf((float(breathRaw - 2) * 10.0f) / 300.0f));
|
||||||
|
int breathMeter = int(ceilf((float(breathRaw) * 10.0f) / 300.0f)) - breathFull;
|
||||||
|
|
||||||
|
int bubbleX = cenX - 191;
|
||||||
|
int bubbleY = height - 19;
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
bubbleX = cenX - 91;
|
||||||
|
bubbleY = height - 41;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//@NOTE: Not sure this works as it should
|
||||||
|
|
||||||
|
for (int bubbleNo = 0; bubbleNo < breathFull + breathMeter; bubbleNo++)
|
||||||
|
{
|
||||||
|
if (bubbleNo < breathFull)
|
||||||
|
blit(bubbleX, bubbleY, 16, 18, 9, 9, 0, 0);
|
||||||
|
else
|
||||||
|
blit(bubbleX, bubbleY, 25, 18, 9, 9, 0, 0);
|
||||||
|
|
||||||
|
bubbleX += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m->m_pTextures->loadAndBindTexture("gui/gui_blocks.png");
|
||||||
|
|
||||||
|
Tesselator& t = Tesselator::instance;
|
||||||
|
t.begin();
|
||||||
|
|
||||||
|
// if we aren't trying to build the real deal, don't do this. It only does worse
|
||||||
|
#ifdef ORIGINAL_CODE
|
||||||
|
t.voidBeginAndEndCalls(true); // to ensure that Gui::renderSlot doesn't end() our tesselator right away?
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int slotX = cenX - 88;
|
||||||
|
#ifdef ENH_ENABLE_9TH_SLOT
|
||||||
|
#define HOTBAR_DIFF 0
|
||||||
|
#else
|
||||||
|
#define HOTBAR_DIFF 1
|
||||||
|
#endif
|
||||||
|
for (int i = 0; i < C_MAX_HOTBAR_ITEMS - HOTBAR_DIFF; i++)
|
||||||
|
{
|
||||||
|
renderSlot(i, slotX, height - 19, f);
|
||||||
|
|
||||||
|
slotX += 20;
|
||||||
|
}
|
||||||
|
#undef HOTBAR_DIFF
|
||||||
|
|
||||||
|
field_A3C = false;
|
||||||
|
|
||||||
|
#ifdef ORIGINAL_CODE
|
||||||
|
t.voidBeginAndEndCalls(false);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
t.draw();
|
||||||
|
|
||||||
|
// blit the "more items" button
|
||||||
|
#ifndef ENH_ENABLE_9TH_SLOT
|
||||||
|
m->m_pTextures->loadAndBindTexture(C_TERRAIN_NAME);
|
||||||
|
blit(cenX + 72, height - 19, 208, 208, 16, 16, 0, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// render messages
|
||||||
|
|
||||||
|
int topEdge = height - 49;
|
||||||
|
|
||||||
|
for (auto& msg : m_guiMessages)
|
||||||
|
{
|
||||||
|
if (msg.field_18 > 199)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int bkgdColor = 0x7F000000, textColor = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
float fade = 10.0f * (1.0f - (float(msg.field_18) / 200.0f));
|
||||||
|
if (fade <= 0.0f)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (fade < 1.0f)
|
||||||
|
{
|
||||||
|
int x = int(fade * fade * 255.0f);
|
||||||
|
if (x == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bkgdColor = (x / 2) << 24;
|
||||||
|
textColor = (x << 24) + 0xFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
fill(2, topEdge, 322, topEdge + 9, bkgdColor);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
m->m_pFont->drawShadow(msg.msg, 2, topEdge + 1, textColor);
|
||||||
|
|
||||||
|
topEdge -= 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::tick()
|
||||||
|
{
|
||||||
|
for (auto& msg : m_guiMessages)
|
||||||
|
{
|
||||||
|
msg.field_18++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::renderSlot(int slot, int x, int y, float f)
|
||||||
|
{
|
||||||
|
int itemID = m_pMinecraft->m_pLocalPlayer->m_pInventory->getSelectionSlotItemId(slot);
|
||||||
|
if (itemID < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ItemInstance inst(Item::items[itemID], 1, 0);
|
||||||
|
ItemRenderer::renderGuiItem(m_pMinecraft->m_pFont, m_pMinecraft->m_pTextures, &inst, x, y, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Gui::getSlotIdAt(int mouseX, int mouseY)
|
||||||
|
{
|
||||||
|
int scaledY = int(InvGuiScale * mouseY);
|
||||||
|
int scaledHeight = int(InvGuiScale * Minecraft::height);
|
||||||
|
|
||||||
|
if (scaledY >= scaledHeight)
|
||||||
|
return -1;
|
||||||
|
if (scaledY < scaledHeight-19)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int slotX = (int(InvGuiScale * mouseX) - int(InvGuiScale * Minecraft::width) / 2 + 88 + 20) / 20;
|
||||||
|
|
||||||
|
//@NOTE: Why not just -88?
|
||||||
|
if (slotX >= 0)
|
||||||
|
slotX--;
|
||||||
|
|
||||||
|
if (slotX > 8)
|
||||||
|
slotX = -1;
|
||||||
|
|
||||||
|
return slotX;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gui::isInside(int mouseX, int mouseY)
|
||||||
|
{
|
||||||
|
return getSlotIdAt(mouseX, mouseY) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::handleClick(int clickID, int mouseX, int mouseY)
|
||||||
|
{
|
||||||
|
if (clickID != 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int slot = getSlotIdAt(mouseX, mouseY);
|
||||||
|
if (slot == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifndef ENH_ENABLE_9TH_SLOT
|
||||||
|
if (slot == 8)
|
||||||
|
{
|
||||||
|
m_pMinecraft->setScreen(new IngameBlockSelectionScreen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
m_pMinecraft->m_pLocalPlayer->m_pInventory->selectSlot(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::handleKeyPressed(int keyCode)
|
||||||
|
{
|
||||||
|
switch (keyCode)
|
||||||
|
{
|
||||||
|
case AKEYCODE_BUTTON_Y:
|
||||||
|
{
|
||||||
|
m_pMinecraft->setScreen(new IngameBlockSelectionScreen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AKEYCODE_BACK:
|
||||||
|
{
|
||||||
|
int* slot = &m_pMinecraft->m_pLocalPlayer->m_pInventory->m_SelectedHotbarSlot;
|
||||||
|
|
||||||
|
#ifdef ENH_ENABLE_9TH_SLOT
|
||||||
|
#define MAX_ITEMS (C_MAX_HOTBAR_ITEMS - 2)
|
||||||
|
#else
|
||||||
|
#define MAX_ITEMS (C_MAX_HOTBAR_ITEMS - 3)
|
||||||
|
#endif
|
||||||
|
//@HUH: for whatever reason, it ignores the 7th item
|
||||||
|
if (*slot <= MAX_ITEMS)
|
||||||
|
(*slot)++;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AKEYCODE_BUTTON_X:
|
||||||
|
{
|
||||||
|
int* slot = &m_pMinecraft->m_pLocalPlayer->m_pInventory->m_SelectedHotbarSlot;
|
||||||
|
|
||||||
|
if (*slot > 0)
|
||||||
|
(*slot)--;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
55
source/GUI/Gui.hpp
Normal file
55
source/GUI/Gui.hpp
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "GuiComponent.hpp"
|
||||||
|
#include "Minecraft.hpp"
|
||||||
|
#include "Random.hpp"
|
||||||
|
#include "Utils.hpp"
|
||||||
|
|
||||||
|
class Minecraft; // in case we're included from Minecraft.hpp
|
||||||
|
|
||||||
|
struct GuiMessage
|
||||||
|
{
|
||||||
|
std::string msg;
|
||||||
|
int field_18;
|
||||||
|
|
||||||
|
GuiMessage(const std::string& x, int a) : msg(x), field_18(a) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Gui : public GuiComponent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Gui(Minecraft* pMinecraft);
|
||||||
|
|
||||||
|
void addMessage(const std::string& str);
|
||||||
|
void inventoryUpdated();
|
||||||
|
void renderVignette(float, int, int);
|
||||||
|
void setNowPlaying(const std::string& str);
|
||||||
|
void render(float f, bool bHaveScreen, int mouseX, int mouseY);
|
||||||
|
void tick();
|
||||||
|
void renderSlot(int slot, int x, int y, float f);
|
||||||
|
int getSlotIdAt(int mx, int my);
|
||||||
|
bool isInside(int mx, int my);
|
||||||
|
void handleClick(int id, int mx, int my);
|
||||||
|
void handleKeyPressed(int keyCode);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static float InvGuiScale;
|
||||||
|
|
||||||
|
public:
|
||||||
|
float field_8 = 0;
|
||||||
|
std::string field_C = "";
|
||||||
|
std::vector<GuiMessage> m_guiMessages;
|
||||||
|
int field_24 = 0;
|
||||||
|
int field_28 = 0;
|
||||||
|
int field_2C = 0;
|
||||||
|
Random m_random;
|
||||||
|
Minecraft* m_pMinecraft;
|
||||||
|
int field_9FC = 0;
|
||||||
|
std::string field_A00 = "";
|
||||||
|
int field_A18 = 0;
|
||||||
|
bool field_A1C = false;
|
||||||
|
float field_A20 = 1.0f;
|
||||||
|
RenderChunk m_renderChunk;
|
||||||
|
bool field_A3C = true;
|
||||||
|
};
|
||||||
|
|
||||||
82
source/GUI/GuiComponent.cpp
Normal file
82
source/GUI/GuiComponent.cpp
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
#include "GuiComponent.hpp"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#pragma warning (disable : 4244)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void GuiComponent::blit(int dx, int dy, int sx, int sy, int tw, int th, int sw, int sh)
|
||||||
|
{
|
||||||
|
auto& t = Tesselator::instance;
|
||||||
|
|
||||||
|
if (!sh) sh = th;
|
||||||
|
if (!sw) sw = tw;
|
||||||
|
|
||||||
|
int width = sw, height = sh;
|
||||||
|
|
||||||
|
t.begin();
|
||||||
|
t.vertexUV(dx, dy + th, field_4, float(sx) / 256.0f, float(sy + sh) / 256.0f);
|
||||||
|
t.vertexUV(dx + tw, dy + th, field_4, float(sx + sw) / 256.0f, float(sy + sh) / 256.0f);
|
||||||
|
t.vertexUV(dx + tw, dy, field_4, float(sx + sw) / 256.0f, float(sy) / 256.0f);
|
||||||
|
t.vertexUV(dx, dy, field_4, float(sx) / 256.0f, float(sy) / 256.0f);
|
||||||
|
t.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiComponent::drawCenteredString(Font* pFont, const std::string& str, int cx, int cy, int color)
|
||||||
|
{
|
||||||
|
int width = pFont->width(str);
|
||||||
|
int height = pFont->height(str);
|
||||||
|
pFont->drawShadow(str, cx - width / 2, cy - height / 2, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiComponent::drawString(Font* pFont, const std::string& str, int cx, int cy, int color)
|
||||||
|
{
|
||||||
|
pFont->drawShadow(str, cx, cy, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiComponent::fill(int a2, int a3, int a4, int a5, int a6)
|
||||||
|
{
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glColor4f(float(GET_RED(a6)) / 255.0f, float(GET_GREEN(a6)) / 255.0f, float(GET_BLUE(a6)) / 255.0f, float(GET_ALPHA(a6)) / 255.0f);
|
||||||
|
|
||||||
|
Tesselator& t = Tesselator::instance;
|
||||||
|
t.begin();
|
||||||
|
|
||||||
|
t.vertex(a2, a5, 0.0f);
|
||||||
|
t.vertex(a4, a5, 0.0f);
|
||||||
|
t.vertex(a4, a3, 0.0f);
|
||||||
|
t.vertex(a2, a3, 0.0f);
|
||||||
|
|
||||||
|
t.draw();
|
||||||
|
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiComponent::fillGradient(int a2, int a3, int a4, int a5, int a6, int a7)
|
||||||
|
{
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glDisable(GL_ALPHA_TEST);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glShadeModel(GL_SMOOTH);
|
||||||
|
|
||||||
|
Tesselator& t = Tesselator::instance;
|
||||||
|
t.begin();
|
||||||
|
|
||||||
|
// note: for some stupid reason OG uses the float overload.
|
||||||
|
t.color(float(GET_RED(a6)) / 255.0f, float(GET_GREEN(a6)) / 255.0f, float(GET_BLUE(a6)) / 255.0f, float(GET_ALPHA(a6)) / 255.0f);
|
||||||
|
t.vertex(a2, a5, 0.0f);
|
||||||
|
t.vertex(a4, a5, 0.0f);
|
||||||
|
t.color(float(GET_RED(a7)) / 255.0f, float(GET_GREEN(a7)) / 255.0f, float(GET_BLUE(a7)) / 255.0f, float(GET_ALPHA(a7)) / 255.0f);
|
||||||
|
t.vertex(a4, a3, 0.0f);
|
||||||
|
t.vertex(a2, a3, 0.0f);
|
||||||
|
|
||||||
|
t.draw();
|
||||||
|
|
||||||
|
glShadeModel(GL_FLAT);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
glEnable(GL_ALPHA_TEST);
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
}
|
||||||
18
source/GUI/GuiComponent.hpp
Normal file
18
source/GUI/GuiComponent.hpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Tesselator.hpp"
|
||||||
|
#include "Font.hpp"
|
||||||
|
|
||||||
|
class GuiComponent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void blit(int dstX, int dstY, int srcX, int srcY, int dstWidth, int dstHeight, int srcWidth, int srcHeight);
|
||||||
|
void drawCenteredString(Font*, const std::string&, int cx, int cy, int color);
|
||||||
|
void drawString(Font*, const std::string&, int cx, int cy, int color);
|
||||||
|
void fill(int left, int top, int right, int bottom, int color);
|
||||||
|
void fillGradient(int left, int top, int right, int bottom, int colorUp, int colorDown);
|
||||||
|
|
||||||
|
public:
|
||||||
|
float field_4;
|
||||||
|
};
|
||||||
|
|
||||||
319
source/GUI/RolledSelectionList.cpp
Normal file
319
source/GUI/RolledSelectionList.cpp
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
#include "RolledSelectionList.hpp"
|
||||||
|
|
||||||
|
static float g_RolledSelectionListUnk, g_RolledSelectionListUnk2;
|
||||||
|
|
||||||
|
RolledSelectionList::RolledSelectionList(Minecraft* minecraft, int a, int b, int c, int d, int e, int f, int g)
|
||||||
|
{
|
||||||
|
m_pMinecraft = minecraft;
|
||||||
|
m_itemWidth = g;
|
||||||
|
field_18 = a;
|
||||||
|
field_C = float(c);
|
||||||
|
field_10 = float(d);
|
||||||
|
field_1C = b;
|
||||||
|
field_20 = float(e);
|
||||||
|
field_24 = float(f);
|
||||||
|
g_RolledSelectionListUnk = field_30 = field_34 = float(g - a) / 2.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RolledSelectionList::getItemAtXPositionRaw(int x)
|
||||||
|
{
|
||||||
|
if (x < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// @NOTE: redundant check
|
||||||
|
int idx = x / m_itemWidth;
|
||||||
|
if (idx < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (idx >= getNumberOfItems())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RolledSelectionList::getItemAtPosition(int x, int y)
|
||||||
|
{
|
||||||
|
if (float(y) < field_20)
|
||||||
|
return -1;
|
||||||
|
if (float(y) > field_24)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return getItemAtXPositionRaw(transformX(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RolledSelectionList::capXPosition()
|
||||||
|
{
|
||||||
|
float f1 = float(m_itemWidth - field_18) / 2.0f;
|
||||||
|
int i1 = getNumberOfItems();
|
||||||
|
|
||||||
|
if (field_30 < f1)
|
||||||
|
{
|
||||||
|
field_30 = f1;
|
||||||
|
field_38 = 0.0f;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
f1 += float(m_itemWidth * (i1 - 1));
|
||||||
|
if (field_30 > f1)
|
||||||
|
{
|
||||||
|
field_30 = f1;
|
||||||
|
field_38 = 0.0f;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RolledSelectionList::tick()
|
||||||
|
{
|
||||||
|
float diff = g_RolledSelectionListUnk - field_34;
|
||||||
|
g_RolledSelectionListUnk = field_34;
|
||||||
|
g_RolledSelectionListUnk2 = diff;
|
||||||
|
field_34 = field_30 - field_38;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RolledSelectionList::render(int mouseX, int mouseY, float f)
|
||||||
|
{
|
||||||
|
renderBackground();
|
||||||
|
|
||||||
|
int nItems = getNumberOfItems();
|
||||||
|
|
||||||
|
// @TODO: fix gotos.
|
||||||
|
if (!Mouse::_buttonStates[1])
|
||||||
|
{
|
||||||
|
if (field_28 < 0)
|
||||||
|
{
|
||||||
|
_crap:
|
||||||
|
field_28 = -1;
|
||||||
|
field_30 = getPos(f);
|
||||||
|
goto _done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_RolledSelectionListUnk2 < 0.0f)
|
||||||
|
field_38 = Mth::Max(-20.0f, g_RolledSelectionListUnk2);
|
||||||
|
else
|
||||||
|
field_38 = Mth::Min(20.0f, g_RolledSelectionListUnk2);
|
||||||
|
|
||||||
|
if (fabsf(field_38) < 2.0f)
|
||||||
|
{
|
||||||
|
field_38 = 0.0f;
|
||||||
|
|
||||||
|
_continue:
|
||||||
|
if (getTimeMs() - field_4C < 300)
|
||||||
|
{
|
||||||
|
int idx = transformX(mouseX) / m_itemWidth;
|
||||||
|
if (idx >= 0)
|
||||||
|
{
|
||||||
|
if (field_50 == idx && abs(field_3C - mouseX) <= 9)
|
||||||
|
selectItem(field_50, 0);
|
||||||
|
}
|
||||||
|
goto _crap;
|
||||||
|
}
|
||||||
|
goto _crap;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fabsf(field_38) > 10.0f)
|
||||||
|
{
|
||||||
|
goto _crap;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto _continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
touched();
|
||||||
|
|
||||||
|
if (float(mouseY) >= field_20 && float(mouseY) <= field_24)
|
||||||
|
{
|
||||||
|
if (field_28 == -1)
|
||||||
|
{
|
||||||
|
field_4C = getTimeMs();
|
||||||
|
field_3C = mouseX;
|
||||||
|
field_50 = getItemAtPosition(mouseX, field_1C / 2);
|
||||||
|
}
|
||||||
|
else if (field_28 >= 0)
|
||||||
|
{
|
||||||
|
field_34 = field_30 = field_30 - (float(mouseX) - field_2C);
|
||||||
|
}
|
||||||
|
|
||||||
|
field_28 = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_done:
|
||||||
|
field_2C = float(mouseX);
|
||||||
|
|
||||||
|
capXPosition();
|
||||||
|
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
glDisable(GL_FOG);
|
||||||
|
|
||||||
|
m_pMinecraft->m_pTextures->loadAndBindTexture("gui/background.png");
|
||||||
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
|
Tesselator& t = Tesselator::instance;
|
||||||
|
t.begin();
|
||||||
|
t.color(0x202020);
|
||||||
|
t.vertexUV(field_C, field_24, 0.0f, (field_C + float(int(field_30))) / 32.0f, field_24 / 32.0f);
|
||||||
|
t.vertexUV(field_10, field_24, 0.0f, (field_10 + float(int(field_30))) / 32.0f, field_24 / 32.0f);
|
||||||
|
t.vertexUV(field_10, field_20, 0.0f, (field_10 + float(int(field_30))) / 32.0f, field_20 / 32.0f);
|
||||||
|
t.vertexUV(field_C, field_20, 0.0f, (field_C + float(int(field_30))) / 32.0f, field_20 / 32.0f);
|
||||||
|
t.draw();
|
||||||
|
|
||||||
|
if (!getNumberOfItems())
|
||||||
|
field_30 = 0.0f;
|
||||||
|
|
||||||
|
if (field_48)
|
||||||
|
renderHeader(int(field_C + 4.0f - float(int(field_30))), field_1C / 2 - 40, t);
|
||||||
|
|
||||||
|
for (int i = 0; i < nItems; i++)
|
||||||
|
{
|
||||||
|
float itemX = float(field_44 + float(int(field_C + 4.0f - float(field_30))) + m_itemWidth * i);
|
||||||
|
if (field_10 < itemX) continue;
|
||||||
|
|
||||||
|
float width = m_itemWidth - 4.0f;
|
||||||
|
if (itemX + width < field_C) continue;
|
||||||
|
|
||||||
|
if (m_bRenderSelection && isSelectedItem(i))
|
||||||
|
{
|
||||||
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
t.begin();
|
||||||
|
t.color(m_bComponentSelected ? 0x7F89BF : 0x808080);
|
||||||
|
|
||||||
|
float right = itemX + width;
|
||||||
|
float up = float(field_1C) / 2.0f - 48.0f - 4.0f;
|
||||||
|
float dn = float(field_1C) / 2.0f + 48.0f - 4.0f;
|
||||||
|
|
||||||
|
t.vertexUV(itemX - 2, up, 0.0f, 0.0f, 0.0f);
|
||||||
|
t.vertexUV(itemX - 2, dn, 0.0f, 1.0f, 0.0f);
|
||||||
|
t.vertexUV(right + 2, dn, 0.0f, 1.0f, 1.0f);
|
||||||
|
t.vertexUV(right + 2, up, 0.0f, 0.0f, 1.0f);
|
||||||
|
t.color(0x000000);
|
||||||
|
t.vertexUV(itemX - 1, up + 1.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
t.vertexUV(itemX - 1, dn - 1.0f, 0.0f, 1.0f, 0.0f);
|
||||||
|
t.vertexUV(right + 1, dn - 1.0f, 0.0f, 1.0f, 1.0f);
|
||||||
|
t.vertexUV(right + 1, up + 1.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
t.draw();
|
||||||
|
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderItem(i, int(itemX), field_1C / 2 - 40, int(width), t);
|
||||||
|
}
|
||||||
|
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
renderHoleBackground(0.0f, field_20, 255, 255);
|
||||||
|
renderHoleBackground(field_24, float(field_1C), 255, 255);
|
||||||
|
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glDisable(GL_ALPHA_TEST);
|
||||||
|
glShadeModel(GL_SMOOTH);
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
// @BUG: The X and Y coordinates have been swapped. This causes the gradient to not render
|
||||||
|
// in the right place.
|
||||||
|
#ifdef ORIGINAL_CODE
|
||||||
|
t.begin();
|
||||||
|
t.color(0, 0);
|
||||||
|
t.vertexUV(field_20, field_C + 4.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
t.vertexUV(field_24, field_C + 4.0f, 0.0f, 1.0f, 1.0f);
|
||||||
|
t.color(0, 255);
|
||||||
|
t.vertexUV(field_24, field_C, 0.0f, 1.0f, 0.0f);
|
||||||
|
t.vertexUV(field_20, field_C, 0.0f, 0.0f, 0.0f);
|
||||||
|
t.draw();
|
||||||
|
|
||||||
|
t.begin();
|
||||||
|
t.color(0, 255);
|
||||||
|
t.vertexUV(field_20, field_10, 0.0f, 0.0f, 1.0f);
|
||||||
|
t.vertexUV(field_24, field_10, 0.0f, 1.0f, 1.0f);
|
||||||
|
t.color(0, 0);
|
||||||
|
t.vertexUV(field_24, field_10 - 4.0f, 0.0f, 1.0f, 0.0f);
|
||||||
|
t.vertexUV(field_20, field_10 - 4.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
t.draw();
|
||||||
|
#else
|
||||||
|
t.begin();
|
||||||
|
t.color(0, 0);
|
||||||
|
t.vertexUV(field_C + 4.0f, field_20, 0.0f, 0.0f, 1.0f);
|
||||||
|
t.vertexUV(field_C + 4.0f, field_24, 0.0f, 1.0f, 1.0f);
|
||||||
|
t.color(0, 255);
|
||||||
|
t.vertexUV(field_C, field_24, 0.0f, 1.0f, 0.0f);
|
||||||
|
t.vertexUV(field_C, field_20, 0.0f, 0.0f, 0.0f);
|
||||||
|
t.draw();
|
||||||
|
|
||||||
|
t.begin();
|
||||||
|
t.color(0, 255);
|
||||||
|
t.vertexUV(field_10, field_20, 0.0f, 0.0f, 1.0f);
|
||||||
|
t.vertexUV(field_10, field_24, 0.0f, 1.0f, 1.0f);
|
||||||
|
t.color(0, 0);
|
||||||
|
t.vertexUV(field_10 - 4.0f, field_24, 0.0f, 1.0f, 0.0f);
|
||||||
|
t.vertexUV(field_10 - 4.0f, field_20, 0.0f, 0.0f, 0.0f);
|
||||||
|
t.draw();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
renderDecorations(mouseX, mouseY);
|
||||||
|
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glShadeModel(GL_FLAT);
|
||||||
|
glEnable(GL_ALPHA_TEST);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RolledSelectionList::renderHoleBackground(float y1, float y2, int a, int b)
|
||||||
|
{
|
||||||
|
m_pMinecraft->m_pTextures->loadAndBindTexture("gui/background.png");
|
||||||
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
|
Tesselator& t = Tesselator::instance;
|
||||||
|
t.begin();
|
||||||
|
t.color(0x505050, b);
|
||||||
|
t.vertexUV(0.0f, y2, 0.0f, 0.0f, y2 / 32.0f);
|
||||||
|
t.vertexUV(float(field_18), y2, 0.0f, float(field_18) / 32.0f, y2 / 32.0f);
|
||||||
|
t.color(0x505050, a);
|
||||||
|
t.vertexUV(float(field_18), y1, 0.0f, float(field_18) / 32.0f, y1 / 32.0f);
|
||||||
|
t.vertexUV(0.0f, y1, 0.0f, 0.0f, y1 / 32.0f);
|
||||||
|
t.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RolledSelectionList::setRenderSelection(bool b)
|
||||||
|
{
|
||||||
|
m_bRenderSelection = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RolledSelectionList::setComponentSelected(bool b)
|
||||||
|
{
|
||||||
|
m_bComponentSelected = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RolledSelectionList::getMaxPosition()
|
||||||
|
{
|
||||||
|
return field_44 + m_itemWidth * getNumberOfItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
float RolledSelectionList::getPos(float f)
|
||||||
|
{
|
||||||
|
return field_34 - field_38 * f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RolledSelectionList::touched()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void RolledSelectionList::renderHeader(int a, int b, Tesselator& t)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void RolledSelectionList::renderDecorations(int x, int y)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void RolledSelectionList::clickedHeader(int x, int y)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
59
source/GUI/RolledSelectionList.hpp
Normal file
59
source/GUI/RolledSelectionList.hpp
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "GuiComponent.hpp"
|
||||||
|
#include "Minecraft.hpp"
|
||||||
|
|
||||||
|
class RolledSelectionList : public GuiComponent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RolledSelectionList(Minecraft*, int, int, int, int, int, int, int);
|
||||||
|
virtual int getItemAtPosition(int, int);
|
||||||
|
virtual bool capXPosition();
|
||||||
|
virtual void tick();
|
||||||
|
virtual void render(int mouseX, int mouseY, float);
|
||||||
|
virtual void renderHoleBackground(float y1, float y2, int a, int b);
|
||||||
|
virtual void setRenderSelection(bool);
|
||||||
|
virtual void setComponentSelected(bool);
|
||||||
|
virtual int getNumberOfItems() = 0;
|
||||||
|
virtual void selectItem(int, bool) = 0;
|
||||||
|
virtual bool isSelectedItem(int) = 0;
|
||||||
|
virtual int getMaxPosition();
|
||||||
|
virtual float getPos(float f);
|
||||||
|
virtual void touched();
|
||||||
|
virtual void renderItem(int, int, int, int, Tesselator&) = 0;
|
||||||
|
virtual void renderHeader(int, int, Tesselator&);
|
||||||
|
virtual void renderBackground() = 0;
|
||||||
|
virtual void renderDecorations(int x, int y);
|
||||||
|
virtual void clickedHeader(int, int);
|
||||||
|
|
||||||
|
int getItemAtXPositionRaw(int x);
|
||||||
|
|
||||||
|
// @NOTE: This is inlined.
|
||||||
|
inline int transformX(int x)
|
||||||
|
{
|
||||||
|
return int(x - field_C - float(field_44) + float(int(field_30)) - 4.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Minecraft* m_pMinecraft;
|
||||||
|
float field_C;
|
||||||
|
float field_10;
|
||||||
|
int m_itemWidth;
|
||||||
|
int field_18;
|
||||||
|
int field_1C;
|
||||||
|
float field_20;
|
||||||
|
float field_24;
|
||||||
|
int field_28 = -2;
|
||||||
|
float field_2C = 0.0f;
|
||||||
|
float field_30;
|
||||||
|
float field_34;
|
||||||
|
float field_38 = 0.0f;
|
||||||
|
int field_3C = -1;
|
||||||
|
bool m_bRenderSelection = true;
|
||||||
|
bool m_bComponentSelected = false;
|
||||||
|
int field_44 = 0;
|
||||||
|
bool field_48 = false;
|
||||||
|
int field_4C = 0;
|
||||||
|
int field_50 = -1;
|
||||||
|
};
|
||||||
|
|
||||||
32
source/GUI/Screen/ChatScreen.cpp
Normal file
32
source/GUI/Screen/ChatScreen.cpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#include "ChatScreen.hpp"
|
||||||
|
|
||||||
|
// @NOTE: This is unused.
|
||||||
|
|
||||||
|
void ChatScreen::buttonClicked(Button* pButton)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatScreen::init()
|
||||||
|
{
|
||||||
|
m_pMinecraft->platform()->showDialog(AppPlatform::DLG_CHAT);
|
||||||
|
m_pMinecraft->platform()->createUserInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatScreen::render(int mouseX, int mouseY, float f)
|
||||||
|
{
|
||||||
|
int userInputStatus = m_pMinecraft->platform()->getUserInputStatus();
|
||||||
|
if (userInputStatus < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (userInputStatus == 1)
|
||||||
|
{
|
||||||
|
std::vector<std::string> userInput = m_pMinecraft->platform()->getUserInput();
|
||||||
|
if (userInput.size() >= 1)
|
||||||
|
{
|
||||||
|
// @NOTE: No sending multiplayer chats. Weird
|
||||||
|
m_pMinecraft->m_gui.addMessage(userInput[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pMinecraft->setScreen(nullptr);
|
||||||
|
}
|
||||||
12
source/GUI/Screen/ChatScreen.hpp
Normal file
12
source/GUI/Screen/ChatScreen.hpp
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Screen.hpp"
|
||||||
|
|
||||||
|
class ChatScreen : public Screen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void buttonClicked(Button*) override;
|
||||||
|
void init() override;
|
||||||
|
void render(int mouseX, int mouseY, float f) override;
|
||||||
|
};
|
||||||
|
|
||||||
67
source/GUI/Screen/ConfirmScreen.cpp
Normal file
67
source/GUI/Screen/ConfirmScreen.cpp
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#include "ConfirmScreen.hpp"
|
||||||
|
|
||||||
|
ConfirmScreen::ConfirmScreen(Screen* pScreen, const std::string& line1, const std::string& line2, int x) :
|
||||||
|
m_btnOK (0, 0, 0, "Ok"),
|
||||||
|
m_btnCancel(1, 0, 0, "Cancel"),
|
||||||
|
m_textLine1(line1),
|
||||||
|
m_textLine2(line2),
|
||||||
|
m_pScreen(pScreen),
|
||||||
|
field_40(x)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfirmScreen::ConfirmScreen(Screen* pScreen, const std::string& line1, const std::string& line2, const std::string& ok, const std::string& cancel, int x) :
|
||||||
|
m_btnOK (0, 0, 0, ok),
|
||||||
|
m_btnCancel(1, 0, 0, cancel),
|
||||||
|
m_textLine1(line1),
|
||||||
|
m_textLine2(line2),
|
||||||
|
m_pScreen(pScreen),
|
||||||
|
field_40(x)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// @NOTE: potential memory leak if pScreen is set and not destroyed!
|
||||||
|
|
||||||
|
void ConfirmScreen::buttonClicked(Button* pButton)
|
||||||
|
{
|
||||||
|
postResult(pButton->field_30 == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConfirmScreen::handleBackEvent(bool b)
|
||||||
|
{
|
||||||
|
if (!b)
|
||||||
|
postResult(false);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfirmScreen::init()
|
||||||
|
{
|
||||||
|
m_btnOK.m_xPos = m_width / 2 - 4 - 120;
|
||||||
|
m_btnCancel.m_xPos = m_width / 2 + 4;
|
||||||
|
|
||||||
|
m_btnCancel.m_yPos = m_btnOK.m_yPos = m_height / 6 + 72;
|
||||||
|
|
||||||
|
m_btnOK.m_width = m_btnCancel.m_width = 120;
|
||||||
|
m_btnOK.m_height = m_btnCancel.m_height = 24;
|
||||||
|
|
||||||
|
m_buttons.push_back(&m_btnOK);
|
||||||
|
m_buttons.push_back(&m_btnCancel);
|
||||||
|
m_buttonTabList.push_back(&m_btnOK);
|
||||||
|
m_buttonTabList.push_back(&m_btnCancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfirmScreen::render(int mouseX, int mouseY, float f)
|
||||||
|
{
|
||||||
|
renderBackground();
|
||||||
|
drawCenteredString(m_pFont, m_textLine1, m_width / 2, 50, 0xFFFFFF);
|
||||||
|
drawCenteredString(m_pFont, m_textLine2, m_width / 2, 70, 0xFFFFFF);
|
||||||
|
Screen::render(mouseX, mouseY, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfirmScreen::postResult(bool b)
|
||||||
|
{
|
||||||
|
m_pScreen->confirmResult(b, field_40);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
27
source/GUI/Screen/ConfirmScreen.hpp
Normal file
27
source/GUI/Screen/ConfirmScreen.hpp
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Screen.hpp"
|
||||||
|
#include "SmallButton.hpp"
|
||||||
|
|
||||||
|
class ConfirmScreen : public Screen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConfirmScreen(Screen* pScreen, const std::string& line1, const std::string& line2, int x);
|
||||||
|
ConfirmScreen(Screen* pScreen, const std::string& line1, const std::string& line2, const std::string& ok, const std::string& cancel, int x);
|
||||||
|
|
||||||
|
void buttonClicked(Button* pButton) override;
|
||||||
|
bool handleBackEvent(bool b) override;
|
||||||
|
void init() override;
|
||||||
|
void render(int mouseX, int mouseY, float f) override;
|
||||||
|
|
||||||
|
virtual void postResult(bool b);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Screen* m_pScreen = nullptr;
|
||||||
|
int field_40 = 0;
|
||||||
|
std::string m_textLine1;
|
||||||
|
std::string m_textLine2;
|
||||||
|
SmallButton m_btnOK;
|
||||||
|
SmallButton m_btnCancel;
|
||||||
|
};
|
||||||
|
|
||||||
23
source/GUI/Screen/DeleteWorldScreen.cpp
Normal file
23
source/GUI/Screen/DeleteWorldScreen.cpp
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#include "DeleteWorldScreen.hpp"
|
||||||
|
#include "SelectWorldScreen.hpp"
|
||||||
|
|
||||||
|
DeleteWorldScreen::DeleteWorldScreen(const LevelSummary& level) :
|
||||||
|
ConfirmScreen(nullptr,
|
||||||
|
"Are you sure you want to delete this world?",
|
||||||
|
"'" + level.field_18 + "' will be lost forever!",
|
||||||
|
"Delete", "Cancel", 0),
|
||||||
|
m_level(level)
|
||||||
|
{
|
||||||
|
// highlight the cancel button so the user will have to do 1 extra action to delete their world
|
||||||
|
m_tabButtonIndex = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeleteWorldScreen::postResult(bool b)
|
||||||
|
{
|
||||||
|
if (b)
|
||||||
|
{
|
||||||
|
m_pMinecraft->getLevelSource()->deleteLevel(m_level.field_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pMinecraft->setScreen(new SelectWorldScreen);
|
||||||
|
}
|
||||||
15
source/GUI/Screen/DeleteWorldScreen.hpp
Normal file
15
source/GUI/Screen/DeleteWorldScreen.hpp
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ConfirmScreen.hpp"
|
||||||
|
|
||||||
|
class DeleteWorldScreen : public ConfirmScreen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeleteWorldScreen(const LevelSummary& level);
|
||||||
|
|
||||||
|
void postResult(bool b) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
LevelSummary m_level;
|
||||||
|
};
|
||||||
|
|
||||||
186
source/GUI/Screen/IngameBlockSelectionScreen.cpp
Normal file
186
source/GUI/Screen/IngameBlockSelectionScreen.cpp
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
#include "IngameBlockSelectionScreen.hpp"
|
||||||
|
#include "ItemRenderer.hpp"
|
||||||
|
|
||||||
|
#define C_SLOTS_HEIGHT ((C_MAX_INVENTORY_ITEMS + 8) / 9)
|
||||||
|
|
||||||
|
std::string g_sNotAvailableInDemoVersion = "Not available in the demo version";
|
||||||
|
|
||||||
|
int IngameBlockSelectionScreen::getSelectedSlot(int x, int y)
|
||||||
|
{
|
||||||
|
int bottom = m_height - 151;
|
||||||
|
int left = m_width / 2 - 87;
|
||||||
|
|
||||||
|
if (y < bottom)
|
||||||
|
return -1;
|
||||||
|
if (x < left)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int idx = (x - left) / 20;
|
||||||
|
if (idx > 8)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return idx + 36 - 9 * ((y - bottom) / 22);
|
||||||
|
}
|
||||||
|
|
||||||
|
int IngameBlockSelectionScreen::getSlotPosX(int x)
|
||||||
|
{
|
||||||
|
return m_width / 2 - 88 + 20 * x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IngameBlockSelectionScreen::getSlotPosY(int y)
|
||||||
|
{
|
||||||
|
return m_height - 63 - 22 * y;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IngameBlockSelectionScreen::isAllowed(int slot)
|
||||||
|
{
|
||||||
|
if (slot < 0 || slot > C_MAX_INVENTORY_ITEMS-1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
#ifdef DEMO
|
||||||
|
return slot > 17;
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IngameBlockSelectionScreen::init()
|
||||||
|
{
|
||||||
|
Inventory* pInv = m_pMinecraft->m_pLocalPlayer->m_pInventory;
|
||||||
|
|
||||||
|
for (int i = 9; i < C_MAX_HOTBAR_ITEMS + C_MAX_INVENTORY_ITEMS; i++)
|
||||||
|
{
|
||||||
|
if (pInv->getSelectionSlotItemId(i) == pInv->getSelectedItemId())
|
||||||
|
{
|
||||||
|
m_selectedSlot = i - 9;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isAllowed(m_selectedSlot))
|
||||||
|
m_selectedSlot = 27;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IngameBlockSelectionScreen::renderSlot(int index, int x, int y, float f)
|
||||||
|
{
|
||||||
|
int item = m_pMinecraft->m_pLocalPlayer->m_pInventory->getSelectionSlotItemId(index);
|
||||||
|
if (item < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ItemInstance inst(item, 2, 0);
|
||||||
|
ItemRenderer::renderGuiItem(m_pMinecraft->m_pFont, m_pMinecraft->m_pTextures, &inst, x, y, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IngameBlockSelectionScreen::renderSlots()
|
||||||
|
{
|
||||||
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
m_pMinecraft->m_pTextures->loadAndBindTexture("gui/gui.png");
|
||||||
|
|
||||||
|
for (int y = 0; y != -22 * C_SLOTS_HEIGHT; y -= 22)
|
||||||
|
blit(m_width / 2 - 182 / 2, m_height - 66 + y, 0, 0, 182, 22, 0, 0);
|
||||||
|
|
||||||
|
if (m_selectedSlot >= 0)
|
||||||
|
blit(m_width / 2 - 92 + 20 * (m_selectedSlot % 9), m_height - 67 - 22 * (m_selectedSlot / 9), 0, 22, 24, 22, 0, 0);
|
||||||
|
|
||||||
|
for (int y = 0, index = 9; y < C_SLOTS_HEIGHT; y++)
|
||||||
|
{
|
||||||
|
int posY = getSlotPosY(y);
|
||||||
|
for (int x = 0; x < 9; x++)
|
||||||
|
{
|
||||||
|
int posX = getSlotPosX(x);
|
||||||
|
renderSlot(index++, posX, posY, 0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IngameBlockSelectionScreen::renderDemoOverlay()
|
||||||
|
{
|
||||||
|
fill(getSlotPosX(0) - 3, getSlotPosY(1) - 3, getSlotPosX(9), getSlotPosY(-1), 0xA0000000);
|
||||||
|
|
||||||
|
int x = (getSlotPosX(4) + getSlotPosX(5)) / 2;
|
||||||
|
int y = (getSlotPosY(0) + getSlotPosY(1)) / 2 + 5;
|
||||||
|
|
||||||
|
drawCenteredString(m_pMinecraft->m_pFont, g_sNotAvailableInDemoVersion, x, y, 0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IngameBlockSelectionScreen::render(int x, int y, float f)
|
||||||
|
{
|
||||||
|
Screen::render(x, y, f);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
fill(0, 0, m_width, m_height, 0x80000000);
|
||||||
|
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
renderSlots();
|
||||||
|
|
||||||
|
#ifdef DEMO
|
||||||
|
renderDemoOverlay();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IngameBlockSelectionScreen::mouseClicked(int x, int y, int type)
|
||||||
|
{
|
||||||
|
// not a left click
|
||||||
|
if (type != 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int slot = getSelectedSlot(x, y);
|
||||||
|
if (isAllowed(slot))
|
||||||
|
m_selectedSlot = slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IngameBlockSelectionScreen::mouseReleased(int x, int y, int type)
|
||||||
|
{
|
||||||
|
// not a left click
|
||||||
|
if (type != 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int slot = getSelectedSlot(x, y);
|
||||||
|
if (isAllowed(slot) && slot == m_selectedSlot)
|
||||||
|
selectSlotAndClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IngameBlockSelectionScreen::selectSlotAndClose()
|
||||||
|
{
|
||||||
|
Inventory* pInv = m_pMinecraft->m_pLocalPlayer->m_pInventory;
|
||||||
|
int item = pInv->getSelectionSlotItemId(m_selectedSlot + 9);
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
// @TODO: Fix gotos
|
||||||
|
#ifdef ENH_ENABLE_9TH_SLOT
|
||||||
|
#define MAX_ITEMS (C_MAX_HOTBAR_ITEMS - 1)
|
||||||
|
#else
|
||||||
|
#define MAX_ITEMS (C_MAX_HOTBAR_ITEMS - 2)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (item == pInv->getSelectionSlotItemId(0))
|
||||||
|
{
|
||||||
|
label_4:
|
||||||
|
if (!idx)
|
||||||
|
goto label_5;
|
||||||
|
}
|
||||||
|
else while (++idx != MAX_ITEMS)
|
||||||
|
{
|
||||||
|
if (item == pInv->getSelectionSlotItemId(idx))
|
||||||
|
goto label_4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
int item = pInv->getSelectionSlotItemId(idx - 1);
|
||||||
|
pInv->setSelectionSlotItemId(idx, item);
|
||||||
|
|
||||||
|
if (idx == 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
--idx;
|
||||||
|
}
|
||||||
|
label_5:
|
||||||
|
pInv->setSelectionSlotItemId(0, item);
|
||||||
|
pInv->selectSlot(0);
|
||||||
|
|
||||||
|
// @TODO: SoundEngine
|
||||||
|
|
||||||
|
m_pMinecraft->setScreen(nullptr);
|
||||||
|
}
|
||||||
25
source/GUI/Screen/IngameBlockSelectionScreen.hpp
Normal file
25
source/GUI/Screen/IngameBlockSelectionScreen.hpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Screen.hpp"
|
||||||
|
|
||||||
|
class IngameBlockSelectionScreen : public Screen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int getSelectedSlot(int x, int y);
|
||||||
|
int getSlotPosX(int x);
|
||||||
|
int getSlotPosY(int y);
|
||||||
|
bool isAllowed(int slot);
|
||||||
|
void renderSlots();
|
||||||
|
void renderDemoOverlay();
|
||||||
|
void renderSlot(int index, int x, int y, float f);
|
||||||
|
void selectSlotAndClose();
|
||||||
|
|
||||||
|
virtual void init() override;
|
||||||
|
virtual void render(int x, int y, float f) override;
|
||||||
|
virtual void mouseClicked(int x, int y, int type) override;
|
||||||
|
virtual void mouseReleased(int x, int y, int type) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_selectedSlot = 0;
|
||||||
|
};
|
||||||
|
|
||||||
61
source/GUI/Screen/InvalidLicenseScreen.cpp
Normal file
61
source/GUI/Screen/InvalidLicenseScreen.cpp
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#include "InvalidLicenseScreen.hpp"
|
||||||
|
|
||||||
|
InvalidLicenseScreen::InvalidLicenseScreen(int error, bool bHasQuitButton) :
|
||||||
|
m_error(error),
|
||||||
|
m_btnOk (1, "Ok"),
|
||||||
|
m_btnBuy(2, "Buy"),
|
||||||
|
m_bHasQuitButton(bHasQuitButton)
|
||||||
|
{
|
||||||
|
if (bHasQuitButton)
|
||||||
|
m_btnOk.field_18 = "Quit";
|
||||||
|
}
|
||||||
|
|
||||||
|
void InvalidLicenseScreen::buttonClicked(Button* pButton)
|
||||||
|
{
|
||||||
|
if (pButton->field_30 == m_btnOk.field_30)
|
||||||
|
{
|
||||||
|
m_pMinecraft->quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pButton->field_30 == m_btnBuy.field_30)
|
||||||
|
{
|
||||||
|
m_pMinecraft->platform()->buyGame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InvalidLicenseScreen::init()
|
||||||
|
{
|
||||||
|
field_E4 = m_height / 3;
|
||||||
|
if (m_bHasQuitButton)
|
||||||
|
field_E4 -= 24;
|
||||||
|
|
||||||
|
if (m_error > 1)
|
||||||
|
{
|
||||||
|
char str[20] = { 0 };
|
||||||
|
sprintf(str, "%d", m_error);
|
||||||
|
m_textLine1 = "License verification failed (error " + std::string(str) + ")";
|
||||||
|
m_textLine2 = "Try again later.";
|
||||||
|
}
|
||||||
|
|
||||||
|
m_btnOk.m_xPos = m_btnBuy.m_xPos = (m_width - m_btnOk.m_width) / 2;
|
||||||
|
|
||||||
|
m_btnOk.m_yPos = field_E4 + 60;
|
||||||
|
m_btnBuy.m_yPos = field_E4 + 88;
|
||||||
|
|
||||||
|
m_buttons.push_back(&m_btnOk);
|
||||||
|
m_buttons.push_back(&m_btnBuy);
|
||||||
|
m_buttonTabList.push_back(&m_btnOk);
|
||||||
|
m_buttonTabList.push_back(&m_btnBuy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InvalidLicenseScreen::tick()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void InvalidLicenseScreen::render(int mouseX, int mouseY, float f)
|
||||||
|
{
|
||||||
|
renderDirtBackground(0);
|
||||||
|
drawCenteredString(m_pMinecraft->m_pFont, m_textLine1, m_width / 2, field_E4, 0xFFFFFF);
|
||||||
|
drawCenteredString(m_pMinecraft->m_pFont, m_textLine2, m_width / 2, field_E4 + 24, 0xFFFFFF);
|
||||||
|
Screen::render(mouseX, mouseY, f);
|
||||||
|
}
|
||||||
23
source/GUI/Screen/InvalidLicenseScreen.hpp
Normal file
23
source/GUI/Screen/InvalidLicenseScreen.hpp
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Screen.hpp"
|
||||||
|
|
||||||
|
class InvalidLicenseScreen : public Screen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InvalidLicenseScreen(int error, bool bHasQuitButton);
|
||||||
|
void buttonClicked(Button* pButton) override;
|
||||||
|
void init() override;
|
||||||
|
void tick() override;
|
||||||
|
void render(int mouseX, int mouseY, float f) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_error;
|
||||||
|
std::string m_textLine1;
|
||||||
|
std::string m_textLine2;
|
||||||
|
Button m_btnOk;
|
||||||
|
Button m_btnBuy;
|
||||||
|
bool m_bHasQuitButton;
|
||||||
|
int field_E4 = 0;
|
||||||
|
};
|
||||||
|
|
||||||
155
source/GUI/Screen/JoinGameScreen.cpp
Normal file
155
source/GUI/Screen/JoinGameScreen.cpp
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
#include "JoinGameScreen.hpp"
|
||||||
|
#include "ProgressScreen.hpp"
|
||||||
|
#include "StartMenuScreen.hpp"
|
||||||
|
|
||||||
|
JoinGameScreen::JoinGameScreen() :
|
||||||
|
m_btnJoin(2, "Join Game"),
|
||||||
|
m_btnBack(3, "Back")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
JoinGameScreen::~JoinGameScreen()
|
||||||
|
{
|
||||||
|
if (m_pAvailableGamesList)
|
||||||
|
delete m_pAvailableGamesList;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoinGameScreen::buttonClicked(Button* pButton)
|
||||||
|
{
|
||||||
|
if (pButton->field_30 == m_btnJoin.field_30)
|
||||||
|
{
|
||||||
|
if (isIndexValid(m_pAvailableGamesList->m_selectedIndex))
|
||||||
|
{
|
||||||
|
m_pMinecraft->joinMultiplayer(m_pAvailableGamesList->m_games[m_pAvailableGamesList->m_selectedIndex]);
|
||||||
|
m_pMinecraft->setScreen(new ProgressScreen);
|
||||||
|
|
||||||
|
m_btnJoin.m_bEnabled = false;
|
||||||
|
m_btnBack.m_bEnabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pButton->field_30 == m_btnBack.field_30)
|
||||||
|
{
|
||||||
|
m_pMinecraft->setScreen(new StartMenuScreen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JoinGameScreen::handleBackEvent(bool b)
|
||||||
|
{
|
||||||
|
if (!b)
|
||||||
|
{
|
||||||
|
m_pMinecraft->cancelLocateMultiplayer();
|
||||||
|
m_pMinecraft->setScreen(new StartMenuScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoinGameScreen::init()
|
||||||
|
{
|
||||||
|
m_btnBack.m_yPos = m_btnJoin.m_yPos = m_height - 26;
|
||||||
|
m_btnBack.m_width = m_btnJoin.m_width = 120;
|
||||||
|
|
||||||
|
m_btnJoin.m_xPos = m_width / 2 - 124;
|
||||||
|
m_btnBack.m_xPos = m_width / 2 + 4;
|
||||||
|
|
||||||
|
m_buttons.push_back(&m_btnJoin);
|
||||||
|
m_buttons.push_back(&m_btnBack);
|
||||||
|
|
||||||
|
m_pMinecraft->m_pRakNetInstance->clearServerList();
|
||||||
|
|
||||||
|
m_pAvailableGamesList = new AvailableGamesList(m_pMinecraft, m_width, m_height, 24, m_height - 30, 28);
|
||||||
|
|
||||||
|
m_buttonTabList.push_back(&m_btnJoin);
|
||||||
|
m_buttonTabList.push_back(&m_btnBack);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JoinGameScreen::isInGameScreen()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoinGameScreen::render(int mouseX, int mouseY, float f)
|
||||||
|
{
|
||||||
|
renderBackground();
|
||||||
|
m_pAvailableGamesList->render(mouseX, mouseY, f);
|
||||||
|
Screen::render(mouseX, mouseY, f);
|
||||||
|
|
||||||
|
drawCenteredString(m_pMinecraft->m_pFont, "Scanning for Games...", m_width / 2, 8, 0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoinGameScreen::tick()
|
||||||
|
{
|
||||||
|
std::vector<PingedCompatibleServer> *serverList, serverListFiltered;
|
||||||
|
serverList = m_pMinecraft->m_pRakNetInstance->getServerList();
|
||||||
|
|
||||||
|
for (const PingedCompatibleServer& pcs : *serverList)
|
||||||
|
{
|
||||||
|
if (pcs.m_name.GetLength())
|
||||||
|
serverListFiltered.push_back(pcs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverListFiltered.size() != m_pAvailableGamesList->m_games.size())
|
||||||
|
{
|
||||||
|
PingedCompatibleServer selectedItem;
|
||||||
|
|
||||||
|
if (isIndexValid(m_pAvailableGamesList->m_selectedIndex))
|
||||||
|
{
|
||||||
|
selectedItem = m_pAvailableGamesList->m_games[m_pAvailableGamesList->m_selectedIndex];
|
||||||
|
|
||||||
|
m_pAvailableGamesList->m_games = serverListFiltered;
|
||||||
|
m_pAvailableGamesList->selectItem(-1, false);
|
||||||
|
|
||||||
|
// relocate the new list item, if possible
|
||||||
|
for (int i = 0; i < int(serverListFiltered.size()); i++)
|
||||||
|
{
|
||||||
|
if (serverListFiltered[i].m_address == selectedItem.m_address)
|
||||||
|
{
|
||||||
|
m_pAvailableGamesList->selectItem(i, false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_pAvailableGamesList->m_games = serverListFiltered;
|
||||||
|
m_pAvailableGamesList->selectItem(-1, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!serverListFiltered.empty())
|
||||||
|
{
|
||||||
|
// Update the names of the items already in the available games list.
|
||||||
|
// @BUG: What would happen if the filtered server list removes an IP and adds another all in the same tick?
|
||||||
|
|
||||||
|
std::vector<PingedCompatibleServer>* pGames = &m_pAvailableGamesList->m_games;
|
||||||
|
for (int i = int(pGames->size() - 1); i >= 0; i--)
|
||||||
|
{
|
||||||
|
int j = 0;
|
||||||
|
for (; j < int(serverListFiltered.size()); j++)
|
||||||
|
{
|
||||||
|
if (serverListFiltered[j].m_address == (*pGames)[i].m_address)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j == serverListFiltered.size())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
(*pGames)[i].m_name = serverListFiltered[j].m_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_btnJoin.m_bEnabled = isIndexValid(m_pAvailableGamesList->m_selectedIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JoinGameScreen::isIndexValid(int idx)
|
||||||
|
{
|
||||||
|
if (!m_pAvailableGamesList)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (idx < 0)
|
||||||
|
return false;
|
||||||
|
if (idx >= m_pAvailableGamesList->getNumberOfItems())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
25
source/GUI/Screen/JoinGameScreen.hpp
Normal file
25
source/GUI/Screen/JoinGameScreen.hpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Screen.hpp"
|
||||||
|
#include "AvailableGamesList.hpp"
|
||||||
|
|
||||||
|
class JoinGameScreen : public Screen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
JoinGameScreen();
|
||||||
|
~JoinGameScreen();
|
||||||
|
void buttonClicked(Button* pButton) override;
|
||||||
|
bool handleBackEvent(bool b) override;
|
||||||
|
void init() override;
|
||||||
|
bool isInGameScreen() override;
|
||||||
|
void render(int mouseX, int mouseY, float f) override;
|
||||||
|
void tick() override;
|
||||||
|
|
||||||
|
virtual bool isIndexValid(int idx);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Button m_btnJoin;
|
||||||
|
Button m_btnBack;
|
||||||
|
AvailableGamesList* m_pAvailableGamesList = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
200
source/GUI/Screen/OptionsScreen.cpp
Normal file
200
source/GUI/Screen/OptionsScreen.cpp
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
#include "OptionsScreen.hpp"
|
||||||
|
#include "StartMenuScreen.hpp"
|
||||||
|
#include "PauseScreen.hpp"
|
||||||
|
|
||||||
|
enum eOptionsButton
|
||||||
|
{
|
||||||
|
OB_BACK = 1,
|
||||||
|
OB_AO,
|
||||||
|
OB_SRV_VIS,
|
||||||
|
OB_FANCY_GFX,
|
||||||
|
OB_INVERT_Y,
|
||||||
|
OB_ANAGLYPHS,
|
||||||
|
OB_VIEW_BOB,
|
||||||
|
OB_VIEW_DIST,
|
||||||
|
OB_FLY_HAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
OptionsScreen::OptionsScreen()
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
:m_BackButton (1, 0, 0, 200, 20, "Done"),
|
||||||
|
m_AOButton (2, 0, 0, 150, 20, ""),
|
||||||
|
m_srvVisButton (3, 0, 0, 150, 20, ""),
|
||||||
|
m_fancyGfxButton (4, 0, 0, 150, 20, ""),
|
||||||
|
m_invertYButton (5, 0, 0, 150, 20, ""),
|
||||||
|
m_anaglyphsButton(6, 0, 0, 150, 20, ""),
|
||||||
|
m_viewBobButton (7, 0, 0, 150, 20, ""),
|
||||||
|
m_viewDistButton (8, 0, 0, 150, 20, ""),
|
||||||
|
m_flightHaxButton(9, 0, 0, 150, 20, "")
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
static std::string BoolOptionStr(bool b)
|
||||||
|
{
|
||||||
|
return b ? "ON" : "OFF";
|
||||||
|
}
|
||||||
|
static std::string ViewDistanceStr(int dist)
|
||||||
|
{
|
||||||
|
switch (dist)
|
||||||
|
{
|
||||||
|
case 0: return "EXTREME";
|
||||||
|
case 1: return "FAR";
|
||||||
|
case 2: return "NORMAL";
|
||||||
|
case 3: return "SHORT";
|
||||||
|
case 4: return "TINY";
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << dist;
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionsScreen::UpdateTexts()
|
||||||
|
{
|
||||||
|
Options& o = m_pMinecraft->m_options;
|
||||||
|
|
||||||
|
m_AOButton.field_18 = "Smooth lighting: " + BoolOptionStr(o.field_18);
|
||||||
|
m_invertYButton.field_18 = "Invert Y-axis: " + BoolOptionStr(o.m_bInvertMouse);
|
||||||
|
m_viewBobButton.field_18 = "View bobbing: " + BoolOptionStr(o.field_14);
|
||||||
|
m_anaglyphsButton.field_18 = "3d Anaglyphs: " + BoolOptionStr(o.m_bAnaglyphs);
|
||||||
|
m_fancyGfxButton.field_18 = "Fancy graphics: " + BoolOptionStr(o.m_bFancyGraphics);
|
||||||
|
m_flightHaxButton.field_18 = "Flight hax: " + BoolOptionStr(o.m_bFlyCheat);
|
||||||
|
m_viewDistButton.field_18 = "View distance: " + ViewDistanceStr(o.field_10);
|
||||||
|
m_srvVisButton.field_18 = "Server " + std::string(o.m_bServerVisibleDefault ? "visible" : "invisible") + " by default";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void OptionsScreen::init()
|
||||||
|
{
|
||||||
|
m_pMinecraft->platform()->showDialog(AppPlatform::DLG_OPTIONS);
|
||||||
|
m_pMinecraft->platform()->createUserInput();
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
m_BackButton.m_xPos = m_width / 2 - m_BackButton.m_width / 2;
|
||||||
|
m_BackButton.m_yPos = m_height - 33;
|
||||||
|
m_BackButton.m_height = 20;
|
||||||
|
m_buttons.push_back(&m_BackButton);
|
||||||
|
|
||||||
|
m_AOButton.m_xPos =
|
||||||
|
m_srvVisButton.m_xPos =
|
||||||
|
m_fancyGfxButton.m_xPos =
|
||||||
|
m_viewDistButton.m_xPos = m_width / 2 - m_AOButton.m_width - 5;
|
||||||
|
|
||||||
|
m_invertYButton.m_xPos =
|
||||||
|
m_anaglyphsButton.m_xPos =
|
||||||
|
m_viewBobButton.m_xPos =
|
||||||
|
m_flightHaxButton.m_xPos = m_width / 2 + 5;
|
||||||
|
|
||||||
|
int yPos = 40;
|
||||||
|
m_AOButton.m_yPos = m_invertYButton.m_yPos = yPos; yPos += 25;
|
||||||
|
m_srvVisButton.m_yPos = m_anaglyphsButton.m_yPos = yPos; yPos += 25;
|
||||||
|
m_fancyGfxButton.m_yPos = m_viewBobButton.m_yPos = yPos; yPos += 25;
|
||||||
|
m_viewDistButton.m_yPos = m_flightHaxButton.m_yPos = yPos; yPos += 25;
|
||||||
|
|
||||||
|
m_buttons.push_back(&m_AOButton);
|
||||||
|
m_buttons.push_back(&m_srvVisButton);
|
||||||
|
m_buttons.push_back(&m_fancyGfxButton);
|
||||||
|
m_buttons.push_back(&m_invertYButton);
|
||||||
|
m_buttons.push_back(&m_anaglyphsButton);
|
||||||
|
m_buttons.push_back(&m_viewBobButton);
|
||||||
|
m_buttons.push_back(&m_viewDistButton);
|
||||||
|
m_buttons.push_back(&m_flightHaxButton);
|
||||||
|
|
||||||
|
m_buttonTabList.push_back(&m_AOButton);
|
||||||
|
m_buttonTabList.push_back(&m_srvVisButton);
|
||||||
|
m_buttonTabList.push_back(&m_fancyGfxButton);
|
||||||
|
m_buttonTabList.push_back(&m_viewDistButton);
|
||||||
|
m_buttonTabList.push_back(&m_invertYButton);
|
||||||
|
m_buttonTabList.push_back(&m_anaglyphsButton);
|
||||||
|
m_buttonTabList.push_back(&m_viewBobButton);
|
||||||
|
m_buttonTabList.push_back(&m_flightHaxButton);
|
||||||
|
|
||||||
|
m_buttonTabList.push_back(&m_BackButton);
|
||||||
|
|
||||||
|
UpdateTexts();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionsScreen::render(int a, int b, float c)
|
||||||
|
{
|
||||||
|
renderBackground();
|
||||||
|
|
||||||
|
if (m_pMinecraft->m_pPlatform->getUserInputStatus() >= 0)
|
||||||
|
{
|
||||||
|
m_pMinecraft->setScreen(new StartMenuScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
drawCenteredString(m_pFont, "Options", m_width / 2, 20, 0xFFFFFF);
|
||||||
|
|
||||||
|
Screen::render(a, b, c);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionsScreen::removed()
|
||||||
|
{
|
||||||
|
m_pMinecraft->reloadOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
|
||||||
|
void OptionsScreen::buttonClicked(Button* pButton)
|
||||||
|
{
|
||||||
|
Options& o = m_pMinecraft->m_options;
|
||||||
|
|
||||||
|
bool* pOption = nullptr;
|
||||||
|
switch (pButton->field_30)
|
||||||
|
{
|
||||||
|
case OB_BACK:
|
||||||
|
if (m_pMinecraft->isLevelGenerated())
|
||||||
|
m_pMinecraft->setScreen(new PauseScreen);
|
||||||
|
else
|
||||||
|
m_pMinecraft->setScreen(new StartMenuScreen);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case OB_AO:
|
||||||
|
o.field_18 ^= 1;
|
||||||
|
Minecraft::useAmbientOcclusion = o.field_18;
|
||||||
|
m_pMinecraft->m_pLevelRenderer->allChanged();
|
||||||
|
UpdateTexts();
|
||||||
|
return;
|
||||||
|
case OB_FANCY_GFX:
|
||||||
|
o.m_bFancyGraphics ^= 1;
|
||||||
|
m_pMinecraft->m_pLevelRenderer->allChanged();
|
||||||
|
UpdateTexts();
|
||||||
|
return;
|
||||||
|
case OB_VIEW_DIST:
|
||||||
|
// @TODO: fix the 'extreme' render distance
|
||||||
|
o.field_10 = (o.field_10 + 1) % 4;
|
||||||
|
UpdateTexts();
|
||||||
|
return;
|
||||||
|
|
||||||
|
case OB_ANAGLYPHS:
|
||||||
|
pOption = &o.m_bAnaglyphs;
|
||||||
|
break;
|
||||||
|
case OB_INVERT_Y:
|
||||||
|
pOption = &o.m_bInvertMouse;
|
||||||
|
break;
|
||||||
|
case OB_SRV_VIS:
|
||||||
|
pOption = &o.m_bServerVisibleDefault;
|
||||||
|
break;
|
||||||
|
case OB_VIEW_BOB:
|
||||||
|
pOption = &o.field_14;
|
||||||
|
break;
|
||||||
|
case OB_FLY_HAX:
|
||||||
|
pOption = &o.m_bFlyCheat;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pOption)
|
||||||
|
return;
|
||||||
|
|
||||||
|
*pOption ^= 1;
|
||||||
|
UpdateTexts();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
30
source/GUI/Screen/OptionsScreen.hpp
Normal file
30
source/GUI/Screen/OptionsScreen.hpp
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Screen.hpp"
|
||||||
|
|
||||||
|
class OptionsScreen : public Screen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OptionsScreen();
|
||||||
|
void init() override;
|
||||||
|
void render(int, int, float) override;
|
||||||
|
void removed() override;
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
void buttonClicked(Button* pButton) override;
|
||||||
|
|
||||||
|
void UpdateTexts();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Button m_BackButton;
|
||||||
|
Button m_AOButton;
|
||||||
|
Button m_srvVisButton;
|
||||||
|
Button m_fancyGfxButton;
|
||||||
|
Button m_invertYButton;
|
||||||
|
Button m_anaglyphsButton;
|
||||||
|
Button m_viewBobButton;
|
||||||
|
Button m_viewDistButton;
|
||||||
|
Button m_flightHaxButton;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
112
source/GUI/Screen/PauseScreen.cpp
Normal file
112
source/GUI/Screen/PauseScreen.cpp
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
#include "PauseScreen.hpp"
|
||||||
|
#include "OptionsScreen.hpp"
|
||||||
|
#include "ServerSideNetworkHandler.hpp"
|
||||||
|
|
||||||
|
PauseScreen::PauseScreen() :
|
||||||
|
m_btnBack(1, "Back to game"),
|
||||||
|
m_btnQuit(2, "Quit to title"),
|
||||||
|
m_btnQuitAndCopy(3, "Quit and copy map"),
|
||||||
|
m_btnVisible(4, "")
|
||||||
|
#ifdef ENH_ADD_OPTIONS_PAUSE
|
||||||
|
, m_btnOptions(999, "Options")
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PauseScreen::init()
|
||||||
|
{
|
||||||
|
m_btnQuit.m_width = 160;
|
||||||
|
m_btnBack.m_width = 160;
|
||||||
|
m_btnVisible.m_width = 160;
|
||||||
|
m_btnQuitAndCopy.m_width = 160;
|
||||||
|
|
||||||
|
m_btnBack.m_yPos = 48;
|
||||||
|
m_btnQuit.m_yPos = 80;
|
||||||
|
m_btnBack.m_xPos = (m_width - 160) / 2;
|
||||||
|
m_btnQuit.m_xPos = (m_width - 160) / 2;
|
||||||
|
m_btnVisible.m_xPos = (m_width - 160) / 2;
|
||||||
|
m_btnQuitAndCopy.m_xPos = (m_width - 160) / 2;
|
||||||
|
|
||||||
|
m_btnVisible.m_yPos = 112;
|
||||||
|
m_btnQuitAndCopy.m_yPos = 112;
|
||||||
|
|
||||||
|
#ifdef ENH_ADD_OPTIONS_PAUSE
|
||||||
|
// TODO: when visible or quit© are on, lower this
|
||||||
|
m_btnOptions.m_width = 160;
|
||||||
|
m_btnOptions.m_yPos = 144;
|
||||||
|
m_btnOptions.m_xPos = m_btnBack.m_xPos;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// add the buttons to the screen:
|
||||||
|
m_buttons.push_back(&m_btnBack);
|
||||||
|
m_buttons.push_back(&m_btnQuit);
|
||||||
|
|
||||||
|
#ifdef ENH_ADD_OPTIONS_PAUSE
|
||||||
|
m_buttons.push_back(&m_btnOptions);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//m_buttons.push_back(&m_btnQuitAndCopy);
|
||||||
|
|
||||||
|
if (m_pMinecraft->m_pRakNetInstance)
|
||||||
|
{
|
||||||
|
updateServerVisibilityText();
|
||||||
|
m_buttons.push_back(&m_btnVisible);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto thing : m_buttons)
|
||||||
|
m_buttonTabList.push_back(thing);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PauseScreen::updateServerVisibilityText()
|
||||||
|
{
|
||||||
|
if (!m_pMinecraft->m_pRakNetInstance) return;
|
||||||
|
if (!m_pMinecraft->m_pRakNetInstance->m_bIsHost) return;
|
||||||
|
|
||||||
|
ServerSideNetworkHandler* pSSNH = (ServerSideNetworkHandler*)m_pMinecraft->m_pNetEventCallback;
|
||||||
|
|
||||||
|
if (pSSNH->m_bAllowIncoming)
|
||||||
|
m_btnVisible.field_18 = "Server is visible";
|
||||||
|
else
|
||||||
|
m_btnVisible.field_18 = "Server is invisible";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PauseScreen::tick()
|
||||||
|
{
|
||||||
|
field_40++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PauseScreen::render(int a, int b, float c)
|
||||||
|
{
|
||||||
|
renderBackground();
|
||||||
|
|
||||||
|
drawCenteredString(m_pFont, "Game menu", m_width / 2, 24, 0xFFFFFF);
|
||||||
|
Screen::render(a, b, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PauseScreen::buttonClicked(Button* pButton)
|
||||||
|
{
|
||||||
|
if (pButton->field_30 == m_btnBack.field_30)
|
||||||
|
m_pMinecraft->setScreen(nullptr);
|
||||||
|
|
||||||
|
if (pButton->field_30 == m_btnQuit.field_30)
|
||||||
|
m_pMinecraft->leaveGame(false);
|
||||||
|
|
||||||
|
if (pButton->field_30 == m_btnQuitAndCopy.field_30)
|
||||||
|
m_pMinecraft->leaveGame(true);
|
||||||
|
|
||||||
|
if (pButton->field_30 == m_btnVisible.field_30)
|
||||||
|
{
|
||||||
|
if (m_pMinecraft->m_pRakNetInstance && m_pMinecraft->m_pRakNetInstance->m_bIsHost)
|
||||||
|
{
|
||||||
|
ServerSideNetworkHandler* pSSNH = (ServerSideNetworkHandler*)m_pMinecraft->m_pNetEventCallback;
|
||||||
|
pSSNH->allowIncomingConnections(!pSSNH->m_bAllowIncoming);
|
||||||
|
|
||||||
|
updateServerVisibilityText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ENH_ADD_OPTIONS_PAUSE
|
||||||
|
if (pButton->field_30 == m_btnOptions.field_30)
|
||||||
|
m_pMinecraft->setScreen(new OptionsScreen);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
28
source/GUI/Screen/PauseScreen.hpp
Normal file
28
source/GUI/Screen/PauseScreen.hpp
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Screen.hpp"
|
||||||
|
|
||||||
|
class PauseScreen : public Screen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PauseScreen();
|
||||||
|
virtual void init() override;
|
||||||
|
virtual void tick() override;
|
||||||
|
virtual void render(int a, int b, float c) override;
|
||||||
|
virtual void buttonClicked(Button*) override;
|
||||||
|
|
||||||
|
void updateServerVisibilityText();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int field_3C = 0;
|
||||||
|
int field_40 = 0;
|
||||||
|
Button m_btnBack;
|
||||||
|
Button m_btnQuit;
|
||||||
|
Button m_btnQuitAndCopy;
|
||||||
|
Button m_btnVisible;
|
||||||
|
|
||||||
|
#ifdef ENH_ADD_OPTIONS_PAUSE
|
||||||
|
Button m_btnOptions;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
78
source/GUI/Screen/ProgressScreen.cpp
Normal file
78
source/GUI/Screen/ProgressScreen.cpp
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
#include "ProgressScreen.hpp"
|
||||||
|
|
||||||
|
bool ProgressScreen::isInGameScreen()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgressScreen::render(int a, int b, float c)
|
||||||
|
{
|
||||||
|
if (m_pMinecraft->isLevelGenerated())
|
||||||
|
{
|
||||||
|
m_pMinecraft->setScreen(nullptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderBackground();
|
||||||
|
|
||||||
|
// render the dirt background
|
||||||
|
// for some reason, this was manually written:
|
||||||
|
|
||||||
|
m_pMinecraft->m_pTextures->loadAndBindTexture("gui/background.png");
|
||||||
|
|
||||||
|
//! why not use the screen stuff
|
||||||
|
int x_width = int(Minecraft::width * Gui::InvGuiScale);
|
||||||
|
int x_height = int(Minecraft::height * Gui::InvGuiScale);
|
||||||
|
|
||||||
|
Tesselator& t = Tesselator::instance;
|
||||||
|
t.begin();
|
||||||
|
t.color(0x404040);
|
||||||
|
t.vertexUV(0.0f, float(x_height), 0, 0, float(x_height) / 32.0f);
|
||||||
|
t.vertexUV(float(x_width), float(x_height), 0, float(x_width) / 32.0f, float(x_height) / 32.0f);
|
||||||
|
t.vertexUV(float(x_width), 0, 0, float(x_width) / 32.0f, 0);
|
||||||
|
t.vertexUV(0.0f, 0, 0, 0, 0);
|
||||||
|
t.draw();
|
||||||
|
|
||||||
|
int yPos = x_height / 2;
|
||||||
|
|
||||||
|
if (m_pMinecraft->m_progressPercent >= 0)
|
||||||
|
{
|
||||||
|
float lX = float(x_width) / 2 - 50, rX = float(x_width) / 2 + 50;
|
||||||
|
float prog = float(m_pMinecraft->m_progressPercent);
|
||||||
|
|
||||||
|
// disable the texturing
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
t.begin();
|
||||||
|
|
||||||
|
t.color(0x808080); // gray background
|
||||||
|
t.vertex(lX, float(yPos + 16), 0);
|
||||||
|
t.vertex(lX, float(yPos + 18), 0);
|
||||||
|
t.vertex(rX, float(yPos + 18), 0);
|
||||||
|
t.vertex(rX, float(yPos + 16), 0);
|
||||||
|
|
||||||
|
t.color(0x80FF80); // the green stuff
|
||||||
|
t.vertex(lX, float(yPos + 16), 0);
|
||||||
|
t.vertex(lX, float(yPos + 18), 0);
|
||||||
|
t.vertex(lX + prog, float(yPos + 18), 0);
|
||||||
|
t.vertex(lX + prog, float(yPos + 16), 0);
|
||||||
|
|
||||||
|
t.draw();
|
||||||
|
|
||||||
|
// restore old state
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Using m_pMinecraft->m_pFont instead of m_pFont.
|
||||||
|
Font* pFont = m_pMinecraft->m_pFont;
|
||||||
|
|
||||||
|
int width = pFont->width("Generating world");
|
||||||
|
pFont->drawShadow("Generating world", (x_width - width) / 2, yPos - 20, 0xFFFFFF);
|
||||||
|
|
||||||
|
width = pFont->width(m_pMinecraft->getProgressMessage());
|
||||||
|
pFont->drawShadow(m_pMinecraft->getProgressMessage(), (x_width - width) / 2, yPos + 4, 0xFFFFFF);
|
||||||
|
|
||||||
|
#ifdef ORIGINAL_CODE
|
||||||
|
sleepMs(50);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
11
source/GUI/Screen/ProgressScreen.hpp
Normal file
11
source/GUI/Screen/ProgressScreen.hpp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Screen.hpp"
|
||||||
|
|
||||||
|
class ProgressScreen : public Screen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void render(int, int, float) override;
|
||||||
|
bool isInGameScreen() override;
|
||||||
|
};
|
||||||
|
|
||||||
30
source/GUI/Screen/RenameMPLevelScreen.cpp
Normal file
30
source/GUI/Screen/RenameMPLevelScreen.cpp
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#include "RenameMPLevelScreen.hpp"
|
||||||
|
#include "StartMenuScreen.hpp"
|
||||||
|
|
||||||
|
RenameMPLevelScreen::RenameMPLevelScreen(const std::string& levelName) : m_levelName(levelName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenameMPLevelScreen::init()
|
||||||
|
{
|
||||||
|
m_pMinecraft->platform()->showDialog(AppPlatform::DLG_RENAME_MP_WORLD);
|
||||||
|
m_pMinecraft->platform()->createUserInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenameMPLevelScreen::render(int mouseX, int mouseY, float f)
|
||||||
|
{
|
||||||
|
int userInputStatus = m_pMinecraft->platform()->getUserInputStatus();
|
||||||
|
if (userInputStatus < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (userInputStatus == 1)
|
||||||
|
{
|
||||||
|
std::vector<std::string> input = m_pMinecraft->platform()->getUserInput();
|
||||||
|
if (input.size() > 0 && !input[0].empty())
|
||||||
|
{
|
||||||
|
m_pMinecraft->getLevelSource()->renameLevel(m_levelName, input[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pMinecraft->setScreen(new StartMenuScreen);
|
||||||
|
}
|
||||||
15
source/GUI/Screen/RenameMPLevelScreen.hpp
Normal file
15
source/GUI/Screen/RenameMPLevelScreen.hpp
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Screen.hpp"
|
||||||
|
|
||||||
|
class RenameMPLevelScreen : public Screen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RenameMPLevelScreen(const std::string& levelName);
|
||||||
|
void init() override;
|
||||||
|
void render(int mouseX, int mouseY, float f) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_levelName;
|
||||||
|
};
|
||||||
|
|
||||||
252
source/GUI/Screen/Screen.cpp
Normal file
252
source/GUI/Screen/Screen.cpp
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
#include "Screen.hpp"
|
||||||
|
|
||||||
|
Screen::Screen()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Screen::~Screen()
|
||||||
|
{
|
||||||
|
m_pClickedButton = nullptr;
|
||||||
|
m_buttons.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::init(Minecraft* pMinecraft, int a3, int a4)
|
||||||
|
{
|
||||||
|
m_width = a3;
|
||||||
|
m_height = a4;
|
||||||
|
m_pMinecraft = pMinecraft;
|
||||||
|
m_pFont = pMinecraft->m_pFont;
|
||||||
|
init();
|
||||||
|
updateTabButtonSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::init()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::buttonClicked(Button* pButton)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::confirmResult(bool b, int i)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Screen::handleBackEvent(bool b)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Screen::isPauseScreen()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Screen::isErrorScreen()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Screen::isInGameScreen()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::keyPressed(int key)
|
||||||
|
{
|
||||||
|
if (key == '\x1B')//escape
|
||||||
|
{
|
||||||
|
m_pMinecraft->setScreen(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_buttonTabList.size())
|
||||||
|
{
|
||||||
|
#ifndef ENH_HIGHLIGHT_BY_HOVER
|
||||||
|
if (m_pMinecraft->m_options.m_keyBinds[Options::MENU_NEXT].value == key)
|
||||||
|
{
|
||||||
|
m_tabButtonIndex++;
|
||||||
|
if (m_tabButtonIndex == int(m_buttonTabList.size()))
|
||||||
|
m_tabButtonIndex = 0;
|
||||||
|
}
|
||||||
|
if (m_pMinecraft->m_options.m_keyBinds[Options::MENU_PREVIOUS].value == key)
|
||||||
|
{
|
||||||
|
m_tabButtonIndex--;
|
||||||
|
if (m_tabButtonIndex == -1)
|
||||||
|
m_tabButtonIndex = int(m_buttonTabList.size() - 1);
|
||||||
|
}
|
||||||
|
if (m_pMinecraft->m_options.m_keyBinds[Options::MENU_OK].value == key)
|
||||||
|
{
|
||||||
|
if (m_buttonTabList[m_tabButtonIndex]->m_bEnabled)
|
||||||
|
{
|
||||||
|
m_pMinecraft->m_pSoundEngine->play("random.click");
|
||||||
|
buttonClicked(m_buttonTabList[m_tabButtonIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTabButtonSelection();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
for (auto textInput : m_textInputs)
|
||||||
|
{
|
||||||
|
textInput->keyPressed(m_pMinecraft, key);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::mouseClicked(int xPos, int yPos, int d) // d = clicked?
|
||||||
|
{
|
||||||
|
if (!d) return;
|
||||||
|
|
||||||
|
for (auto button : m_buttons)
|
||||||
|
{
|
||||||
|
if (button->clicked(m_pMinecraft, xPos, yPos))
|
||||||
|
{
|
||||||
|
m_pClickedButton = button;
|
||||||
|
m_pMinecraft->m_pSoundEngine->play("random.click");
|
||||||
|
|
||||||
|
buttonClicked(button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
for (auto textInput : m_textInputs)
|
||||||
|
{
|
||||||
|
textInput->onClick(xPos, yPos);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::mouseReleased(int xPos, int yPos, int d)
|
||||||
|
{
|
||||||
|
if (!d) return;
|
||||||
|
|
||||||
|
if (m_pClickedButton)
|
||||||
|
{
|
||||||
|
m_pClickedButton->released(xPos, yPos);
|
||||||
|
m_pClickedButton = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::render(int xPos, int yPos, float unused)
|
||||||
|
{
|
||||||
|
for (auto button : m_buttons)
|
||||||
|
{
|
||||||
|
button->render(m_pMinecraft, xPos, yPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
for (auto textInput : m_textInputs)
|
||||||
|
{
|
||||||
|
textInput->tick();
|
||||||
|
textInput->render();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::tick()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::removed()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::setSize(int width, int height)
|
||||||
|
{
|
||||||
|
m_width = width;
|
||||||
|
m_height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::updateEvents()
|
||||||
|
{
|
||||||
|
if (field_10) return;
|
||||||
|
|
||||||
|
for (int i = Mouse::_index + 1; i<int(Mouse::_inputs.size()); i++)
|
||||||
|
{
|
||||||
|
Mouse::_index = i;
|
||||||
|
mouseEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = Keyboard::_index + 1; i<int(Keyboard::_inputs.size()); i++)
|
||||||
|
{
|
||||||
|
Keyboard::_index = i;
|
||||||
|
keyboardEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::keyboardEvent()
|
||||||
|
{
|
||||||
|
// @UB: This probably behaves in an unexpected way if _inputs is empty
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
if (Keyboard::_inputs.empty() || Keyboard::_index < 0)
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (Keyboard::_inputs[Keyboard::_index].field_0)
|
||||||
|
keyPressed(Keyboard::_inputs[Keyboard::_index].field_4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::mouseEvent()
|
||||||
|
{
|
||||||
|
MouseInput& inp = Mouse::_inputs[Mouse::_index];
|
||||||
|
|
||||||
|
if (1 <= inp.field_0 && inp.field_0 <= 2)
|
||||||
|
{
|
||||||
|
if (inp.field_4 == 1)
|
||||||
|
mouseClicked(m_width * Mouse::_x / Minecraft::width, m_height * Mouse::_y / Minecraft::height - 1, inp.field_0);
|
||||||
|
else
|
||||||
|
mouseReleased(m_width * Mouse::_x / Minecraft::width, m_height * Mouse::_y / Minecraft::height - 1, inp.field_0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::renderBackground(int unk)
|
||||||
|
{
|
||||||
|
if (m_pMinecraft->isLevelGenerated())
|
||||||
|
{
|
||||||
|
fillGradient(0, 0, m_width, m_height, 0xC0101010, 0xD0101010);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
renderDirtBackground(unk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::renderBackground()
|
||||||
|
{
|
||||||
|
renderBackground(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::renderDirtBackground(int unk)
|
||||||
|
{
|
||||||
|
glDisable(GL_FOG);
|
||||||
|
|
||||||
|
m_pMinecraft->m_pTextures->loadAndBindTexture("gui/background.png");
|
||||||
|
glColor4f(1, 1, 1, 1);
|
||||||
|
|
||||||
|
Tesselator& t = Tesselator::instance;
|
||||||
|
t.begin();
|
||||||
|
t.color(0x404040);
|
||||||
|
t.vertexUV(0.0f, float(m_height), 0, 0, float(unk) + float(m_height) / 32.0f);
|
||||||
|
t.vertexUV(float(m_width), float(m_height), 0, float(unk) + float(m_width) / 32.0f, float(unk) + float(m_height) / 32.0f);
|
||||||
|
t.vertexUV(float(m_width), 0, 0, float(unk) + float(m_width) / 32.0f, 0);
|
||||||
|
t.vertexUV(0.0f, 0, 0, 0, 0);
|
||||||
|
t.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Screen::updateTabButtonSelection()
|
||||||
|
{
|
||||||
|
#ifndef ENH_HIGHLIGHT_BY_HOVER
|
||||||
|
for (int i = 0; i < int(m_buttonTabList.size()); i++)
|
||||||
|
{
|
||||||
|
m_buttonTabList[i]->field_36 = m_tabButtonIndex == i;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
55
source/GUI/Screen/Screen.hpp
Normal file
55
source/GUI/Screen/Screen.hpp
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Mouse.hpp"
|
||||||
|
#include "Keyboard.hpp"
|
||||||
|
#include "Button.hpp"
|
||||||
|
#include "TextInputBox.hpp"
|
||||||
|
|
||||||
|
class Button;
|
||||||
|
|
||||||
|
class Screen : public GuiComponent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Screen();
|
||||||
|
virtual ~Screen();
|
||||||
|
|
||||||
|
void init(Minecraft*, int, int);
|
||||||
|
void updateTabButtonSelection();
|
||||||
|
void setSize(int width, int height);
|
||||||
|
|
||||||
|
virtual void render(int, int, float);
|
||||||
|
virtual void init();
|
||||||
|
virtual void updateEvents();
|
||||||
|
virtual void mouseEvent();
|
||||||
|
virtual void keyboardEvent();
|
||||||
|
virtual bool handleBackEvent(bool);
|
||||||
|
virtual void tick();
|
||||||
|
virtual void removed();
|
||||||
|
virtual void renderBackground(int);
|
||||||
|
virtual void renderBackground();
|
||||||
|
virtual void renderDirtBackground(int);
|
||||||
|
virtual bool isPauseScreen();
|
||||||
|
virtual bool isErrorScreen();
|
||||||
|
virtual bool isInGameScreen();
|
||||||
|
virtual void confirmResult(bool, int);
|
||||||
|
virtual void buttonClicked(Button*);
|
||||||
|
virtual void mouseClicked(int, int, int);
|
||||||
|
virtual void mouseReleased(int, int, int);
|
||||||
|
virtual void keyPressed(int);
|
||||||
|
|
||||||
|
public:
|
||||||
|
int m_width = 1;
|
||||||
|
int m_height = 1;
|
||||||
|
bool field_10 = false;
|
||||||
|
Minecraft* m_pMinecraft;
|
||||||
|
std::vector<Button*> m_buttons;
|
||||||
|
std::vector<Button*> m_buttonTabList;
|
||||||
|
int m_tabButtonIndex = 0;
|
||||||
|
Font* m_pFont;
|
||||||
|
Button* m_pClickedButton = 0;
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
std::vector<TextInputBox*> m_textInputs;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
246
source/GUI/Screen/SelectWorldScreen.cpp
Normal file
246
source/GUI/Screen/SelectWorldScreen.cpp
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
#include "SelectWorldScreen.hpp"
|
||||||
|
#include "DeleteWorldScreen.hpp"
|
||||||
|
#include "ProgressScreen.hpp"
|
||||||
|
#include "StartMenuScreen.hpp"
|
||||||
|
#include "Util.hpp"
|
||||||
|
|
||||||
|
SelectWorldScreen::SelectWorldScreen() :
|
||||||
|
m_btnDelete (1, "Delete"),
|
||||||
|
m_btnCreateNew(2, "Create new"),
|
||||||
|
m_btnBack (3, "Back"),
|
||||||
|
m_btnUnknown (4, "")
|
||||||
|
{
|
||||||
|
m_btnDelete.m_bEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectWorldScreen::init()
|
||||||
|
{
|
||||||
|
m_pWorldSelectionList = new WorldSelectionList(m_pMinecraft, m_width, m_height);
|
||||||
|
loadLevelSource();
|
||||||
|
m_pWorldSelectionList->commit();
|
||||||
|
|
||||||
|
m_btnDelete.m_yPos = m_btnBack.m_yPos = m_btnCreateNew.m_yPos = m_height - 28;
|
||||||
|
m_btnDelete.m_width = m_btnBack.m_width = m_btnCreateNew.m_width = 84;
|
||||||
|
m_btnDelete.m_height = m_btnBack.m_height = m_btnCreateNew.m_height = 24;
|
||||||
|
|
||||||
|
m_btnDelete.m_xPos = m_width / 2 - 130;
|
||||||
|
m_btnCreateNew.m_xPos = m_width / 2 - 42;
|
||||||
|
m_btnBack.m_xPos = m_width / 2 + 46;
|
||||||
|
|
||||||
|
m_buttons.push_back(&m_btnCreateNew);
|
||||||
|
m_buttons.push_back(&m_btnBack);
|
||||||
|
m_buttons.push_back(&m_btnDelete);
|
||||||
|
|
||||||
|
field_12C = Mouse::_buttonStates[1] == 0;
|
||||||
|
|
||||||
|
m_buttonTabList.push_back(&m_btnUnknown);
|
||||||
|
m_buttonTabList.push_back(&m_btnDelete);
|
||||||
|
m_buttonTabList.push_back(&m_btnCreateNew);
|
||||||
|
m_buttonTabList.push_back(&m_btnBack);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelectWorldScreen::isInGameScreen()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectWorldScreen::keyPressed(int code)
|
||||||
|
{
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
if (m_pMinecraft->m_options.m_keyBinds[Options::MENU_OK].value == code)
|
||||||
|
m_pWorldSelectionList->selectItem(m_pWorldSelectionList->getItemAtPosition(m_width / 2, m_height / 2), false);
|
||||||
|
|
||||||
|
m_btnUnknown.field_36 = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (m_btnUnknown.field_36)
|
||||||
|
{
|
||||||
|
if (m_pMinecraft->m_options.m_keyBinds[Options::LEFT].value == code)
|
||||||
|
m_pWorldSelectionList->stepLeft();
|
||||||
|
|
||||||
|
if (m_pMinecraft->m_options.m_keyBinds[Options::RIGHT].value == code)
|
||||||
|
m_pWorldSelectionList->stepRight();
|
||||||
|
}
|
||||||
|
|
||||||
|
Screen::keyPressed(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char g_SelectWorldFilterArray[] = { '/','\n','\r','\x09','\0','\xC','`','?','*','\\','<','>','|','"',':'};
|
||||||
|
|
||||||
|
void SelectWorldScreen::tick()
|
||||||
|
{
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
m_btnUnknown.field_36 = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (field_130 == 1)
|
||||||
|
{
|
||||||
|
// poll the user status to get details about the world name and seed
|
||||||
|
int userInputStatus = m_pMinecraft->platform()->getUserInputStatus();
|
||||||
|
|
||||||
|
if (userInputStatus < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (userInputStatus != 1)
|
||||||
|
{
|
||||||
|
field_130 = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> userInput = m_pMinecraft->platform()->getUserInput();
|
||||||
|
std::string levelNickname = Util::stringTrim(userInput[0]);
|
||||||
|
std::string levelUniqueName = levelNickname;
|
||||||
|
|
||||||
|
for (int i = 0; i < sizeof(g_SelectWorldFilterArray); i++)
|
||||||
|
{
|
||||||
|
std::string str;
|
||||||
|
str.push_back(g_SelectWorldFilterArray[i]);
|
||||||
|
Util::stringReplace(levelUniqueName, str, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
levelUniqueName = getUniqueLevelName(levelUniqueName);
|
||||||
|
|
||||||
|
int seed = int(getEpochTimeS());
|
||||||
|
if (userInput.size() > 1)
|
||||||
|
{
|
||||||
|
std::string seedThing = Util::stringTrim(userInput[1]);
|
||||||
|
if (!seedThing.empty())
|
||||||
|
{
|
||||||
|
int num;
|
||||||
|
if (sscanf(seedThing.c_str(), "%d", &num) > 0)
|
||||||
|
seed = num;
|
||||||
|
else
|
||||||
|
seed = Util::hashCode(seedThing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pMinecraft->selectLevel(levelUniqueName, levelNickname, seed);
|
||||||
|
m_pMinecraft->hostMultiplayer();
|
||||||
|
m_pMinecraft->setScreen(new ProgressScreen);
|
||||||
|
|
||||||
|
field_130 = 0;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pWorldSelectionList->tick();
|
||||||
|
if (m_pWorldSelectionList->field_90)
|
||||||
|
{
|
||||||
|
LevelSummary& ls = m_pWorldSelectionList->m_levelSummary;
|
||||||
|
m_pMinecraft->selectLevel(ls.field_0, ls.field_18, 0);
|
||||||
|
m_pMinecraft->hostMultiplayer();
|
||||||
|
m_pMinecraft->setScreen(new ProgressScreen);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the level summary stuff is unused.
|
||||||
|
LevelSummary ls;
|
||||||
|
if (isIndexValid(m_pWorldSelectionList->m_selectedIndex))
|
||||||
|
ls = m_pWorldSelectionList->m_items[m_pWorldSelectionList->m_selectedIndex];
|
||||||
|
|
||||||
|
m_btnDelete.m_bEnabled = isIndexValid(m_pWorldSelectionList->m_selectedIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectWorldScreen::render(int mouseX, int mouseY, float f)
|
||||||
|
{
|
||||||
|
renderBackground();
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
m_btnUnknown.field_36 = true;
|
||||||
|
#endif
|
||||||
|
m_pWorldSelectionList->setComponentSelected(m_btnUnknown.field_36);
|
||||||
|
if (field_12C)
|
||||||
|
{
|
||||||
|
m_pWorldSelectionList->render(mouseX, mouseY, f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_pWorldSelectionList->render(0, 0, f);
|
||||||
|
field_12C = Mouse::_buttonStates[1] == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Screen::render(mouseX, mouseY, f);
|
||||||
|
|
||||||
|
drawCenteredString(m_pMinecraft->m_pFont, "Select world", m_width / 2, 8, 0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelectWorldScreen::handleBackEvent(bool b)
|
||||||
|
{
|
||||||
|
if (b)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// @TODO: m_pMinecraft->cancelLocateMultiplayer();
|
||||||
|
m_pMinecraft->setScreen(new StartMenuScreen);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectWorldScreen::buttonClicked(Button* pButton)
|
||||||
|
{
|
||||||
|
if (pButton->field_30 == m_btnCreateNew.field_30)
|
||||||
|
{
|
||||||
|
m_pMinecraft->platform()->showDialog(AppPlatform::DLG_CREATE_WORLD);
|
||||||
|
m_pMinecraft->platform()->createUserInput();
|
||||||
|
field_130 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pButton->field_30 == m_btnDelete.field_30)
|
||||||
|
{
|
||||||
|
LevelSummary ls(m_pWorldSelectionList->m_items[m_pWorldSelectionList->m_selectedIndex]);
|
||||||
|
m_pMinecraft->setScreen(new DeleteWorldScreen(ls));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pButton->field_30 == m_btnBack.field_30)
|
||||||
|
{
|
||||||
|
// @TODO: m_pMinecraft->cancelLocateMultiplayer();
|
||||||
|
m_pMinecraft->setScreen(new StartMenuScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pButton->field_30 == m_btnUnknown.field_30)
|
||||||
|
{
|
||||||
|
m_pWorldSelectionList->selectItem(m_pWorldSelectionList->getItemAtPosition(m_width / 2, m_height / 2), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelectWorldScreen::isIndexValid(int idx)
|
||||||
|
{
|
||||||
|
if (!m_pWorldSelectionList)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (idx < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (idx >= m_pWorldSelectionList->getNumberOfItems())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SelectWorldScreen::getUniqueLevelName(const std::string& in)
|
||||||
|
{
|
||||||
|
std::set<std::string> maps;
|
||||||
|
|
||||||
|
for (const auto& ls : m_levels)
|
||||||
|
{
|
||||||
|
maps.insert(ls.field_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string out = in;
|
||||||
|
while (maps.find(out) != maps.end())
|
||||||
|
out += "-";
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectWorldScreen::loadLevelSource()
|
||||||
|
{
|
||||||
|
m_pMinecraft->getLevelSource()->getLevelList(m_levels);
|
||||||
|
|
||||||
|
std::sort(m_levels.begin(), m_levels.end());
|
||||||
|
|
||||||
|
for (const auto& level : m_levels)
|
||||||
|
{
|
||||||
|
if (level.field_0 == "_LastJoinedServer")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
m_pWorldSelectionList->m_items.push_back(level);
|
||||||
|
}
|
||||||
|
}
|
||||||
33
source/GUI/Screen/SelectWorldScreen.hpp
Normal file
33
source/GUI/Screen/SelectWorldScreen.hpp
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Screen.hpp"
|
||||||
|
#include "WorldSelectionList.hpp"
|
||||||
|
|
||||||
|
class SelectWorldScreen : public Screen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SelectWorldScreen();
|
||||||
|
|
||||||
|
void init() override;
|
||||||
|
bool isInGameScreen() override;
|
||||||
|
void keyPressed(int code) override;
|
||||||
|
void tick() override;
|
||||||
|
void render(int mouseX, int mouseY, float f) override;
|
||||||
|
bool handleBackEvent(bool b) override;
|
||||||
|
void buttonClicked(Button* pButton) override;
|
||||||
|
|
||||||
|
bool isIndexValid(int);
|
||||||
|
std::string getUniqueLevelName(const std::string& in);
|
||||||
|
void loadLevelSource();
|
||||||
|
|
||||||
|
public:
|
||||||
|
Button m_btnDelete;
|
||||||
|
Button m_btnCreateNew;
|
||||||
|
Button m_btnBack;
|
||||||
|
Button m_btnUnknown;
|
||||||
|
WorldSelectionList* m_pWorldSelectionList = nullptr;
|
||||||
|
std::vector<LevelSummary> m_levels;
|
||||||
|
bool field_12C;
|
||||||
|
int field_130 = 0;
|
||||||
|
};
|
||||||
|
|
||||||
171
source/GUI/Screen/StartMenuScreen.cpp
Normal file
171
source/GUI/Screen/StartMenuScreen.cpp
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
#include "StartMenuScreen.hpp"
|
||||||
|
#include "InvalidLicenseScreen.hpp"
|
||||||
|
#include "OptionsScreen.hpp"
|
||||||
|
#include "ProgressScreen.hpp"
|
||||||
|
#include "SelectWorldScreen.hpp"
|
||||||
|
#include "JoinGameScreen.hpp"
|
||||||
|
|
||||||
|
StartMenuScreen::StartMenuScreen() :
|
||||||
|
m_startButton (2, 0, 0, 160, 24, "Start Game"),
|
||||||
|
m_joinButton (3, 0, 0, 160, 24, "Join Game"),
|
||||||
|
m_optionsButton(4, 0, 0, 78, 22, "Options"),
|
||||||
|
m_testButton (999, 0, 0, 78, 22, "Test"),
|
||||||
|
m_buyButton (5, 0, 0, 78, 22, "Buy")
|
||||||
|
//, m_testBox(1, 10, 10, 200, 16, "Insert some text...")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartMenuScreen::_updateLicense()
|
||||||
|
{
|
||||||
|
int licenseID = m_pMinecraft->getLicenseId();
|
||||||
|
if (licenseID < 0)
|
||||||
|
{
|
||||||
|
m_optionsButton.m_bEnabled = false;
|
||||||
|
m_startButton.m_bEnabled = false;
|
||||||
|
m_joinButton.m_bEnabled = false;
|
||||||
|
}
|
||||||
|
else if (licenseID <= 1)
|
||||||
|
{
|
||||||
|
m_optionsButton.m_bEnabled = true;
|
||||||
|
m_startButton.m_bEnabled = true;
|
||||||
|
m_joinButton.m_bEnabled = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_pMinecraft->setScreen(new InvalidLicenseScreen(licenseID, m_pMinecraft->platform()->hasBuyButtonWhenInvalidLicense()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartMenuScreen::buttonClicked(Button* pButton)
|
||||||
|
{
|
||||||
|
if (pButton->field_30 == m_startButton.field_30)
|
||||||
|
{
|
||||||
|
#if defined(DEMO) || !defined(ORIGINAL_CODE)
|
||||||
|
|
||||||
|
# ifdef DEMO
|
||||||
|
# define DEMO_SEED int(getEpochTimeS())
|
||||||
|
# else
|
||||||
|
// 1942892620 = long(12345678901324)
|
||||||
|
# define DEMO_SEED 123456
|
||||||
|
# endif
|
||||||
|
|
||||||
|
m_pMinecraft->selectLevel("_DemoLevel", "_DemoLevel", DEMO_SEED);
|
||||||
|
m_pMinecraft->hostMultiplayer();
|
||||||
|
m_pMinecraft->setScreen(new ProgressScreen);
|
||||||
|
#else
|
||||||
|
m_pMinecraft->setScreen(new SelectWorldScreen);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (pButton->field_30 == m_joinButton.field_30)
|
||||||
|
{
|
||||||
|
m_pMinecraft->locateMultiplayer();
|
||||||
|
m_pMinecraft->setScreen(new JoinGameScreen);
|
||||||
|
}
|
||||||
|
else if (pButton->field_30 == m_buyButton.field_30)
|
||||||
|
{
|
||||||
|
m_pMinecraft->platform()->buyGame();
|
||||||
|
}
|
||||||
|
else if (pButton->field_30 == m_optionsButton.field_30)
|
||||||
|
{
|
||||||
|
m_pMinecraft->setScreen(new OptionsScreen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartMenuScreen::init()
|
||||||
|
{
|
||||||
|
int yPos = m_height / 2;
|
||||||
|
|
||||||
|
m_joinButton.m_yPos = yPos + 25;
|
||||||
|
m_startButton.m_yPos = yPos - 3;
|
||||||
|
|
||||||
|
yPos += 55;
|
||||||
|
|
||||||
|
m_optionsButton.m_yPos = yPos;
|
||||||
|
m_testButton.m_yPos = yPos;
|
||||||
|
m_buyButton.m_yPos = yPos;
|
||||||
|
|
||||||
|
m_startButton.m_xPos = (m_width - m_startButton.m_width) / 2;
|
||||||
|
|
||||||
|
int x1 = m_width - m_joinButton.m_width;
|
||||||
|
|
||||||
|
m_joinButton.m_xPos = x1 / 2;
|
||||||
|
m_optionsButton.m_xPos = x1 / 2;
|
||||||
|
m_buyButton.m_xPos = x1 / 2 + m_optionsButton.m_width + 4;
|
||||||
|
m_testButton.m_xPos = x1 / 2 + m_optionsButton.m_width + 4;
|
||||||
|
|
||||||
|
// add the buttons to the screen:
|
||||||
|
m_buttons.push_back(&m_startButton);
|
||||||
|
m_buttonTabList.push_back(&m_startButton);
|
||||||
|
m_buttons.push_back(&m_joinButton);
|
||||||
|
m_buttonTabList.push_back(&m_joinButton);
|
||||||
|
m_buttons.push_back(&m_optionsButton);
|
||||||
|
m_buttonTabList.push_back(&m_optionsButton);
|
||||||
|
|
||||||
|
#ifdef DEMO
|
||||||
|
m_buttons.push_back(&m_buyButton);
|
||||||
|
m_buttonTabList.push_back(&m_buyButton);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
field_154 = "\xFFMojang AB";
|
||||||
|
field_16C = m_width - 1 - m_pFont->width(field_154);
|
||||||
|
|
||||||
|
field_170 = "v0.1.0 alpha"
|
||||||
|
#ifdef DEMO
|
||||||
|
" (Demo)"
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
|
field_188 = (m_width - m_pFont->width(field_170)) / 2;
|
||||||
|
|
||||||
|
//m_testBox.init(m_pFont);
|
||||||
|
//m_textInputs.push_back(&m_testBox);
|
||||||
|
|
||||||
|
_updateLicense();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StartMenuScreen::isInGameScreen()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartMenuScreen::render(int a, int b, float c)
|
||||||
|
{
|
||||||
|
renderBackground();
|
||||||
|
|
||||||
|
Textures* tx = m_pMinecraft->m_pTextures;
|
||||||
|
|
||||||
|
int id = tx->loadTexture("gui/title.png", true);
|
||||||
|
Texture *pTex = tx->getTemporaryTextureData(id);
|
||||||
|
|
||||||
|
if (pTex)
|
||||||
|
{
|
||||||
|
if (id != tx->m_currBoundTex)
|
||||||
|
{
|
||||||
|
glBindTexture(GL_TEXTURE_2D, id);
|
||||||
|
tx->m_currBoundTex = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
int left = (m_width - pTex->m_width) / 2;
|
||||||
|
int width = pTex->m_width;
|
||||||
|
int height = pTex->m_height;
|
||||||
|
|
||||||
|
Tesselator& t = Tesselator::instance;
|
||||||
|
glColor4f(1, 1, 1, 1);
|
||||||
|
t.begin();
|
||||||
|
t.vertexUV(float(left), float(height + 4), field_4, 0.0f, 1.0f);
|
||||||
|
t.vertexUV(float(left + width), float(height + 4), field_4, 1.0f, 1.0f);
|
||||||
|
t.vertexUV(float(left + width), 4, field_4, 1.0f, 0.0f);
|
||||||
|
t.vertexUV(float(left), 4, field_4, 0.0f, 0.0f);
|
||||||
|
t.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
drawString(m_pFont, field_170, field_188, 62, 0xFFCCCCCC);
|
||||||
|
drawString(m_pFont, field_154, field_16C, m_height - 10, 0x00FFFFFF);
|
||||||
|
|
||||||
|
Screen::render(a, b, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartMenuScreen::tick()
|
||||||
|
{
|
||||||
|
_updateLicense();
|
||||||
|
}
|
||||||
30
source/GUI/Screen/StartMenuScreen.hpp
Normal file
30
source/GUI/Screen/StartMenuScreen.hpp
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Screen.hpp"
|
||||||
|
|
||||||
|
class StartMenuScreen : public Screen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StartMenuScreen();
|
||||||
|
void _updateLicense();
|
||||||
|
|
||||||
|
void init() override;
|
||||||
|
void buttonClicked(Button*) override;
|
||||||
|
bool isInGameScreen() override;
|
||||||
|
void render(int, int, float) override;
|
||||||
|
void tick() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Button m_startButton;
|
||||||
|
Button m_joinButton;
|
||||||
|
Button m_optionsButton;
|
||||||
|
Button m_testButton;
|
||||||
|
Button m_buyButton;
|
||||||
|
std::string field_154;
|
||||||
|
int field_16C;
|
||||||
|
std::string field_170;
|
||||||
|
int field_188;
|
||||||
|
|
||||||
|
//TextInputBox m_testBox;
|
||||||
|
};
|
||||||
|
|
||||||
233
source/GUI/ScrolledSelectionList.cpp
Normal file
233
source/GUI/ScrolledSelectionList.cpp
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
#include "ScrolledSelectionList.hpp"
|
||||||
|
|
||||||
|
#define C_ITEM_WIDTH (220)
|
||||||
|
|
||||||
|
ScrolledSelectionList::ScrolledSelectionList(Minecraft* minecraft, int a3, int a4, int a5, int a6, int a7) :
|
||||||
|
m_pMinecraft(minecraft),
|
||||||
|
field_C(float(a5)),
|
||||||
|
field_10(float(a6)),
|
||||||
|
m_itemHeight(a7),
|
||||||
|
field_18(a3),
|
||||||
|
field_1C(a4),
|
||||||
|
field_20(float(a3))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrolledSelectionList::setRenderSelection(bool b)
|
||||||
|
{
|
||||||
|
m_bRenderSelection = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ScrolledSelectionList::getMaxPosition()
|
||||||
|
{
|
||||||
|
return field_48 + m_itemHeight * getNumberOfItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrolledSelectionList::renderHeader(int a, int b, Tesselator& t)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrolledSelectionList::renderDecorations(int a, int b)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrolledSelectionList::clickedHeader(int x, int y)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int ScrolledSelectionList::getItemAtPosition(int x, int y)
|
||||||
|
{
|
||||||
|
if (x < field_18 / 2 - C_ITEM_WIDTH / 2)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (x > field_18 / 2 + C_ITEM_WIDTH / 2)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return getItemAtYPositionRaw(transformY(y));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrolledSelectionList::capYPosition()
|
||||||
|
{
|
||||||
|
float maxY = float(getMaxPosition()) - (float(field_10 - field_C) - 4.0f);
|
||||||
|
if (maxY < 0.0f)
|
||||||
|
maxY *= 0.5f;
|
||||||
|
|
||||||
|
if (field_34 < 0.0f)
|
||||||
|
field_34 = 0.0f;
|
||||||
|
if (field_34 > maxY)
|
||||||
|
field_34 = maxY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrolledSelectionList::render(int mouseX, int mouseY, float f)
|
||||||
|
{
|
||||||
|
renderBackground();
|
||||||
|
|
||||||
|
int nItems = getNumberOfItems();
|
||||||
|
if (Mouse::_buttonStates[1])
|
||||||
|
{
|
||||||
|
if (float(mouseY) >= field_C && float(mouseY) <= field_10 && mouseY != field_28)
|
||||||
|
{
|
||||||
|
int field_2C_old = field_2C;
|
||||||
|
|
||||||
|
if (field_2C == -1)
|
||||||
|
{
|
||||||
|
field_2C = 1;
|
||||||
|
}
|
||||||
|
else if (field_2C == 1)
|
||||||
|
{
|
||||||
|
field_3C = mouseY;
|
||||||
|
field_40 = getTimeMs();
|
||||||
|
}
|
||||||
|
else if (field_2C == 0)
|
||||||
|
{
|
||||||
|
float diff = float(mouseY) - field_30;
|
||||||
|
field_34 -= diff;
|
||||||
|
field_38 += diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field_2C_old >= 0)
|
||||||
|
field_2C = 0;
|
||||||
|
|
||||||
|
field_28 = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (field_2C >= 0)
|
||||||
|
{
|
||||||
|
if (fabsf(field_38) < 2.0f)
|
||||||
|
field_38 = 0.0f;
|
||||||
|
|
||||||
|
if (getTimeMs() - field_40 < 300)
|
||||||
|
{
|
||||||
|
if (transformY(mouseY) / m_itemHeight >= 0 && m_itemHeight > abs(field_3C - mouseY))
|
||||||
|
{
|
||||||
|
selectItem(transformY(mouseY) / m_itemHeight, false);
|
||||||
|
field_38 = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
field_2C = -1;
|
||||||
|
field_34 -= field_38;
|
||||||
|
}
|
||||||
|
|
||||||
|
field_30 = float(mouseY);
|
||||||
|
field_38 *= 0.75f;
|
||||||
|
capYPosition();
|
||||||
|
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
glDisable(GL_FOG);
|
||||||
|
|
||||||
|
m_pMinecraft->m_pTextures->loadAndBindTexture("gui/background.png");
|
||||||
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
|
Tesselator& t = Tesselator::instance;
|
||||||
|
t.begin();
|
||||||
|
t.color(0x202020);
|
||||||
|
t.vertexUV(field_24, field_10, 0.0f, field_24 / 32.0f, (field_10 + float(int(field_34))) / 32.0f);
|
||||||
|
t.vertexUV(field_20, field_10, 0.0f, field_20 / 32.0f, (field_10 + float(int(field_34))) / 32.0f);
|
||||||
|
t.vertexUV(field_20, field_C, 0.0f, field_20 / 32.0f, (field_C + float(int(field_34))) / 32.0f);
|
||||||
|
t.vertexUV(field_24, field_C, 0.0f, field_24 / 32.0f, (field_C + float(int(field_34))) / 32.0f);
|
||||||
|
t.draw();
|
||||||
|
|
||||||
|
int itemX = field_18 / 2 - (C_ITEM_WIDTH - 4) / 2;
|
||||||
|
int scrollY = int(field_C + 4 - float(int(field_34)));
|
||||||
|
|
||||||
|
if (field_45)
|
||||||
|
renderHeader(itemX, scrollY, t);
|
||||||
|
|
||||||
|
for (int i = 0; i < nItems; i++)
|
||||||
|
{
|
||||||
|
float itemY = float(field_48 + scrollY + i * m_itemHeight);
|
||||||
|
if (field_10 < itemY)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
float lowerY = itemY + m_itemHeight - 4;
|
||||||
|
if (lowerY < field_C)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (m_bRenderSelection && isSelectedItem(i))
|
||||||
|
{
|
||||||
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
t.begin();
|
||||||
|
t.color(0x808080);
|
||||||
|
t.vertexUV(float(field_18) / 2.0f - C_ITEM_WIDTH / 2.0f, lowerY + 2.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
t.vertexUV(float(field_18) / 2.0f + C_ITEM_WIDTH / 2.0f, lowerY + 2.0f, 0.0f, 1.0f, 1.0f);
|
||||||
|
t.vertexUV(float(field_18) / 2.0f + C_ITEM_WIDTH / 2.0f, itemY - 2.0f, 0.0f, 1.0f, 0.0f);
|
||||||
|
t.vertexUV(float(field_18) / 2.0f - C_ITEM_WIDTH / 2.0f, itemY - 2.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
t.color(0x000000);
|
||||||
|
t.vertexUV(float(field_18) / 2.0f - C_ITEM_WIDTH / 2.0f + 1, lowerY + 1.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
t.vertexUV(float(field_18) / 2.0f + C_ITEM_WIDTH / 2.0f - 1, lowerY + 1.0f, 0.0f, 1.0f, 1.0f);
|
||||||
|
t.vertexUV(float(field_18) / 2.0f + C_ITEM_WIDTH / 2.0f - 1, itemY - 1.0f, 0.0f, 1.0f, 0.0f);
|
||||||
|
t.vertexUV(float(field_18) / 2.0f - C_ITEM_WIDTH / 2.0f + 1, itemY - 1.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
t.draw();
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderItem(i, itemX, int(itemY), int(m_itemHeight - 4.0f), t);
|
||||||
|
}
|
||||||
|
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
renderHoleBackground(0.0f, field_C, 255, 255);
|
||||||
|
renderHoleBackground(field_10, float(field_1C), 255, 255);
|
||||||
|
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glDisable(GL_ALPHA_TEST);
|
||||||
|
glShadeModel(GL_SMOOTH);
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
t.begin();
|
||||||
|
t.color(0, 0);
|
||||||
|
t.vertexUV(field_24, field_C + 4.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
t.vertexUV(field_20, field_C + 4.0f, 0.0f, 1.0f, 1.0f);
|
||||||
|
t.color(0, 255);
|
||||||
|
t.vertexUV(field_20, field_C, 0.0f, 1.0f, 0.0f);
|
||||||
|
t.vertexUV(field_24, field_C, 0.0f, 0.0f, 0.0f);
|
||||||
|
t.draw();
|
||||||
|
|
||||||
|
t.begin();
|
||||||
|
t.color(0, 255);
|
||||||
|
t.vertexUV(field_24, field_10, 0.0f, 0.0f, 1.0f);
|
||||||
|
t.vertexUV(field_20, field_10, 0.0f, 1.0f, 1.0f);
|
||||||
|
t.color(0, 0);
|
||||||
|
t.vertexUV(field_20, field_10 - 4.0f, 0.0f, 1.0f, 0.0f);
|
||||||
|
t.vertexUV(field_24, field_10 - 4.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
t.draw();
|
||||||
|
|
||||||
|
renderDecorations(mouseX, mouseY);
|
||||||
|
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glShadeModel(GL_FLAT);
|
||||||
|
glEnable(GL_ALPHA_TEST);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrolledSelectionList::renderHoleBackground(float a, float b, int c, int d)
|
||||||
|
{
|
||||||
|
m_pMinecraft->m_pTextures->loadAndBindTexture("gui/background.png");
|
||||||
|
|
||||||
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
|
Tesselator& t = Tesselator::instance;
|
||||||
|
t.begin();
|
||||||
|
t.color(0x505050, d);
|
||||||
|
t.vertexUV(0.0f, b, 0.0f, 0.0f, b / 32.0f);
|
||||||
|
t.vertexUV(float(field_18), b, 0.0f, field_18 / 32.0f, b / 32.0f);
|
||||||
|
t.color(0x505050, c);
|
||||||
|
t.vertexUV(float(field_18), a, 0.0f, field_18 / 32.0f, a / 32.0f);
|
||||||
|
t.vertexUV(0.0f, a, 0.0f, 0.0f, a / 32.0f);
|
||||||
|
t.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrolledSelectionList::setRenderHeader(bool b, int i)
|
||||||
|
{
|
||||||
|
field_45 = b;
|
||||||
|
if (!b)
|
||||||
|
i = 0;
|
||||||
|
field_48 = i;
|
||||||
|
}
|
||||||
71
source/GUI/ScrolledSelectionList.hpp
Normal file
71
source/GUI/ScrolledSelectionList.hpp
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "GuiComponent.hpp"
|
||||||
|
#include "Minecraft.hpp"
|
||||||
|
|
||||||
|
class ScrolledSelectionList : public GuiComponent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ScrolledSelectionList(Minecraft*, int, int, int, int, int);
|
||||||
|
|
||||||
|
virtual void setRenderSelection(bool);
|
||||||
|
virtual int getNumberOfItems() = 0;
|
||||||
|
virtual void selectItem(int, bool) = 0;
|
||||||
|
virtual bool isSelectedItem(int) = 0;
|
||||||
|
virtual int getMaxPosition();
|
||||||
|
virtual void renderItem(int, int, int, int, Tesselator&) = 0;
|
||||||
|
virtual void renderHeader(int, int, Tesselator&);
|
||||||
|
virtual void renderBackground() = 0;
|
||||||
|
virtual void renderDecorations(int, int);
|
||||||
|
virtual void clickedHeader(int x, int y);
|
||||||
|
virtual int getItemAtPosition(int x, int y);
|
||||||
|
virtual void capYPosition();
|
||||||
|
virtual void render(int mouseX, int mouseY, float f);
|
||||||
|
virtual void renderHoleBackground(float, float, int, int);
|
||||||
|
|
||||||
|
void setRenderHeader(bool, int);
|
||||||
|
|
||||||
|
|
||||||
|
// @NOTE: This is inlined.
|
||||||
|
inline int getItemAtYPositionRaw(int y)
|
||||||
|
{
|
||||||
|
if (y < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// @NOTE: redundant check
|
||||||
|
int idx = y / m_itemHeight;
|
||||||
|
if (idx < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (idx >= getNumberOfItems())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
// @NOTE: This is also inlined.
|
||||||
|
inline int transformY(int y)
|
||||||
|
{
|
||||||
|
return int(y - field_C - field_48 + field_34 - 4.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Minecraft* m_pMinecraft;
|
||||||
|
float field_C;
|
||||||
|
float field_10;
|
||||||
|
int m_itemHeight;
|
||||||
|
int field_18;
|
||||||
|
int field_1C;
|
||||||
|
float field_20;
|
||||||
|
float field_24 = 0.0f;
|
||||||
|
int field_28;
|
||||||
|
int field_2C = -2;
|
||||||
|
float field_30 = 0.0f;
|
||||||
|
float field_34 = 0.0f;
|
||||||
|
float field_38 = 0.0f;
|
||||||
|
int field_3C = -1;
|
||||||
|
int field_40 = 0;
|
||||||
|
bool m_bRenderSelection = true;
|
||||||
|
bool field_45 = false;
|
||||||
|
int field_48 = 0;
|
||||||
|
};
|
||||||
|
|
||||||
25
source/GUI/SmallButton.cpp
Normal file
25
source/GUI/SmallButton.cpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#include "SmallButton.hpp"
|
||||||
|
|
||||||
|
// @NOTE: Used in the ConfirmScreen.
|
||||||
|
// I reckon this was used in the OptionsScreen as well, since the button sizes are the same.
|
||||||
|
|
||||||
|
SmallButton::SmallButton(int id, int x, int y, const std::string& str) :
|
||||||
|
Button(id, x, y, 150, 20, str)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SmallButton::SmallButton(int id, int x, int y, int width, int height, const std::string& str) :
|
||||||
|
Button(id, x, y, width, height, str)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SmallButton::SmallButton(int id, int x, int y, Options::Option* pOption, const std::string& str) :
|
||||||
|
Button(id, x, y, 150, 20, str),
|
||||||
|
m_pOption(pOption)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Options::Option* SmallButton::getOption()
|
||||||
|
{
|
||||||
|
return m_pOption;
|
||||||
|
}
|
||||||
16
source/GUI/SmallButton.hpp
Normal file
16
source/GUI/SmallButton.hpp
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Button.hpp"
|
||||||
|
|
||||||
|
class SmallButton : public Button
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SmallButton(int id, int x, int y, const std::string& str);
|
||||||
|
SmallButton(int id, int x, int y, int width, int height, const std::string& str);
|
||||||
|
SmallButton(int id, int x, int y, Options::Option* pOption, const std::string& str);
|
||||||
|
Options::Option* getOption();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Options::Option* m_pOption = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
258
source/GUI/TextInputBox.cpp
Normal file
258
source/GUI/TextInputBox.cpp
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
#include "TextInputBox.hpp"
|
||||||
|
#include "Minecraft.hpp"
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
|
||||||
|
TextInputBox::TextInputBox(int id, int x, int y) :
|
||||||
|
TextInputBox(id, x, y, 200, 12, "", "")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TextInputBox::TextInputBox(int id, int x, int y, int width, int height) :
|
||||||
|
TextInputBox(id, x, y, width, height, "", "")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TextInputBox::TextInputBox(int id, int x, int y, int width, int height, const std::string& placeholder) :
|
||||||
|
TextInputBox(id, x, y, width, height, placeholder, "")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TextInputBox::TextInputBox(int id, int x, int y, int width, int height, const std::string& placeholder, const std::string& text) :
|
||||||
|
m_ID(id),
|
||||||
|
m_xPos(x),
|
||||||
|
m_yPos(y),
|
||||||
|
m_width(width),
|
||||||
|
m_height(height),
|
||||||
|
m_placeholder(placeholder),
|
||||||
|
m_text(text)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputBox::init(Font* pFont)
|
||||||
|
{
|
||||||
|
m_pFont = pFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputBox::setEnabled(bool bEnabled)
|
||||||
|
{
|
||||||
|
m_bEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputBox::keyPressed(Minecraft* minecraft, int key)
|
||||||
|
{
|
||||||
|
if (!m_bFocused)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool bShiftPressed = minecraft->platform()->shiftPressed();
|
||||||
|
|
||||||
|
char chr = '\0';
|
||||||
|
if (key >= AKEYCODE_A && key <= AKEYCODE_Z)
|
||||||
|
{
|
||||||
|
chr = char((key - AKEYCODE_A) + (bShiftPressed ? 'A' : 'a'));
|
||||||
|
}
|
||||||
|
if (key >= AKEYCODE_0 && key <= AKEYCODE_9)
|
||||||
|
{
|
||||||
|
static const char shiftmap[] = { ')', '!', '@', '#', '$', '%', '^', '&', '*', '(' };
|
||||||
|
chr = char(bShiftPressed ? shiftmap[key - AKEYCODE_0] : (key - AKEYCODE_0 + '0'));
|
||||||
|
}
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case AKEYCODE_DEL:
|
||||||
|
chr = '\b';
|
||||||
|
break;
|
||||||
|
case AKEYCODE_FORWARD_DEL:
|
||||||
|
chr = '\001';
|
||||||
|
break;
|
||||||
|
case AKEYCODE_ARROW_LEFT:
|
||||||
|
chr = '\002';
|
||||||
|
break;
|
||||||
|
case AKEYCODE_ARROW_RIGHT:
|
||||||
|
chr = '\003';
|
||||||
|
break;
|
||||||
|
case AKEYCODE_COMMA:
|
||||||
|
chr = bShiftPressed ? '<' : ',';
|
||||||
|
break;
|
||||||
|
case AKEYCODE_PERIOD:
|
||||||
|
chr = bShiftPressed ? '>' : ':';
|
||||||
|
break;
|
||||||
|
case AKEYCODE_PLUS:
|
||||||
|
chr = bShiftPressed ? '+' : '=';
|
||||||
|
break;
|
||||||
|
case AKEYCODE_MINUS:
|
||||||
|
chr = bShiftPressed ? '_' : '-';
|
||||||
|
break;
|
||||||
|
case AKEYCODE_SEMICOLON:
|
||||||
|
chr = bShiftPressed ? ':' : ';';
|
||||||
|
break;
|
||||||
|
case AKEYCODE_SLASH:
|
||||||
|
chr = bShiftPressed ? '?' : '/';
|
||||||
|
break;
|
||||||
|
case AKEYCODE_GRAVE:
|
||||||
|
chr = bShiftPressed ? '~' : '`';
|
||||||
|
break;
|
||||||
|
case AKEYCODE_BACKSLASH:
|
||||||
|
chr = bShiftPressed ? '|' : '\\';
|
||||||
|
break;
|
||||||
|
case AKEYCODE_APOSTROPHE:
|
||||||
|
chr = bShiftPressed ? '"' : '\'';
|
||||||
|
break;
|
||||||
|
case AKEYCODE_LEFT_BRACKET:
|
||||||
|
chr = bShiftPressed ? '{' : '[';
|
||||||
|
break;
|
||||||
|
case AKEYCODE_RIGHT_BRACKET:
|
||||||
|
chr = bShiftPressed ? '}' : ']';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chr)
|
||||||
|
charPressed(chr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputBox::tick()
|
||||||
|
{
|
||||||
|
if (!m_lastFlashed)
|
||||||
|
m_lastFlashed = getTimeMs();
|
||||||
|
|
||||||
|
if (m_bFocused)
|
||||||
|
{
|
||||||
|
if (getTimeMs() > m_lastFlashed + 500)
|
||||||
|
{
|
||||||
|
m_lastFlashed += 500;
|
||||||
|
m_bCursorOn ^= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_bCursorOn = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputBox::setFocused(bool b)
|
||||||
|
{
|
||||||
|
if (m_bFocused == b)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_bFocused = b;
|
||||||
|
if (b)
|
||||||
|
{
|
||||||
|
m_lastFlashed = getTimeMs();
|
||||||
|
m_bCursorOn = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputBox::onClick(int x, int y)
|
||||||
|
{
|
||||||
|
setFocused(clicked(x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputBox::charPressed(int k)
|
||||||
|
{
|
||||||
|
if (!m_bFocused)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (k == '\b')
|
||||||
|
{
|
||||||
|
if (m_text.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_insertHead <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_insertHead > int(m_text.size()))
|
||||||
|
m_insertHead = int(m_text.size());
|
||||||
|
|
||||||
|
m_text.erase(m_text.begin() + m_insertHead - 1, m_text.begin() + m_insertHead);
|
||||||
|
m_insertHead--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k == '\001') // delete
|
||||||
|
{
|
||||||
|
if (m_text.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_insertHead < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_insertHead >= int(m_text.size()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_text.erase(m_text.begin() + m_insertHead, m_text.begin() + m_insertHead + 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k == '\002') // left
|
||||||
|
{
|
||||||
|
m_insertHead--;
|
||||||
|
if (m_insertHead < 0)
|
||||||
|
m_insertHead = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k == '\003') // right
|
||||||
|
{
|
||||||
|
m_insertHead++;
|
||||||
|
if (!m_text.empty())
|
||||||
|
{
|
||||||
|
if (m_insertHead > int(m_text.size()))
|
||||||
|
m_insertHead = int(m_text.size());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_insertHead = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k == '\n' || k == '\r')
|
||||||
|
{
|
||||||
|
m_bFocused = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// other unrenderable character?
|
||||||
|
if (k < ' ' || k > '~')
|
||||||
|
return;
|
||||||
|
|
||||||
|
// note: the width will increase by the same amount no matter where K is appended
|
||||||
|
int width = m_pFont->width(m_text + char(k));
|
||||||
|
if (width < m_width - 2)
|
||||||
|
{
|
||||||
|
m_text.insert(m_text.begin() + m_insertHead, k);
|
||||||
|
m_insertHead++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputBox::render()
|
||||||
|
{
|
||||||
|
fill(m_xPos, m_yPos, m_xPos + m_width, m_yPos + m_height, 0xFF000000);
|
||||||
|
|
||||||
|
int textYPos = (m_height - 8) / 2;
|
||||||
|
|
||||||
|
if (m_text.empty())
|
||||||
|
drawString(m_pFont, m_placeholder, m_xPos + 1, m_xPos + 1, 0x404040);
|
||||||
|
else
|
||||||
|
drawString(m_pFont, m_text, m_xPos + 1, m_xPos + textYPos, 0xFFFFFF);
|
||||||
|
|
||||||
|
if (m_bCursorOn)
|
||||||
|
{
|
||||||
|
int xPos = 1;
|
||||||
|
|
||||||
|
std::string substr = m_text.substr(0, m_insertHead);
|
||||||
|
xPos += m_pFont->width(substr);
|
||||||
|
|
||||||
|
drawString(m_pFont, "_", m_xPos + xPos, m_xPos + textYPos + 1, 0xFFFFFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TextInputBox::clicked(int xPos, int yPos)
|
||||||
|
{
|
||||||
|
if (!m_bEnabled) return false;
|
||||||
|
|
||||||
|
if (xPos < m_xPos) return false;
|
||||||
|
if (yPos < m_yPos) return false;
|
||||||
|
if (xPos >= m_xPos + m_width) return false;
|
||||||
|
if (yPos >= m_yPos + m_height) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
46
source/GUI/TextInputBox.hpp
Normal file
46
source/GUI/TextInputBox.hpp
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Utils.hpp"
|
||||||
|
#include "GuiComponent.hpp"
|
||||||
|
|
||||||
|
class Minecraft;
|
||||||
|
|
||||||
|
// @NOTE: This is NOT original Mojang code.
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
|
||||||
|
class TextInputBox : public GuiComponent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TextInputBox(int id, int x, int y);
|
||||||
|
TextInputBox(int id, int x, int y, int width, int height);
|
||||||
|
TextInputBox(int id, int x, int y, int width, int height, const std::string& placeholder);
|
||||||
|
TextInputBox(int id, int x, int y, int width, int height, const std::string& placeholder, const std::string& text);
|
||||||
|
|
||||||
|
void init(Font* pFont);
|
||||||
|
void setEnabled(bool bEnabled);
|
||||||
|
void keyPressed(Minecraft*, int key);
|
||||||
|
void charPressed(int chr);
|
||||||
|
void render();
|
||||||
|
void tick();
|
||||||
|
void setFocused(bool b);
|
||||||
|
void onClick(int x, int y);
|
||||||
|
bool clicked(int x, int y);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_ID = 0;
|
||||||
|
int m_xPos = 0;
|
||||||
|
int m_yPos = 0;
|
||||||
|
int m_width = 0;
|
||||||
|
int m_height = 0;
|
||||||
|
std::string m_placeholder;
|
||||||
|
std::string m_text;
|
||||||
|
bool m_bFocused = false;
|
||||||
|
bool m_bEnabled = true;
|
||||||
|
bool m_bCursorOn = true;
|
||||||
|
int m_insertHead = 0;
|
||||||
|
int m_lastFlashed = 0;
|
||||||
|
Font* m_pFont = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
209
source/GUI/WorldSelectionList.cpp
Normal file
209
source/GUI/WorldSelectionList.cpp
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
#include "WorldSelectionList.hpp"
|
||||||
|
#include "Utils.hpp"
|
||||||
|
|
||||||
|
static float WorldSelectionList_Static1(float a, float b, float c, float d)
|
||||||
|
{
|
||||||
|
float x1 = 2 * (a / b), x2;
|
||||||
|
|
||||||
|
if (x1 < 1.0f)
|
||||||
|
x2 = c + ((d - c) * 0.5f) * x1 * x1;
|
||||||
|
else
|
||||||
|
x2 = c + ((d - c) * -0.5f) * ((x1 - 1.0f) * (x1 - 3.0f) - 1.0f);
|
||||||
|
|
||||||
|
return x2;
|
||||||
|
}
|
||||||
|
|
||||||
|
WorldSelectionList::WorldSelectionList(Minecraft* minecraft, int a, int b) :
|
||||||
|
RolledSelectionList(minecraft, a, b, 0, a, 26, b - 32, 120)
|
||||||
|
{
|
||||||
|
field_68 = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WorldSelectionList::capXPosition()
|
||||||
|
{
|
||||||
|
if (RolledSelectionList::capXPosition())
|
||||||
|
{
|
||||||
|
field_D8 = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldSelectionList::tick()
|
||||||
|
{
|
||||||
|
RolledSelectionList::tick();
|
||||||
|
field_D0++;
|
||||||
|
if (Mouse::_buttonStates[1] || !field_28)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_selectedIndex = -1;
|
||||||
|
if (field_D8 == 1)
|
||||||
|
{
|
||||||
|
field_54 += 1.0f;
|
||||||
|
if (field_54 != field_58)
|
||||||
|
{
|
||||||
|
tweenInited();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
field_D8 = 0;
|
||||||
|
field_38 = 0.0f;
|
||||||
|
field_34 = field_30 = field_60;
|
||||||
|
m_selectedIndex = getItemAtPosition(field_18 / 2, field_1C / 2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float abs_field38 = Mth::abs(field_38);
|
||||||
|
if (abs_field38 >= 5.0f)
|
||||||
|
{
|
||||||
|
field_38 *= 0.9f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
field_38 *= 0.8f;
|
||||||
|
if (abs_field38 < 1.0f && field_28 < 0)
|
||||||
|
{
|
||||||
|
float x1 = float((field_18 - m_itemWidth) / 2) + field_30;
|
||||||
|
int x2 = getItemAtXPositionRaw(int(x1 - 10.0f * field_38));
|
||||||
|
float x3 = float(m_itemWidth * x2) - x1;
|
||||||
|
|
||||||
|
if (x3 < -float(m_itemWidth / 2))
|
||||||
|
x3 += float(m_itemWidth);
|
||||||
|
|
||||||
|
if (Mth::abs(x3) > 1.0f || abs_field38 >= 0.1f)
|
||||||
|
{
|
||||||
|
field_5C = field_30;
|
||||||
|
field_60 = field_30 + x3;
|
||||||
|
field_54 = 0.0f;
|
||||||
|
field_D8 = 1;
|
||||||
|
field_58 = float(Mth::Min(7, int(float(0.25f * Mth::abs(x3))) + 1));
|
||||||
|
|
||||||
|
tweenInited();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_selectedIndex = getItemAtPosition(field_18 / 2, field_1C / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int WorldSelectionList::getNumberOfItems()
|
||||||
|
{
|
||||||
|
return int(m_items.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldSelectionList::selectItem(int index, bool b)
|
||||||
|
{
|
||||||
|
if (m_selectedIndex >= 0 && m_selectedIndex == index && !field_90)
|
||||||
|
{
|
||||||
|
field_90 = 1;
|
||||||
|
m_levelSummary = m_items[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WorldSelectionList::isSelectedItem(int index)
|
||||||
|
{
|
||||||
|
return m_selectedIndex == index;
|
||||||
|
}
|
||||||
|
|
||||||
|
float WorldSelectionList::getPos(float f)
|
||||||
|
{
|
||||||
|
if (field_D8 != 1)
|
||||||
|
return RolledSelectionList::getPos(f);
|
||||||
|
|
||||||
|
return Lerp(WorldSelectionList_Static1(field_54, field_58, field_5C, field_60),
|
||||||
|
WorldSelectionList_Static1(field_54 + 1.0f, field_58, field_5C, field_60),
|
||||||
|
f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldSelectionList::touched()
|
||||||
|
{
|
||||||
|
field_D8 = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldSelectionList::renderItem(int index, int xPos, int yPos, int width, Tesselator& t)
|
||||||
|
{
|
||||||
|
int xCenter = xPos + m_itemWidth / 2;
|
||||||
|
float mult = Max(1.1f - 0.0055f * float(abs(field_18 / 2 - xCenter)), 0.2f);
|
||||||
|
if (mult > 1.0f)
|
||||||
|
mult = 1.0f;
|
||||||
|
|
||||||
|
int color1 = 0x010101 * int(mult * 255.0f);
|
||||||
|
int color2 = 0x010101 * int(mult * 140.0f);
|
||||||
|
|
||||||
|
std::vector<std::string> details = m_vvs[index];
|
||||||
|
|
||||||
|
drawString(m_pMinecraft->m_pFont, details[0], xCenter + 5 - m_itemWidth / 2, yPos + 50, color1);
|
||||||
|
drawString(m_pMinecraft->m_pFont, details[1], xCenter + 5 - m_itemWidth / 2, yPos + 60, color2);
|
||||||
|
drawString(m_pMinecraft->m_pFont, details[2], xCenter + 5 - m_itemWidth / 2, yPos + 70, color2);
|
||||||
|
|
||||||
|
m_pMinecraft->m_pTextures->loadAndBindTexture(m_previewImages[index]);
|
||||||
|
|
||||||
|
// @NOTE: useless assignment of color
|
||||||
|
t.color(0.3f, 1.0f, 0.2f);
|
||||||
|
|
||||||
|
t.begin();
|
||||||
|
t.color(color1);
|
||||||
|
float y = float(yPos) - 6.0f;
|
||||||
|
t.vertexUV(float(xCenter - 32), y, this->field_4, 0.0f, 0.0f);
|
||||||
|
t.vertexUV(float(xCenter - 32), y + 48.0f, this->field_4, 0.0f, 1.0f);
|
||||||
|
t.vertexUV(float(xCenter + 32), y + 48.0f, this->field_4, 1.0f, 1.0f);
|
||||||
|
t.vertexUV(float(xCenter + 32), y, this->field_4, 1.0f, 0.0f);
|
||||||
|
t.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldSelectionList::renderBackground()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldSelectionList::commit()
|
||||||
|
{
|
||||||
|
for (const auto& item : m_items)
|
||||||
|
{
|
||||||
|
// @NOTE: this string stream crap is unused.
|
||||||
|
// Weirdly Java Edition Beta 1.3 did not have world previews, so its interesting to see PE try
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << item.field_18 << "/preview.png";
|
||||||
|
|
||||||
|
m_previewImages.push_back("gui/default_world.png");
|
||||||
|
|
||||||
|
std::vector<std::string> vs;
|
||||||
|
vs.push_back(item.field_18);
|
||||||
|
vs.push_back(m_pMinecraft->platform()->getDateString(item.field_30));
|
||||||
|
vs.push_back(item.field_0);
|
||||||
|
m_vvs.push_back(vs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldSelectionList::stepLeft()
|
||||||
|
{
|
||||||
|
if (m_selectedIndex <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
field_5C = field_30;
|
||||||
|
field_D8 = 1;
|
||||||
|
field_60 = field_5C - float(m_itemWidth);
|
||||||
|
field_54 = 0.0f;
|
||||||
|
field_58 = 8.0f;
|
||||||
|
tweenInited();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldSelectionList::stepRight()
|
||||||
|
{
|
||||||
|
if (m_selectedIndex < 0 || m_selectedIndex >= getNumberOfItems() - 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
field_5C = field_30;
|
||||||
|
field_D8 = 1;
|
||||||
|
field_60 = field_5C + float(m_itemWidth);
|
||||||
|
field_54 = 0.0f;
|
||||||
|
field_58 = 8.0f;
|
||||||
|
tweenInited();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldSelectionList::tweenInited()
|
||||||
|
{
|
||||||
|
field_38 =
|
||||||
|
WorldSelectionList_Static1(field_54, field_58, field_5C, field_60) -
|
||||||
|
WorldSelectionList_Static1(field_54 + 1.0f, field_58, field_5C, field_60);
|
||||||
|
}
|
||||||
42
source/GUI/WorldSelectionList.hpp
Normal file
42
source/GUI/WorldSelectionList.hpp
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RolledSelectionList.hpp"
|
||||||
|
|
||||||
|
class WorldSelectionList : public RolledSelectionList
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WorldSelectionList(Minecraft*, int, int);
|
||||||
|
|
||||||
|
bool capXPosition() override;
|
||||||
|
void tick() override;
|
||||||
|
int getNumberOfItems() override;
|
||||||
|
void selectItem(int, bool) override;
|
||||||
|
bool isSelectedItem(int) override;
|
||||||
|
float getPos(float) override;
|
||||||
|
void touched() override;
|
||||||
|
void renderItem(int, int, int, int, Tesselator&) override;
|
||||||
|
void renderBackground() override;
|
||||||
|
|
||||||
|
void commit();
|
||||||
|
void stepLeft();
|
||||||
|
void stepRight();
|
||||||
|
void tweenInited();
|
||||||
|
|
||||||
|
public:
|
||||||
|
float field_54;
|
||||||
|
float field_58;
|
||||||
|
float field_5C;
|
||||||
|
float field_60;
|
||||||
|
int m_selectedIndex;
|
||||||
|
int field_68;
|
||||||
|
std::vector<LevelSummary> m_items;
|
||||||
|
std::vector<std::vector<std::string> > m_vvs;
|
||||||
|
std::vector<std::string> m_previewImages;
|
||||||
|
bool field_90 = false;
|
||||||
|
LevelSummary m_levelSummary;
|
||||||
|
int field_CC = -1;
|
||||||
|
int field_D0 = 0;
|
||||||
|
int field_D4;
|
||||||
|
int field_D8 = 0;
|
||||||
|
};
|
||||||
|
|
||||||
110
source/GameMode/GameMode.cpp
Normal file
110
source/GameMode/GameMode.cpp
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
#include "GameMode.hpp"
|
||||||
|
#include "Minecraft.hpp"
|
||||||
|
|
||||||
|
GameMode::GameMode(Minecraft* pMinecraft)
|
||||||
|
{
|
||||||
|
m_pMinecraft = pMinecraft;
|
||||||
|
}
|
||||||
|
|
||||||
|
GameMode::~GameMode()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameMode::initLevel(Level* pLevel)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameMode::startDestroyBlock(int x, int y, int z, int i)
|
||||||
|
{
|
||||||
|
destroyBlock(x, y, z, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameMode::destroyBlock(int x, int y, int z, int i)
|
||||||
|
{
|
||||||
|
Level* pLevel = m_pMinecraft->m_pLevel;
|
||||||
|
Tile* pTile = Tile::tiles[pLevel->getTile(x, y, z)];
|
||||||
|
int tileData = pLevel->getData(x, y, z);
|
||||||
|
|
||||||
|
bool bChanged = pLevel->setTile(x, y, z, 0);
|
||||||
|
|
||||||
|
if (pTile && bChanged)
|
||||||
|
{
|
||||||
|
m_pMinecraft->m_pSoundEngine->play("step." + pTile->m_pSound->m_name,
|
||||||
|
float(x) + 0.5f, float(y) + 0.5f, float(z) + 0.5f,
|
||||||
|
0.5f * (1.0f + pTile->m_pSound->field_18), 0.8f * pTile->m_pSound->field_1C);
|
||||||
|
|
||||||
|
pTile->destroy(pLevel, x, y, z, tileData);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameMode::continueDestroyBlock(int x, int y, int z, int t)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameMode::stopDestroyBlock()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameMode::tick()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameMode::render(float f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
float GameMode::getPickRange()
|
||||||
|
{
|
||||||
|
return 7.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalPlayer* GameMode::createPlayer(Level* pLevel)
|
||||||
|
{
|
||||||
|
return new LocalPlayer(m_pMinecraft, pLevel, m_pMinecraft->m_pUser, pLevel->m_pDimension->field_50);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameMode::initPlayer(Player* pPlayer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameMode::adjustPlayer(Player* pPlayer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameMode::canHurtPlayer()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameMode::interact(Player* player, Entity* entity)
|
||||||
|
{
|
||||||
|
player->interact(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameMode::attack(Player* player, Entity* entity)
|
||||||
|
{
|
||||||
|
player->attack(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
int GameMode::handleInventoryMouseClick(int a, int b, int c, Player* player)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameMode::handleCloseInventory(int a, Player* player)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameMode::isCreativeType()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameMode::isSurvivalType()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
37
source/GameMode/GameMode.hpp
Normal file
37
source/GameMode/GameMode.hpp
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Level.hpp"
|
||||||
|
#include "ItemInstance.hpp"
|
||||||
|
|
||||||
|
class Minecraft;
|
||||||
|
|
||||||
|
class GameMode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GameMode(Minecraft* pMinecraft);
|
||||||
|
virtual ~GameMode();
|
||||||
|
virtual void initLevel(Level*);
|
||||||
|
virtual void startDestroyBlock(int, int, int, int);
|
||||||
|
virtual bool destroyBlock(int, int, int, int);
|
||||||
|
virtual void continueDestroyBlock(int, int, int, int);
|
||||||
|
virtual void stopDestroyBlock();
|
||||||
|
virtual void tick();
|
||||||
|
virtual void render(float f);
|
||||||
|
virtual float getPickRange();
|
||||||
|
virtual bool useItem(Player*, Level*, ItemInstance*);
|
||||||
|
virtual bool useItemOn(Player*, Level*, ItemInstance*, int, int, int, int);
|
||||||
|
virtual LocalPlayer* createPlayer(Level*);
|
||||||
|
virtual void initPlayer(Player*);
|
||||||
|
virtual void adjustPlayer(Player*);
|
||||||
|
virtual bool canHurtPlayer();
|
||||||
|
virtual void interact(Player*, Entity*);
|
||||||
|
virtual void attack(Player*, Entity*);
|
||||||
|
virtual int handleInventoryMouseClick(int, int, int, Player*);
|
||||||
|
virtual void handleCloseInventory(int, Player*);
|
||||||
|
virtual bool isCreativeType();
|
||||||
|
virtual bool isSurvivalType();
|
||||||
|
|
||||||
|
public:
|
||||||
|
Minecraft* m_pMinecraft;
|
||||||
|
uint8_t field_8 = 0;
|
||||||
|
};
|
||||||
171
source/GameMode/SurvivalMode.cpp
Normal file
171
source/GameMode/SurvivalMode.cpp
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
#include "SurvivalMode.hpp"
|
||||||
|
#include "Minecraft.hpp"
|
||||||
|
|
||||||
|
SurvivalMode::SurvivalMode(Minecraft* pMC) : GameMode(pMC)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SurvivalMode::initPlayer(Player* p)
|
||||||
|
{
|
||||||
|
p->m_yaw = -180.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SurvivalMode::startDestroyBlock(int x, int y, int z, int i)
|
||||||
|
{
|
||||||
|
TileID tile = m_pMinecraft->m_pLevel->getTile(x, y, z);
|
||||||
|
|
||||||
|
if (tile <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifdef ENH_INSTA_BREAK
|
||||||
|
destroyBlock(x, y, z, i);
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (field_18 == 0.0f)
|
||||||
|
{
|
||||||
|
Tile::tiles[tile]->attack(m_pMinecraft->m_pLevel, x, y, z, m_pMinecraft->m_pLocalPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Tile::tiles[tile]->getDestroyProgress(m_pMinecraft->m_pLocalPlayer) >= 1.0f)
|
||||||
|
{
|
||||||
|
destroyBlock(x, y, z, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SurvivalMode::destroyBlock(int x, int y, int z, int i)
|
||||||
|
{
|
||||||
|
m_pMinecraft->m_pParticleEngine->destroy(x, y, z);
|
||||||
|
|
||||||
|
TileID tile = m_pMinecraft->m_pLevel->getTile(x, y, z);
|
||||||
|
int data = m_pMinecraft->m_pLevel->getData(x, y, z);
|
||||||
|
|
||||||
|
if (!GameMode::destroyBlock(x, y, z, i))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//@HUH: check too late?
|
||||||
|
bool bCanDestroy = m_pMinecraft->m_pLocalPlayer->canDestroy(Tile::tiles[tile]);
|
||||||
|
|
||||||
|
if (bCanDestroy)
|
||||||
|
{
|
||||||
|
Tile::tiles[tile]->playerDestroy(m_pMinecraft->m_pLevel, m_pMinecraft->m_pLocalPlayer, x, y, z, data);
|
||||||
|
|
||||||
|
if (m_pMinecraft->isOnline())
|
||||||
|
{
|
||||||
|
m_pMinecraft->m_pRakNetInstance->send(new RemoveBlockPacket(m_pMinecraft->m_pLocalPlayer->m_EntityID, x, y, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SurvivalMode::continueDestroyBlock(int x, int y, int z, int i)
|
||||||
|
{
|
||||||
|
if (field_24 > 0)
|
||||||
|
{
|
||||||
|
field_24--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_destroyingX != x || m_destroyingY != y || m_destroyingZ != z)
|
||||||
|
{
|
||||||
|
field_18 = 0.0f;
|
||||||
|
field_1C = 0.0f;
|
||||||
|
field_20 = 0;
|
||||||
|
m_destroyingX = x;
|
||||||
|
m_destroyingY = y;
|
||||||
|
m_destroyingZ = z;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TileID tile = m_pMinecraft->m_pLevel->getTile(m_destroyingX, m_destroyingY, m_destroyingZ);
|
||||||
|
if (!tile)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Tile* pTile = Tile::tiles[tile];
|
||||||
|
float destroyProgress = pTile->getDestroyProgress(m_pMinecraft->m_pLocalPlayer);
|
||||||
|
|
||||||
|
field_18 += 16.0f * destroyProgress;
|
||||||
|
field_20++;
|
||||||
|
|
||||||
|
if ((field_20 & 3) == 1)
|
||||||
|
{
|
||||||
|
m_pMinecraft->m_pSoundEngine->play("step." + pTile->m_pSound->m_name,
|
||||||
|
float(x) + 0.5f, float(y) + 0.5f, float(z) + 0.5f,
|
||||||
|
0.5f * (1.0f + pTile->m_pSound->field_18), 0.8f * pTile->m_pSound->field_1C);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field_18 >= 1.0f)
|
||||||
|
{
|
||||||
|
destroyBlock(m_destroyingX, m_destroyingY, m_destroyingZ, i);
|
||||||
|
field_20 = 0;
|
||||||
|
field_24 = 5;
|
||||||
|
field_18 = 0.0f;
|
||||||
|
field_1C = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SurvivalMode::stopDestroyBlock()
|
||||||
|
{
|
||||||
|
field_18 = 0.0f;
|
||||||
|
field_24 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SurvivalMode::tick()
|
||||||
|
{
|
||||||
|
field_1C = field_18;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SurvivalMode::render(float f)
|
||||||
|
{
|
||||||
|
if (field_18 <= 0.0f)
|
||||||
|
{
|
||||||
|
m_pMinecraft->m_gui.field_8 = 0.0f;
|
||||||
|
m_pMinecraft->m_pLevelRenderer->field_10 = 0.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float x = field_1C + (field_18 - field_1C) * f;
|
||||||
|
m_pMinecraft->m_gui.field_8 = x;
|
||||||
|
m_pMinecraft->m_pLevelRenderer->field_10 = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float SurvivalMode::getPickRange()
|
||||||
|
{
|
||||||
|
return 5.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SurvivalMode::isCreativeType()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SurvivalMode::isSurvivalType()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameMode::useItem(Player* player, Level* level, ItemInstance* instance)
|
||||||
|
{
|
||||||
|
int oldAmount = instance->m_amount;
|
||||||
|
|
||||||
|
if (instance == instance->use(level, player))
|
||||||
|
return instance->m_amount != oldAmount;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameMode::useItemOn(Player* player, Level* level, ItemInstance* instance, int x, int y, int z, int d)
|
||||||
|
{
|
||||||
|
TileID tile = level->getTile(x, y, z);
|
||||||
|
if (tile > 0 && Tile::tiles[tile]->use(level, x, y, z, player))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (instance)
|
||||||
|
return instance->useOn(player, level, x, y, z, d);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
30
source/GameMode/SurvivalMode.hpp
Normal file
30
source/GameMode/SurvivalMode.hpp
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "GameMode.hpp"
|
||||||
|
|
||||||
|
class SurvivalMode : public GameMode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SurvivalMode(Minecraft*);
|
||||||
|
|
||||||
|
virtual void startDestroyBlock(int x, int y, int z, int i) override;
|
||||||
|
virtual bool destroyBlock(int x, int y, int z, int i);
|
||||||
|
virtual void continueDestroyBlock(int x, int y, int z, int i);
|
||||||
|
virtual void stopDestroyBlock() override;
|
||||||
|
virtual void tick() override;
|
||||||
|
virtual void render(float f) override;
|
||||||
|
virtual float getPickRange() override;
|
||||||
|
virtual bool isCreativeType() override;
|
||||||
|
virtual bool isSurvivalType() override;
|
||||||
|
virtual void initPlayer(Player*) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
int m_destroyingX = -1;
|
||||||
|
int m_destroyingY = -1;
|
||||||
|
int m_destroyingZ = -1;
|
||||||
|
float field_18 = 0.0f;
|
||||||
|
float field_1C = 0.0f;
|
||||||
|
int field_20 = 0;
|
||||||
|
int field_24 = 0;
|
||||||
|
};
|
||||||
|
|
||||||
198
source/Inventory.cpp
Normal file
198
source/Inventory.cpp
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
#include "Inventory.hpp"
|
||||||
|
#include "Item.hpp"
|
||||||
|
|
||||||
|
#ifdef DEMO
|
||||||
|
|
||||||
|
static void MoveItemToSlot(int* pItems, int item, int index)
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= C_MAX_INVENTORY_ITEMS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (pItems[index] == item)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// search for the item, if it doesn't exist, return
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (; i < C_MAX_INVENTORY_ITEMS; i++)
|
||||||
|
{
|
||||||
|
if (pItems[i] == item)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == C_MAX_INVENTORY_ITEMS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// swap the slot where our `item` was, and the slot at the index
|
||||||
|
int oldItem = pItems[index];
|
||||||
|
pItems[index] = pItems[i];
|
||||||
|
pItems[i] = oldItem;
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
if (item > 0)
|
||||||
|
#endif
|
||||||
|
printf("adding item: %s to %d\n", Tile::tiles[item]->getDescriptionId().c_str(), index);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ShuffleInventoryForDemo(int* pHotbar, int* pItems)
|
||||||
|
{
|
||||||
|
pHotbar[0] = Tile::wood->m_ID;
|
||||||
|
pHotbar[1] = Tile::stoneBrick->m_ID;
|
||||||
|
pHotbar[2] = Tile::sandStone->m_ID;
|
||||||
|
pHotbar[3] = Tile::dirt->m_ID;
|
||||||
|
pHotbar[4] = Tile::redBrick->m_ID;
|
||||||
|
pHotbar[5] = Tile::rock->m_ID;
|
||||||
|
pHotbar[6] = Tile::torch->m_ID;
|
||||||
|
pHotbar[7] = Tile::ladder->m_ID;
|
||||||
|
#ifdef ENH_ENABLE_9TH_SLOT
|
||||||
|
pHotbar[8] = Tile::rose->m_ID;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MoveItemToSlot(pItems, pHotbar[0], 27);
|
||||||
|
MoveItemToSlot(pItems, pHotbar[1], 28);
|
||||||
|
MoveItemToSlot(pItems, pHotbar[2], 29);
|
||||||
|
MoveItemToSlot(pItems, pHotbar[3], 30);
|
||||||
|
MoveItemToSlot(pItems, pHotbar[4], 31);
|
||||||
|
MoveItemToSlot(pItems, pHotbar[5], 32);
|
||||||
|
MoveItemToSlot(pItems, pHotbar[6], 33);
|
||||||
|
MoveItemToSlot(pItems, pHotbar[7], 34);
|
||||||
|
MoveItemToSlot(pItems, Tile::flower->m_ID, 35);
|
||||||
|
MoveItemToSlot(pItems, Tile::cloth_10->m_ID, 18);
|
||||||
|
MoveItemToSlot(pItems, Tile::cloth_20->m_ID, 19);
|
||||||
|
MoveItemToSlot(pItems, Tile::cloth_30->m_ID, 20);
|
||||||
|
MoveItemToSlot(pItems, Tile::cloth_40->m_ID, 21);
|
||||||
|
MoveItemToSlot(pItems, Tile::cloth_50->m_ID, 22);
|
||||||
|
MoveItemToSlot(pItems, Tile::cloth_60->m_ID, 23);
|
||||||
|
MoveItemToSlot(pItems, Tile::cloth_70->m_ID, 24);
|
||||||
|
MoveItemToSlot(pItems, Tile::sand->m_ID, 25);
|
||||||
|
MoveItemToSlot(pItems, Tile::glass->m_ID, 26);
|
||||||
|
MoveItemToSlot(pItems, Tile::mushroom1->m_ID, 1);
|
||||||
|
MoveItemToSlot(pItems, Tile::obsidian->m_ID, 8);
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
// @NOTE: For Testing
|
||||||
|
//pHotbar[1] = Item::camera->m_itemID;
|
||||||
|
//pHotbar[2] = Tile::tnt->m_ID;
|
||||||
|
//pHotbar[3] = Tile::water->m_ID;
|
||||||
|
//pHotbar[4] = Tile::lava->m_ID;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Inventory::Inventory(Player* pPlayer)
|
||||||
|
{
|
||||||
|
m_pPlayer = pPlayer;
|
||||||
|
m_SelectedHotbarSlot = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < C_MAX_HOTBAR_ITEMS; i++)
|
||||||
|
m_hotbar[i] = -1;
|
||||||
|
for (int i = 0; i < C_MAX_INVENTORY_ITEMS; i++)
|
||||||
|
m_items[i] = -1;
|
||||||
|
|
||||||
|
// @NOTE: This layout of the hotbar and inventory can be seen in the following video,
|
||||||
|
// titled "Minecraft - Pocket Edition on Xperia Play".
|
||||||
|
// https://www.youtube.com/watch?v=jO-y5wzmK4E
|
||||||
|
|
||||||
|
m_hotbar[0] = Tile::wood->m_ID;
|
||||||
|
m_hotbar[1] = Tile::cloth_10->m_ID;
|
||||||
|
m_hotbar[2] = Tile::cloth_20->m_ID;
|
||||||
|
m_hotbar[3] = Tile::cloth_30->m_ID;
|
||||||
|
m_hotbar[4] = Tile::cloth_40->m_ID;
|
||||||
|
m_hotbar[5] = Tile::cloth_50->m_ID;
|
||||||
|
m_hotbar[6] = Tile::cloth_60->m_ID;
|
||||||
|
m_hotbar[7] = Tile::ladder->m_ID;
|
||||||
|
|
||||||
|
// slot 8 missing. I assume that's the "..." button
|
||||||
|
|
||||||
|
m_items[0] = Tile::rock->m_ID;
|
||||||
|
m_items[1] = Tile::stoneBrick->m_ID;
|
||||||
|
m_items[2] = Tile::sandStone->m_ID;
|
||||||
|
m_items[3] = Tile::wood->m_ID;
|
||||||
|
m_items[4] = Tile::treeTrunk->m_ID;
|
||||||
|
m_items[5] = Tile::goldBlock->m_ID;
|
||||||
|
m_items[6] = Tile::ironBlock->m_ID;
|
||||||
|
m_items[7] = Tile::emeraldBlock->m_ID;
|
||||||
|
m_items[8] = Tile::redBrick->m_ID;
|
||||||
|
m_items[9] = Tile::leaves->m_ID;
|
||||||
|
m_items[10] = Tile::cloth_10->m_ID;
|
||||||
|
m_items[11] = Tile::cloth_20->m_ID;
|
||||||
|
m_items[12] = Tile::cloth_30->m_ID;
|
||||||
|
m_items[13] = Tile::cloth_40->m_ID;
|
||||||
|
m_items[14] = Tile::cloth_50->m_ID;
|
||||||
|
m_items[15] = Tile::cloth_60->m_ID;
|
||||||
|
m_items[16] = Tile::cloth_70->m_ID;
|
||||||
|
m_items[17] = Tile::glass->m_ID;
|
||||||
|
m_items[18] = Tile::cloth_01->m_ID;
|
||||||
|
m_items[19] = Tile::cloth_11->m_ID;
|
||||||
|
m_items[20] = Tile::cloth_21->m_ID;
|
||||||
|
m_items[21] = Tile::cloth_31->m_ID;
|
||||||
|
m_items[22] = Tile::cloth_41->m_ID;
|
||||||
|
m_items[23] = Tile::stairs_wood->m_ID;
|
||||||
|
m_items[24] = Tile::stairs_stone->m_ID;
|
||||||
|
m_items[25] = Tile::stoneSlabHalf->m_ID;
|
||||||
|
m_items[26] = Tile::sand->m_ID;
|
||||||
|
m_items[27] = Tile::ladder->m_ID;
|
||||||
|
m_items[28] = Tile::torch->m_ID;
|
||||||
|
m_items[29] = Tile::flower->m_ID;
|
||||||
|
m_items[30] = Tile::rose->m_ID;
|
||||||
|
m_items[31] = Tile::mushroom1->m_ID;
|
||||||
|
m_items[32] = Tile::mushroom2->m_ID;
|
||||||
|
m_items[33] = Tile::reeds->m_ID;
|
||||||
|
m_items[34] = Tile::obsidian->m_ID;
|
||||||
|
m_items[35] = Tile::dirt->m_ID;
|
||||||
|
|
||||||
|
#ifdef DEMO
|
||||||
|
ShuffleInventoryForDemo(m_hotbar, m_items);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENH_EXTRA_ITEMS_IN_INV
|
||||||
|
// populate the 5th row now with items that might be of interest
|
||||||
|
m_items[36] = Tile::tnt->m_ID;
|
||||||
|
m_items[37] = Item::camera->m_itemID;
|
||||||
|
m_items[38] = Item::door_wood->m_itemID;
|
||||||
|
m_items[39] = Tile::gravel->m_ID;
|
||||||
|
m_items[40] = Tile::water->m_ID;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ENH_ENABLE_9TH_SLOT
|
||||||
|
#define HOTBAR_DIFF 0
|
||||||
|
#else
|
||||||
|
#define HOTBAR_DIFF 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int Inventory::getSelectionSize()
|
||||||
|
{
|
||||||
|
return C_MAX_HOTBAR_ITEMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Inventory::getSelectionSlotItemId(int slot)
|
||||||
|
{
|
||||||
|
if (slot >= 0 && slot < C_MAX_HOTBAR_ITEMS - HOTBAR_DIFF)
|
||||||
|
return m_hotbar[slot];
|
||||||
|
|
||||||
|
if (slot > C_MAX_HOTBAR_ITEMS + C_MAX_INVENTORY_ITEMS - 1 || slot < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return m_items[slot - C_MAX_HOTBAR_ITEMS];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inventory::setSelectionSlotItemId(int slotNo, int item)
|
||||||
|
{
|
||||||
|
if (slotNo >= 0 && slotNo < C_MAX_HOTBAR_ITEMS - HOTBAR_DIFF)
|
||||||
|
m_hotbar[slotNo] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Inventory::getSelectedItemId()
|
||||||
|
{
|
||||||
|
return getSelectionSlotItemId(m_SelectedHotbarSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inventory::selectSlot(int slotNo)
|
||||||
|
{
|
||||||
|
if (slotNo < 0 || slotNo >= C_MAX_HOTBAR_ITEMS - HOTBAR_DIFF)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_SelectedHotbarSlot = slotNo;
|
||||||
|
}
|
||||||
33
source/Inventory.hpp
Normal file
33
source/Inventory.hpp
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Player.hpp"
|
||||||
|
|
||||||
|
class Player; // in case we're included from Player.hpp
|
||||||
|
|
||||||
|
#define C_MAX_HOTBAR_ITEMS (9)
|
||||||
|
|
||||||
|
#ifdef ENH_EXTRA_ITEMS_IN_INV
|
||||||
|
#define C_MAX_INVENTORY_ITEMS (36+9)
|
||||||
|
#else
|
||||||
|
#define C_MAX_INVENTORY_ITEMS (36)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class Inventory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Inventory(Player*);
|
||||||
|
|
||||||
|
int getSelectionSize();
|
||||||
|
int getSelectionSlotItemId(int slotNo);
|
||||||
|
int getSelectedItemId();
|
||||||
|
void selectSlot(int slotNo);
|
||||||
|
void setSelectionSlotItemId(int slotNo, int item);
|
||||||
|
|
||||||
|
public:
|
||||||
|
int m_SelectedHotbarSlot;
|
||||||
|
Player* m_pPlayer;
|
||||||
|
|
||||||
|
int m_hotbar[C_MAX_HOTBAR_ITEMS];
|
||||||
|
int m_items [C_MAX_INVENTORY_ITEMS];
|
||||||
|
};
|
||||||
|
|
||||||
357
source/Network/ClientSideNetworkHandler.cpp
Normal file
357
source/Network/ClientSideNetworkHandler.cpp
Normal file
@@ -0,0 +1,357 @@
|
|||||||
|
#include <RakPeer.h>
|
||||||
|
#include "ClientSideNetworkHandler.hpp"
|
||||||
|
|
||||||
|
// This lets you make the client shut up and not log events in the debug console.
|
||||||
|
#define VERBOSE_CLIENT
|
||||||
|
|
||||||
|
#if defined(ORIGINAL_CODE) || defined(VERBOSE_CLIENT)
|
||||||
|
#define puts_ignorable(str) puts(str)
|
||||||
|
#define printf_ignorable(str, ...) printf(str, __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define puts_ignorable(str)
|
||||||
|
#define printf_ignorable(str, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ClientSideNetworkHandler::ClientSideNetworkHandler(Minecraft* pMinecraft, RakNetInstance* pRakNetInstance)
|
||||||
|
{
|
||||||
|
m_pMinecraft = pMinecraft;
|
||||||
|
m_pRakNetInstance = pRakNetInstance;
|
||||||
|
m_pServerPeer = m_pRakNetInstance->getPeer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientSideNetworkHandler::levelGenerated(Level* level)
|
||||||
|
{
|
||||||
|
m_pLevel = level;
|
||||||
|
requestNextChunk();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientSideNetworkHandler::onConnect(const RakNet::RakNetGUID& rakGuid) // server guid
|
||||||
|
{
|
||||||
|
RakNet::RakNetGUID localGuid = ((RakNet::RakPeer*)m_pServerPeer)->GetMyGUID();
|
||||||
|
printf_ignorable("onConnect, server guid: %s, local guid: %s\n", rakGuid.ToString(), localGuid.ToString());
|
||||||
|
|
||||||
|
m_serverGUID = rakGuid;
|
||||||
|
|
||||||
|
LoginPacket* pLoginPkt = new LoginPacket;
|
||||||
|
pLoginPkt->m_str = RakNet::RakString(m_pMinecraft->m_pUser->field_0.c_str());
|
||||||
|
|
||||||
|
m_pRakNetInstance->send(pLoginPkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientSideNetworkHandler::onUnableToConnect()
|
||||||
|
{
|
||||||
|
puts_ignorable("onUnableToConnect");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientSideNetworkHandler::onDisconnect(const RakNet::RakNetGUID& rakGuid)
|
||||||
|
{
|
||||||
|
puts_ignorable("onDisconnect");
|
||||||
|
|
||||||
|
if (m_pLevel)
|
||||||
|
m_pLevel->field_11 = false;
|
||||||
|
|
||||||
|
m_pMinecraft->m_gui.addMessage("Disconnected from server");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, MessagePacket* pMsgPkt)
|
||||||
|
{
|
||||||
|
puts_ignorable("MessagePacket");
|
||||||
|
|
||||||
|
m_pMinecraft->m_gui.addMessage(pMsgPkt->m_str.C_String());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, StartGamePacket* pStartGamePkt)
|
||||||
|
{
|
||||||
|
puts_ignorable("StartGamePacket");
|
||||||
|
|
||||||
|
m_pMinecraft->getLevelSource()->deleteLevel("_LastJoinedServer");
|
||||||
|
|
||||||
|
m_pLevel = new Level(
|
||||||
|
m_pMinecraft->getLevelSource()->selectLevel("_LastJoinedServer", true),
|
||||||
|
"temp",
|
||||||
|
pStartGamePkt->field_4,
|
||||||
|
pStartGamePkt->field_8);
|
||||||
|
|
||||||
|
m_pLevel->field_11 = true;
|
||||||
|
|
||||||
|
auto pLocalPlayer = new LocalPlayer(m_pMinecraft, m_pLevel, m_pMinecraft->m_pUser, m_pLevel->m_pDimension->field_50);
|
||||||
|
pLocalPlayer->m_guid = ((RakNet::RakPeer*)m_pServerPeer)->GetMyGUID();
|
||||||
|
pLocalPlayer->m_EntityID = pStartGamePkt->field_C;
|
||||||
|
|
||||||
|
pLocalPlayer->moveTo(
|
||||||
|
pStartGamePkt->field_10,
|
||||||
|
pStartGamePkt->field_14,
|
||||||
|
pStartGamePkt->field_18,
|
||||||
|
pLocalPlayer->m_yaw,
|
||||||
|
pLocalPlayer->m_pitch);
|
||||||
|
|
||||||
|
m_pMinecraft->setLevel(m_pLevel, "ClientSideNetworkHandler -> setLevel", pLocalPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, AddPlayerPacket* pAddPlayerPkt)
|
||||||
|
{
|
||||||
|
puts_ignorable("AddPlayerPacket");
|
||||||
|
|
||||||
|
if (!m_pLevel) return;
|
||||||
|
|
||||||
|
Player* pPlayer = new Player(m_pLevel);
|
||||||
|
pPlayer->m_EntityID = pAddPlayerPkt->m_id;
|
||||||
|
m_pLevel->addEntity(pPlayer);
|
||||||
|
|
||||||
|
pPlayer->moveTo(
|
||||||
|
pAddPlayerPkt->m_x,
|
||||||
|
pAddPlayerPkt->m_y,
|
||||||
|
pAddPlayerPkt->m_z,
|
||||||
|
pPlayer->m_yaw,
|
||||||
|
pPlayer->m_pitch);
|
||||||
|
|
||||||
|
pPlayer->m_name = pAddPlayerPkt->m_name;
|
||||||
|
pPlayer->m_guid = pAddPlayerPkt->m_guid;
|
||||||
|
|
||||||
|
m_pMinecraft->m_gui.addMessage(pPlayer->m_name + " joined the game");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, RemoveEntityPacket* pRemoveEntityPkt)
|
||||||
|
{
|
||||||
|
if (!m_pLevel) return;
|
||||||
|
|
||||||
|
Entity* pEnt = m_pLevel->getEntity(pRemoveEntityPkt->m_id);
|
||||||
|
|
||||||
|
#if defined(ORIGINAL_CODE) || UINTPTR_MAX == UINT32_MAX
|
||||||
|
// @NOTE: On x64 systems, this won't print the right things.
|
||||||
|
printf_ignorable("RemoveEntityPacket %d %d", pEnt, m_pMinecraft->m_pLocalPlayer);
|
||||||
|
#else
|
||||||
|
printf_ignorable("RemoveEntityPacket %p %p", pEnt, m_pMinecraft->m_pLocalPlayer);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (pEnt)
|
||||||
|
m_pLevel->removeEntity(pEnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, MovePlayerPacket* packet)
|
||||||
|
{
|
||||||
|
if (!m_pLevel) return;
|
||||||
|
|
||||||
|
Entity* pEntity = m_pLevel->getEntity(packet->m_id);
|
||||||
|
if (!pEntity)
|
||||||
|
{
|
||||||
|
LogMsg("No player with id %d", packet->m_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pEntity->lerpTo(packet->m_x, packet->m_y, packet->m_z, packet->m_yaw, packet->m_pitch, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, PlaceBlockPacket* pPlaceBlockPkt)
|
||||||
|
{
|
||||||
|
puts_ignorable("PlaceBlockPacket");
|
||||||
|
|
||||||
|
Player* pPlayer = (Player*)m_pLevel->getEntity(pPlaceBlockPkt->m_playerID);
|
||||||
|
if (!pPlayer)
|
||||||
|
{
|
||||||
|
LogMsg("No player with id %d", pPlaceBlockPkt->m_playerID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pPlayer->swing();
|
||||||
|
|
||||||
|
// @BUG: Not buffering the update.
|
||||||
|
if (!areAllChunksLoaded())
|
||||||
|
return;
|
||||||
|
|
||||||
|
int x = pPlaceBlockPkt->m_x;
|
||||||
|
int y = pPlaceBlockPkt->m_y;
|
||||||
|
int z = pPlaceBlockPkt->m_z;
|
||||||
|
int tile = pPlaceBlockPkt->m_tile;
|
||||||
|
int face = pPlaceBlockPkt->m_face;
|
||||||
|
|
||||||
|
if (!m_pLevel->mayPlace(tile, x, y, z, true))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Tile* pTile = Tile::tiles[tile];
|
||||||
|
if (!m_pLevel->setTile(x, y, z, tile))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Tile::tiles[tile]->setPlacedOnFace(m_pLevel, x, y, z, face);
|
||||||
|
Tile::tiles[tile]->setPlacedBy(m_pLevel, x, y, z, pPlayer);
|
||||||
|
|
||||||
|
const Tile::SoundType* pSound = pTile->m_pSound;
|
||||||
|
m_pLevel->playSound(float(x) + 0.5f, float(y) + 0.5f, float(z) + 0.5f, "step." + pSound->m_name, 0.5f * (1.0f + pSound->field_18), 0.8f * pSound->field_1C);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, RemoveBlockPacket* pRemoveBlockPkt)
|
||||||
|
{
|
||||||
|
puts_ignorable("RemoveBlockPacket");
|
||||||
|
|
||||||
|
Player* pPlayer = (Player*)m_pLevel->getEntity(pRemoveBlockPkt->m_playerID);
|
||||||
|
if (!pPlayer)
|
||||||
|
{
|
||||||
|
LogMsg("No player with id %d", pRemoveBlockPkt->m_playerID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pPlayer->swing();
|
||||||
|
|
||||||
|
// @BUG: Not buffering the update.
|
||||||
|
if (!areAllChunksLoaded())
|
||||||
|
return;
|
||||||
|
|
||||||
|
int x = pRemoveBlockPkt->m_x;
|
||||||
|
int y = pRemoveBlockPkt->m_y;
|
||||||
|
int z = pRemoveBlockPkt->m_z;
|
||||||
|
|
||||||
|
Tile* pTile = Tile::tiles[m_pLevel->getTile(x, y, z)];
|
||||||
|
int data = m_pLevel->getData(x, y, z);
|
||||||
|
bool setTileResult = m_pLevel->setTile(x, y, z, TILE_AIR);
|
||||||
|
|
||||||
|
if (pTile && setTileResult)
|
||||||
|
{
|
||||||
|
const Tile::SoundType* pSound = pTile->m_pSound;
|
||||||
|
m_pLevel->playSound(float(x) + 0.5f, float(y) + 0.5f, float(z) + 0.5f, "step." + pSound->m_name, 0.5f * (1.0f + pSound->field_18), 0.8f * pSound->field_1C);
|
||||||
|
|
||||||
|
pTile->destroy(m_pLevel, x, y, z, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, UpdateBlockPacket* pkt)
|
||||||
|
{
|
||||||
|
if (!areAllChunksLoaded())
|
||||||
|
{
|
||||||
|
m_bufferedBlockUpdates.push_back(SBufferedBlockUpdate(pkt->m_x, pkt->m_y, pkt->m_z, pkt->m_tile, pkt->m_data));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pLevel->setTileAndData(pkt->m_x, pkt->m_y, pkt->m_z, pkt->m_tile, pkt->m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, ChunkDataPacket* pChunkDataPkt)
|
||||||
|
{
|
||||||
|
if (!m_pLevel)
|
||||||
|
{
|
||||||
|
puts("Level @ handle ChunkDataPacket is 0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LevelChunk* pChunk = m_pLevel->getChunkSource()->create(pChunkDataPkt->m_x, pChunkDataPkt->m_z);
|
||||||
|
if (!pChunk || pChunk->isEmpty())
|
||||||
|
{
|
||||||
|
puts("Failed to find write-able chunk");
|
||||||
|
// @BUG: Not trying again.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int x16 = 16 * pChunkDataPkt->m_x;
|
||||||
|
int z16 = 16 * pChunkDataPkt->m_z;
|
||||||
|
|
||||||
|
bool updated = false;
|
||||||
|
|
||||||
|
int minY = 128, maxY = 0;
|
||||||
|
int minX = 16, minZ = 16;
|
||||||
|
int maxX = 0, maxZ = 0;
|
||||||
|
|
||||||
|
for (int k = 0; k < 256; k++)
|
||||||
|
{
|
||||||
|
uint8_t updMap;
|
||||||
|
pChunkDataPkt->m_data.Read(updMap);
|
||||||
|
|
||||||
|
if (!updMap)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (int j = 0; j < 8; j++)
|
||||||
|
{
|
||||||
|
if ((updMap >> j) & 1)
|
||||||
|
{
|
||||||
|
int yPos = j * 16;
|
||||||
|
TileID tiles[16];
|
||||||
|
uint8_t datas[16 / 2];
|
||||||
|
|
||||||
|
pChunkDataPkt->m_data.Read((char*)tiles, 16 * sizeof(TileID));
|
||||||
|
pChunkDataPkt->m_data.Read((char*)datas, 16 / 2);
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
m_pLevel->setTileNoUpdate(x16 + (k & 0xF), yPos + i, z16 + (k >> 4), tiles[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int idx = ((k & 0xF) << 11) | ((k >> 4) << 7) + yPos;
|
||||||
|
memcpy(&pChunk->m_tileData[idx >> 1], datas, sizeof datas);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ymin = 16 * (1 << j);
|
||||||
|
if (minY >= ymin)
|
||||||
|
minY = ymin;
|
||||||
|
if (maxY < ymin + 15)
|
||||||
|
maxY = ymin + 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minX >= (k & 0xF))
|
||||||
|
minX = k & 0xF;
|
||||||
|
if (minZ >= (k >> 4))
|
||||||
|
minZ = k >> 4;
|
||||||
|
if (maxX <= (k & 0xF))
|
||||||
|
maxX = k & 0xF;
|
||||||
|
if (maxZ <= (k >> 4))
|
||||||
|
maxZ = k >> 4;
|
||||||
|
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updated)
|
||||||
|
m_pLevel->setTilesDirty(minX + x16, minY, minZ, maxX + x16, maxY, maxZ + z16);
|
||||||
|
|
||||||
|
pChunk->m_bUnsaved = true;
|
||||||
|
|
||||||
|
if (areAllChunksLoaded())
|
||||||
|
flushAllBufferedUpdates();
|
||||||
|
else
|
||||||
|
requestNextChunk();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, PlayerEquipmentPacket* pPlayerEquipmentPkt)
|
||||||
|
{
|
||||||
|
Player* pPlayer = (Player*)m_pLevel->getEntity(pPlayerEquipmentPkt->m_playerID);
|
||||||
|
if (!pPlayer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifndef ORIGINAL_CODE
|
||||||
|
if (!Item::items[pPlayerEquipmentPkt->m_itemID])
|
||||||
|
{
|
||||||
|
LogMsg("That item %d doesn't actually exist!", pPlayerEquipmentPkt->m_itemID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (pPlayer->m_guid == m_pServerPeer->GetMyGUID())
|
||||||
|
{
|
||||||
|
puts("Attempted to modify local player's inventory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pPlayer->m_pInventory->setSelectionSlotItemId(0, pPlayerEquipmentPkt->m_itemID);
|
||||||
|
pPlayer->m_pInventory->selectSlot(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClientSideNetworkHandler::areAllChunksLoaded()
|
||||||
|
{
|
||||||
|
return m_chunksRequested > 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientSideNetworkHandler::requestNextChunk()
|
||||||
|
{
|
||||||
|
if (areAllChunksLoaded())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// @BUG: The return value of areAllChunksLoaded() is actually true even before the
|
||||||
|
// 256th chunk is loaded.
|
||||||
|
|
||||||
|
m_pRakNetInstance->send(new RequestChunkPacket(m_chunksRequested % 16, m_chunksRequested / 16));
|
||||||
|
m_chunksRequested++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientSideNetworkHandler::flushAllBufferedUpdates()
|
||||||
|
{
|
||||||
|
for (const SBufferedBlockUpdate& u : m_bufferedBlockUpdates)
|
||||||
|
{
|
||||||
|
m_pLevel->setTileAndData(u.x, u.y, u.z, u.tile, u.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user