1
0

Merge branch 'master' into ChunkLoader

This commit is contained in:
Howaner 2014-10-06 17:38:42 +02:00
commit a59f2d15fb
37 changed files with 1105 additions and 691 deletions

View File

@ -30,5 +30,6 @@ xoft
Yeeeeezus (Donated AlchemistVillage prefabs)
Howaner
Masy98
WebFreak001
Please add yourself to this list if you contribute to MCServer.

View File

@ -529,6 +529,7 @@ end
GetLocale = { Params = "", Return = "Locale", Notes = "Returns the locale string that the client sends as part of the protocol handshake. Can be used to provide localized strings." },
GetPing = { Params = "", Return = "number", Notes = "Returns the ping time, in ms" },
GetPlayer = { Params = "", Return = "{{cPlayer|cPlayer}}", Notes = "Returns the player object connected to this client. Note that this may be nil, for example if the player object is not yet spawned." },
GetProtocolVersion = { Params = "", Return = "number", Notes = "Returns the protocol version number of the protocol that the client is talking. Returns zero if the protocol version is not (yet) known." },
GetUniqueID = { Params = "", Return = "number", Notes = "Returns the UniqueID of the client used to identify the client in the server" },
GetUUID = { Params = "", Return = "string", Notes = "Returns the authentication-based UUID of the client. This UUID should be used to identify the player when persisting any player-related data. Returns a 32-char UUID (no dashes)" },
GetUsername = { Params = "", Return = "string", Notes = "Returns the username that the client has provided" },
@ -785,7 +786,9 @@ end</pre>
AddSpeedX = { Params = "AddX", Return = "", Notes = "Adds the specified amount of speed in the X axis direction." },
AddSpeedY = { Params = "AddY", Return = "", Notes = "Adds the specified amount of speed in the Y axis direction." },
AddSpeedZ = { Params = "AddZ", Return = "", Notes = "Adds the specified amount of speed in the Z axis direction." },
ArmorCoversAgainst = { Params = "{{cEntity|AttackerEntity}}, DamageType, RawDamage", Return = "number", Notes = "Returns the points out of a_RawDamage that the currently equipped armor would cover." },
Destroy = { Params = "", Return = "", Notes = "Schedules the entity to be destroyed" },
GetAirLevel = { Params = "", Return = "number", Notes = "Returns the air level (number of ticks of air left). Note, this function is only updated with mobs or players." },
GetArmorCoverAgainst = { Params = "AttackerEntity, DamageType, RawDamage", Return = "number", Notes = "Returns the number of hitpoints out of RawDamage that the currently equipped armor would cover. See {{TakeDamageInfo}} for more information on attack damage." },
GetChunkX = { Params = "", Return = "number", Notes = "Returns the X-coord of the chunk in which the entity is placed" },
GetChunkZ = { Params = "", Return = "number", Notes = "Returns the Z-coord of the chunk in which the entity is placed" },
@ -801,6 +804,7 @@ end</pre>
GetHeadYaw = { Params = "", Return = "number", Notes = "Returns the pitch of the entity's head (FIXME: Rename to GetHeadPitch() )." },
GetHealth = { Params = "", Return = "number", Notes = "Returns the current health of the entity." },
GetHeight = { Params = "", Return = "number", Notes = "Returns the height (Y size) of the entity" },
GetInvulnerableTicks = { Params = "", Return = "number", Notes = "Returns the number of ticks that this entity will be invulnerable for. This is used for after-hit recovery - the entities are invulnerable for half a second after being hit." },
GetKnockbackAmountAgainst = { Params = "ReceiverEntity", Return = "number", Notes = "Returns the amount of knockback that the currently equipped items would cause when attacking the ReceiverEntity." },
GetLookVector = { Params = "", Return = "{{Vector3f}}", Notes = "Returns the vector that defines the direction in which the entity is looking" },
GetMass = { Params = "", Return = "number", Notes = "Returns the mass of the entity. Currently unused." },
@ -818,23 +822,29 @@ end</pre>
GetSpeedX = { Params = "", Return = "number", Notes = "Returns the X-part of the speed vector" },
GetSpeedY = { Params = "", Return = "number", Notes = "Returns the Y-part of the speed vector" },
GetSpeedZ = { Params = "", Return = "number", Notes = "Returns the Z-part of the speed vector" },
GetTicksAlive = { Params = "", Return = "number", Notes = "Returns the number of ticks that this entity has been alive for." },
GetUniqueID = { Params = "", Return = "number", Notes = "Returns the ID that uniquely identifies the entity within the running server. Note that this ID is not persisted to the data files." },
GetWidth = { Params = "", Return = "number", Notes = "Returns the width (X and Z size) of the entity." },
GetWorld = { Params = "", Return = "{{cWorld}}", Notes = "Returns the world where the entity resides" },
GetYaw = { Params = "", Return = "number", Notes = "Returns the yaw (direction) of the entity. Measured in degrees, values range from -180 to +180. 0 means ZP, 90 means XM, -180 means ZM, -90 means XP." },
HandleSpeedFromAttachee = { Params = "ForwardAmount, SidewaysAmount", Return = "", Notes = "Updates the entity's speed based on the attachee exerting the specified force forward and sideways. Used for entities being driven by other entities attached to them - usually players driving minecarts and boats." },
Heal = { Params = "Hitpoints", Return = "", Notes = "Heals the specified number of hitpoints. Hitpoints is expected to be a positive number." },
IsA = { Params = "ClassName", Return = "bool", Notes = "Returns true if the entity class is a descendant of the specified class name, or the specified class itself" },
IsBoat = { Params = "", Return = "bool", Notes = "Returns true if the entity is a {{cBoat|boat}}." },
IsCrouched = { Params = "", Return = "bool", Notes = "Returns true if the entity is crouched. Always false for entities that don't support crouching." },
IsDestroyed = { Params = "", Return = "bool", Notes = "Returns true if the entity has been destroyed and is awaiting removal from the internal structures." },
IsEnderCrystal = { Params = "", Return = "bool", Notes = "Returns true if the entity is an ender crystal." },
IsExpOrb = { Params = "", Return = "bool", Notes = "Returns true if the entity represents an experience orb" },
IsFallingBlock = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cFallingBlock}} entity." },
IsFireproof = { Params = "", Return = "bool", Notes = "Returns true if the entity takes no damage from being on fire." },
IsFloater = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a fishing rod floater" },
IsInvisible = { Params = "", Return = "bool", Notes = "Returns true if the entity is invisible" },
IsItemFrame = { Params = "", Return = "bool", Notes = "Returns true if the entity is an item frame." },
IsMinecart = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cMinecart|minecart}}" },
IsMob = { Params = "", Return = "bool", Notes = "Returns true if the entity represents any {{cMonster|mob}}." },
IsOnFire = { Params = "", Return = "bool", Notes = "Returns true if the entity is on fire" },
IsPainting = { Params = "", Return = "bool", Notes = "Returns if this entity is a painting." },
IsPawn = { Params = "", Return = "bool", Notes = "Returns true if the entity is a {{cPawn}} descendant." },
IsPickup = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cPickup|pickup}}." },
IsPlayer = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cPlayer|player}}" },
IsProjectile = { Params = "", Return = "bool", Notes = "Returns true if the entity is a {{cProjectileEntity}} descendant." },
@ -844,12 +854,19 @@ end</pre>
IsSubmerged = { Params = "", Return = "bool", Notes = "Returns true if the mob or player is submerged in water (head is in a water block). Note, this function is only updated with mobs or players." },
IsSwimming = { Params = "", Return = "bool", Notes = "Returns true if the mob or player is swimming in water (feet are in a water block). Note, this function is only updated with mobs or players." },
IsTNT = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cTNTEntity|TNT entity}}" },
Killed = { Params = "{{cEntity|Victim}}", Return = "", Notes = "This entity has killed another entity (the Victim). For players, adds the scoreboard statistics about the kill." },
KilledBy = { Notes = "FIXME: Remove this from API" },
GetAirLevel = { Params = "", Return = "number", Notes = "Returns the air level (number of ticks of air left). Note, this function is only updated with mobs or players." },
MoveToWorld =
{
{ Params = "{{cWorld|World}}, [ShouldSendRespawn]", Return = "bool", Notes = "Removes the entity from this world and starts moving it to the specified world. Note that to avoid deadlocks, the move is asynchronous - the entity is moved into a queue and will be moved from that queue into the destination world at some (unpredictable) time in the future. ShouldSendRespawn is used only for players, it specifies whether the player should be sent a Repawn packet upon leaving the world (The client handles respawns only between different dimensions)." },
{ Params = "WorldName, [ShouldSendRespawn]", Return = "bool", Notes = "Removes the entity from this world and starts moving it to the specified world. Note that to avoid deadlocks, the move is asynchronous - the entity is moved into a queue and will be moved from that queue into the destination world at some (unpredictable) time in the future. ShouldSendRespawn is used only for players, it specifies whether the player should be sent a Repawn packet upon leaving the world (The client handles respawns only between different dimensions)." },
},
SetGravity = { Params = "Gravity", Return = "", Notes = "Sets the number that is used as the gravity for physics simulation. 1G (9.78) by default." },
SetHeadYaw = { Params = "HeadPitch", Return = "", Notes = "Sets the head pitch (FIXME: Rename to SetHeadPitch() )." },
SetHealth = { Params = "Hitpoints", Return = "", Notes = "Sets the entity's health to the specified amount of hitpoints. Doesn't broadcast any hurt animation. Doesn't kill the entity if health drops below zero. Use the TakeDamage() function instead for taking damage." },
SetHeight = { Params = "", Return = "", Notes = "FIXME: Remove this from API" },
SetInvulnerableTicks = { Params = "NumTicks", Return = "", Notes = "Sets the amount of ticks for which the entity will not receive any damage from other entities." },
SetIsFireproof = { Params = "IsFireproof", Return = "", Notes = "Sets whether the entity receives damage from being on fire." },
SetMass = { Params = "Mass", Return = "", Notes = "Sets the mass of the entity. Currently unused." },
SetMaxHealth = { Params = "MaxHitpoints", Return = "", Notes = "Sets the maximum hitpoints of the entity. If current health is above MaxHitpoints, it is capped to MaxHitpoints." },
SetPitch = { Params = "number", Return = "", Notes = "Sets the pitch (nose-down rotation) of the entity" },
@ -864,7 +881,7 @@ end</pre>
SetPosZ = { Params = "number", Return = "", Notes = "Sets the Z-coord of the entity's pivot" },
SetRoll = { Params = "number", Return = "", Notes = "Sets the roll (sideways rotation) of the entity. Currently unused." },
SetRot = { Params = "{{Vector3f|Rotation}}", Return = "", Notes = "Sets the entire rotation vector (Yaw, Pitch, Roll)" },
SetYawFromSpeed = { Params = "", Return = "", Notes = "Sets the entity's yaw to match its current speed (entity looking forwards as it moves). (FIXME: Rename to SetYawFromSpeed)" },
SetYawFromSpeed = { Params = "", Return = "", Notes = "Sets the entity's yaw to match its current speed (entity looking forwards as it moves)." },
SetSpeed =
{
{ Params = "SpeedX, SpeedY, SpeedZ", Return = "", Notes = "Sets the current speed of the entity" },
@ -890,18 +907,20 @@ end</pre>
Constants =
{
etBoat = { Notes = "The entity is a {{cBoat}}" },
etEnderCrystal = { Notes = "" },
etEntity = { Notes = "No further specialization available" },
etExpOrb = { Notes = "The entity is a {{cExpOrb}}" },
etFallingBlock = { Notes = "The entity is a {{cFallingBlock}}" },
etFloater = { Notes = "The entity is a fishing rod floater" },
etItemFrame = { Notes = "" },
etMinecart = { Notes = "The entity is a {{cMinecart}} descendant" },
etMob = { Notes = "The entity is a {{cMonster}} descendant" },
etMonster = { Notes = "The entity is a {{cMonster}} descendant" },
etMinecart = { Notes = "The entity is a {{cMinecart}} descendant" },
etPlayer = { Notes = "The entity is a {{cPlayer}}" },
etPainting = { Notes = "The entity is a {{cPainting}}" },
etPickup = { Notes = "The entity is a {{cPickup}}" },
etPlayer = { Notes = "The entity is a {{cPlayer}}" },
etProjectile = { Notes = "The entity is a {{cProjectileEntity}} descendant" },
etTNT = { Notes = "The entity is a {{cTNTEntity}}" },
etPainting = { Notes = "The entity is a {{cPainting}}" },
},
ConstantGroups =
{

View File

@ -34,9 +34,9 @@ function OnServerPing(ClientHandle, ServerDescription, OnlinePlayers, MaxPlayers
MaxPlayers = 0
-- Change favicon
if (cFile:IsFile("my-favicon.png")) then
if cFile:IsFile("my-favicon.png") then
local FaviconData = cFile:ReadWholeFile("my-favicon.png")
if (FaviconData != "") then
if (FaviconData ~= "") and (FaviconData ~= nil) then
Favicon = Base64Encode(FaviconData)
end
end

@ -1 +1 @@
Subproject commit 3a0e0597b7a24c44bf87ec90beb9be48d0b99709
Subproject commit f8c2531fbef9bfd0b6f024d4d3319384a70a0831

View File

@ -1,326 +1,353 @@
/* reset CSS */
body, html
{
font-family: "Open Sans", Tahoma, sans-serif;
padding: 0;
margin: 0;
font-weight: 400;
background-color: #fbe9e7;
color: rgba(0, 0, 0, 0.87);
}
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
.light { font-weight: 300; }
.bold { font-weight: 600; }
#wrapper
{
background-color: #ff5722;
margin: 40px auto;
width: 99%;
max-width: 1200px;
box-sizing: border-box;
-moz-box-sizing: border-box;
box-shadow: 0px 4px 5px rgba(0, 0, 0, 0.15);
color: rgba(0, 0, 0, 0.87);
}
.title
{
font-size: 30pt;
padding: 10px 40px;
text-decoration: none;
color: white;
text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3);
display: block;
}
#sidebar
{
float: left;
width: 20%;
}
.sideNav
{
list-style: none;
background-color: #fafafa;
margin: 20px 0;
padding: 5px 0;
width: 100%;
box-shadow: 1px 0px 10px rgba(0, 0, 0, 0.2);
}
.sideNav li
{
padding: 10px;
color: rgba(0, 0, 0, 0.54);
}
.sideNav li.link
{
padding-left: 30px;
}
.sideNav li.link a
{
text-decoration: none;
color: rgba(0, 0, 0, 0.87);
}
#container
{
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-size: 100%;
vertical-align: baseline;
background: transparent;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
overflow: hidden;
background-color: #f5f5f5;
}
/* remember to define focus styles! */
:focus {
outline: 0;
#main
{
float: right;
width: 80%;
padding: 0 15px 20px 15px;
box-sizing: border-box;
-moz-box-sizing: border-box;
}
/* remove textarea resize at Safari */
textarea {
resize: none;
.clear
{
clear: both;
}
/* remember to highlight inserts somehow! */
ins {
text-decoration: none;
}
del {
text-decoration: line-through;
}
/* tables still need 'cellspacing="0"' in the markup */
table {
table
{
width: 100%;
border-collapse: collapse;
border-spacing: 0;
}
table td
{
padding: 5px;
}
/*
Origional from http://www.perspectived.com/
Modified by Ben Phelps
Made for FakeTruth - MCServer
*/
/* Basic ---------------------------------------- */
.clear { clear: both; }
body {
background: white;
font-family: Arial, Helvetica, sans-serif;
font-size: 12px;
color: #646464;
table th
{
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
padding: 5px;
text-align: center;
}
#wrapper {
text-align: left;
width: 930px;
margin: 0 auto;
table tr:nth-child(odd)
{
background-color: rgba(0, 0, 0, 0.015);
}
/* Logo ---------------------------------------- */
h1 {
margin: 15px 0 10px 5px;
width: 180px;
height: 36px;
background: url(logo.png) no-repeat left top;
p
{
margin: 8px 0;
padding: 8px 3px;
}
h1 a {
a
{
text-decoration: none;
color: #0277bd;
-webkit-transition: color 0.1s linear;
-moz-transition: color 0.1s linear;
transition: color 0.1s linear;
}
a:hover
{
color: #01579b;
}
.welcome-msg
{
color: rgba(0, 0, 0, 0.54);
}
.username
{
text-transform: capitalize;
color: rgba(0, 0, 0, 0.87);
}
a:hover
{
color: black;
}
input, select
{
padding: 8px;
}
form
{
padding: 4px;
}
.info input[type="submit"], .info button, .info input[type="button"],
.warn input[type="submit"], .warn button, .warn input[type="button"],
.err input[type="submit"], .err button, .err input[type="button"]
{
float: right;
}
.err
{
color: white;
display: block;
width: 225px;
height: 28px;
background-color: #e51c23 !important;
padding: 15px;
line-height: 30px;
min-height: 30px;
}
h1 span { display: none; }
a {
color: #646464;
.err:before
{
content: "ERROR: ";
}
/* Container ---------------------------------------- */
#containerHolder {
background: #eee;
padding: 5px;
.warn
{
color: white;
display: block;
background-color: #ff5722 !important;
padding: 15px;
line-height: 30px;
min-height: 30px;
}
#container {
background: #fff url(background.gif) repeat-y left top;
border: 1px solid #ddd;
width: 918px;
.warn:before
{
content: "WARNING: ";
}
#connectHolder {
background: #eee;
padding: 5px;
margin-bottom:8px;
.info
{
color: white;
display: block;
background-color: #5677fc !important;
padding: 15px;
line-height: 30px;
min-height: 30px;
}
#connect {
border: 1px solid #ddd;
background-color: #fff;
padding:5px;
width: 908px;
.info:before
{
content: "INFORMATION: ";
}
.pics {
height: 375px;
width: 600px;
}
.pics img {
padding: 5px;
border: 1px solid #ddd;
background-color: #eee;
width: 600px;
height: 375px;
margin-left: 15px;
}
/* Login -------------------------------------- */
#loginLogo {
margin: 0 auto;
margin-top:100px;
width: 180px;
height: 36px;
background-image: url(logo.png);
}
#loginHolder {
background: #eee;
padding: 5px;
width: 310px;
margin: 0 auto;
height: 90px;
margin-top:20px;
}
#login {
padding:10px;
width: 288px;
height: 68px;
border: 1px solid #ddd;
background:#fff;
text-align: left;
}
/* Sidebar ---------------------------------------- */
#sidebar {
width: 179px;
#footer .fleft
{
float: left;
}
#sidebar .sideNav { width: 179px; }
#sidebar .sideNav li { border-bottom: 1px solid #ddd; width: 179px; }
#sidebar .sideNav li a {
display: block;
color: #646464;
background: #f6f6f6;
text-decoration: none;
height: 29px;
line-height: 29px;
padding: 0 19px;
width: 141px;
}
#sidebar .sideNav li a:hover { background: #fdfcf6; }
#sidebar .sideNav li a.active, #sidebar .sideNav li a.active:hover {
background: #f0f7fa;
color: #c66653;
}
/* Breadcrumb ---------------------------------------- */
h2 {
width: 718px;
#footer .fright
{
float: right;
color: #646464;
font-size: 16px;
line-height: 16px;
font-weight: bold;
margin: 20px 0 0 0;
padding: 0 0 10px 0;
border-bottom: 1px solid #ddd;
}
h2 a {
color: #646464;
text-decoration: none;
}
h2 a.active { color: #c66653; }
h2 a:hover { text-decoration: underline; }
/* Content ---------------------------------------- */
#main {
width: 700px;
float: right;
padding: 0 19px 0 0;
}
#main p {
padding: 10px;
}
h3 {
font-size: 14px;
line-height: 14px;
font-weight: bold;
color: #5494af;
padding: 0 0 0 10px;
margin: 20px 0 10px;
}
h4 {
padding: 0 0 0 10px;
margin: 20px 0 10px;
}
#main ul {
padding: 0 0 0 10px;
list-style-type: circle;
list-style-position: inside;
}
#main table {
border-top: 1px solid #ddd;
width: 700px;
}
#main table tr th {
text-align: left;
background: #f6f6f6;
padding: 0px 20px;
height: 20px;
line-height: 20px;
border-bottom: 1px solid #ddd;
}
#main table tr td {
background: #f6f6f6;
padding: 0px 20px;
height: 29px;
line-height: 29px;
border-bottom: 1px solid #ddd;
}
#main table tr.odd td {
background: #fbfbfb;
}
#main table tr:hover td { background: #fdfcf6; }
#main table .action {
text-align: right;
padding: 0 20px 0 10px;
}
#main table tr .action a { margin: 0 0 0 10px; text-decoration: none; color: #9b9b9b; }
#main table tr:hover .action .edit { color: #c5a059; }
#main table tr:hover .action .delete { color: #a02b2b; }
#main table tr:hover .action .view { color: #55a34a; }
#main table tr:hover .action a:hover { text-decoration: underline; }
fieldset {
border: 1px solid #ddd;
padding: 19px;
margin: 0 0 20px 0;
background: #fbfbfb;
#footer
{
margin: 0;
padding: 10px;
font-size: 9pt;
color: rgba(255, 255, 255, 0.8);
box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.2) inset;
}
form p { margin: 0 0 14px 0; float: left; width: 100%; }
#footer a
{
text-transform: none;
color: white;
}
label {
display: block;
input[type="submit"], button, input[type="button"]
{
background-color: #ffc107;
padding: 8px 15px 8px 15px;
margin: 0 2px;
display: inline-block;
text-align: center;
color: black;
box-shadow: 0px 2px 3px rgba(0,0,0,0.2);
border: none;
outline: none;
cursor: pointer;
}
input[type="submit"]:hover, button:hover, input[type="button"]:hover
{
background-color: #ffca28;
}
input[type="submit"]:active, button:active, input[type="button"]:active
{
background-color: #ffd54f;
-webkit-transform: translateY(1px);
-moz-transform: translateY(1px);
transform: translateY(1px);
}
hr
{
border: none;
height: 1px;
background-color: rgba(0, 0, 0, 0.12);
}
h4
{
padding-bottom: 10px;
margin-bottom: 12px;
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
}
/**** PAGE SPECIFIC CSS ****/
/* remove the * for disabling: */
.page-core-server-settings table td
{
text-align: center;
width: 25%;
}
.page-core-server-settings.no-param table td:nth-child(1) a,
.page-core-server-settings.param-tab-general table td:nth-child(1) a
{
font-weight: 600;
color: rgba(0, 0, 0, 0.87);
}
.page-core-server-settings.param-tab-monsters table td:nth-child(2) a
{
font-weight: 600;
color: rgba(0, 0, 0, 0.87);
}
.page-core-server-settings.param-tab-worlds table td:nth-child(3) a
{
font-weight: 600;
color: rgba(0, 0, 0, 0.87);
}
.page-core-server-settings.param-tab-world table td:nth-child(4) a
{
font-weight: 600;
color: rgba(0, 0, 0, 0.87);
}
.page-core-permissions form table tr,
.page-core-permissions form table td,
.page-core-permissions form table th
{
border: none;
background-color: transparent;
}
.page-core-permissions form table tr:nth-child(1) th
{
width: 35%;
}
.page-core-permissions form table tr:nth-child(1) td
{
width: 65%;
}
.page-core-permissions form table td input
{
width: 100%;
margin: 0 0 7px 0;
line-height: 12px;
box-sizing: border-box;
-moz-box-sizing: border-box;
margin: 0;
}
/* Footer ---------------------------------------- */
#footer {
margin: 10px 0 30px 0;
font-size: 11px;
line-height: 11px;
color: #9B9B9B;
padding: 0 0 0 5px;
#ChatDiv
{
margin-bottom: 10px;
}
#footer a { color: #9B9B9B; }
#ChatMessage
{
width: 100%;
box-sizing: border-box;
-moz-box-sizing: border-box;
}
#footer a:hover { text-decoration: none; }
/**/

View File

@ -70,25 +70,33 @@ function ShowPage(WebAdmin, TemplateRequest)
PageContent, SubTitle = GetDefaultPage()
end
local reqParamsClass = ""
for key,value in pairs(TemplateRequest.Request.Params) do
reqParamsClass = reqParamsClass .. " param-" .. string.lower(string.gsub(key, "[^a-zA-Z0-9]+", "-") .. "-" .. string.gsub(value, "[^a-zA-Z0-9]+", "-"))
end
if (string.gsub(reqParamsClass, "%s", "") == "") then
reqParamsClass = " no-param"
end
Output([[
<!DOCTYPE html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="icon" href="/favicon.ico">
<title>]] .. Title .. [[</title>
<link rel="stylesheet" type="text/css" media="screen" href="/style.css">
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,600,300' rel='stylesheet' type='text/css'>
<link rel="stylesheet" type="text/css" href="/style.css">
</head>
<body>
<div id="wrapper">
<!-- h1 tag stays for the logo, you can use the a tag for linking the index page -->
<h1>
<a href="]] .. BaseURL .. [["><span>MCServer</span></a>
</h1>
<div id="containerHolder">
<div id="container">
<div id="sidebar">
<ul class="sideNav">
<div id="wrapper">
<div id="containerHolder">
<a href="./" class="title light">MCServer</a>
<div id="container">
<div id="sidebar">
<ul class="sideNav">
<li class='link'><a href=']] .. BaseURL .. [['>Home</a></li>
]])
@ -100,7 +108,7 @@ function ShowPage(WebAdmin, TemplateRequest)
Output("<li>"..PluginWebTitle.."</li>\n");
for webname,prettyname in pairs(TabNames) do
Output("<li><a href='" .. BaseURL .. PluginWebTitle .. "/" .. webname .. "'>" .. prettyname .. "</a></li>\n")
Output("<li class='link'><a href='" .. BaseURL .. PluginWebTitle .. "/" .. webname .. "'>" .. prettyname .. "</a></li>\n")
end
end
end
@ -108,30 +116,23 @@ function ShowPage(WebAdmin, TemplateRequest)
Output([[
</ul>
<!-- // .sideNav -->
</div>
<!-- // #sidebar -->
<!-- h2 stays for breadcrumbs -->
<h2>Welcome ]] .. TemplateRequest.Request.Username .. [[</h2>
<div id="main">
<h3>]] .. SubTitle .. [[</h3>
]] .. PageContent .. [[
</div>
<!-- // #main -->
<div class="clear"></div>
</div>
<!-- // #container -->
</div>
<!-- // #containerHolder -->
<p id="footer">MCServer is using: ]] .. MemoryUsageKiB / 1024 .. [[ MiB of memory; Current chunk count: ]] .. NumChunks .. [[ </p>
<div id="main" class="page-]] .. string.lower(PluginPage.PluginName .. "-" .. string.gsub(PluginPage.TabName, "[^a-zA-Z0-9]+", "-")) .. reqParamsClass .. [[">
<h2 class="welcome-msg">Welcome <span class="username">]] .. TemplateRequest.Request.Username .. [[</span></h2>
<hr/>
<h3>]] .. SubTitle .. [[</h3>
]] .. PageContent .. [[</div>
<div class="clear"></div>
</div>
</div>
<!-- // #wrapper -->
<div id="footer"><div class="fleft">running MCServer using <span class="bold">]] .. MemoryUsageKiB / 1024 .. [[MB</span> of memory; <span class="bold">]] .. NumChunks .. [[</span> chunks</div><div class="fright">design by <a href="//www.github.com/WebFreak001">WebFreak001</a></div><div class="clear"></div></div>
</div>
</body>
</html>
]])
]])
return table.concat(SiteContent)
end

View File

@ -0,0 +1,137 @@
-- Use a table for fast concatenation of strings
local SiteContent = {}
function Output(String)
table.insert(SiteContent, String)
end
function GetTableSize(Table)
local Size = 0
for key,value in pairs(Table) do
Size = Size + 1
end
return Size
end
function GetDefaultPage()
local PM = cRoot:Get():GetPluginManager()
local SubTitle = "Current Game"
local Content = ""
Content = Content .. "<h4>Server Name:</h4>"
Content = Content .. "<p>" .. cRoot:Get():GetServer():GetServerID() .. "</p>"
Content = Content .. "<h4>Plugins:</h4><ul>"
local AllPlugins = PM:GetAllPlugins()
for key,value in pairs(AllPlugins) do
if( value ~= nil and value ~= false ) then
Content = Content .. "<li>" .. key .. " V." .. value:GetVersion() .. "</li>"
end
end
Content = Content .. "</ul>"
Content = Content .. "<h4>Players:</h4><ul>"
local AddPlayerToTable = function( Player )
Content = Content .. "<li>" .. Player:GetName() .. "</li>"
end
cRoot:Get():ForEachPlayer( AddPlayerToTable )
Content = Content .. "</ul><br>";
return Content, SubTitle
end
function ShowPage(WebAdmin, TemplateRequest)
SiteContent = {}
local BaseURL = WebAdmin:GetBaseURL(TemplateRequest.Request.Path)
local Title = "MCServer WebAdmin"
local MemoryUsageKiB = cRoot:GetPhysicalRAMUsage()
local NumChunks = cRoot:Get():GetTotalChunkCount()
local PluginPage = WebAdmin:GetPage(TemplateRequest.Request)
local PageContent = PluginPage.Content
local SubTitle = PluginPage.PluginName
if (PluginPage.TabName ~= "") then
SubTitle = PluginPage.PluginName .. " - " .. PluginPage.TabName
end
if (PageContent == "") then
PageContent, SubTitle = GetDefaultPage()
end
Output([[
<!DOCTYPE html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="icon" href="/favicon.ico">
<title>]] .. Title .. [[</title>
<link rel="stylesheet" type="text/css" media="screen" href="/style.css">
</head>
<body>
<div id="wrapper">
<!-- h1 tag stays for the logo, you can use the a tag for linking the index page -->
<h1>
<a href="]] .. BaseURL .. [["><span>MCServer</span></a>
</h1>
<div id="containerHolder">
<div id="container">
<div id="sidebar">
<ul class="sideNav">
]])
local AllPlugins = WebAdmin:GetPlugins()
for key,value in pairs(AllPlugins) do
local PluginWebTitle = value:GetWebTitle()
local TabNames = value:GetTabNames()
if (GetTableSize(TabNames) > 0) then
Output("<li>"..PluginWebTitle.."</li>\n");
for webname,prettyname in pairs(TabNames) do
Output("<li><a href='" .. BaseURL .. PluginWebTitle .. "/" .. webname .. "'>" .. prettyname .. "</a></li>\n")
end
end
end
Output([[
</ul>
<!-- // .sideNav -->
</div>
<!-- // #sidebar -->
<!-- h2 stays for breadcrumbs -->
<h2>Welcome ]] .. TemplateRequest.Request.Username .. [[</h2>
<div id="main">
<h3>]] .. SubTitle .. [[</h3>
]] .. PageContent .. [[
</div>
<!-- // #main -->
<div class="clear"></div>
</div>
<!-- // #container -->
</div>
<!-- // #containerHolder -->
<p id="footer">MCServer is using: ]] .. MemoryUsageKiB / 1024 .. [[ MiB of memory; Current chunk count: ]] .. NumChunks .. [[ </p>
</div>
<!-- // #wrapper -->
</body>
</html>
]])
return table.concat(SiteContent)
end

View File

@ -33,7 +33,7 @@ For other stuff, including plugins and discussion, check the [forums](http://for
Earn bitcoins for commits or donate to reward the MCServer developers: [![tip for next commit](http://tip4commit.com/projects/74.svg)](http://tip4commit.com/projects/74)
Support Us on Gratipay: [![Support via Gittip](http://img.shields.io/gittip/mcs_team.svg)](https://www.gittip.com/mcs_team)
Support Us on Gratipay: [![Support via Gratipay](http://img.shields.io/gittip/cuberite_team.svg)](https://www.gratipay.com/cuberite_team)
Travis CI: [![Build Status](http://img.shields.io/travis/mc-server/MCServer.svg)](https://travis-ci.org/mc-server/MCServer)

View File

@ -42,8 +42,9 @@ BiomeView::BiomeView(QWidget * parent) :
// Add a chunk-update callback mechanism:
connect(&m_Cache, SIGNAL(chunkAvailable(int, int)), this, SLOT(chunkAvailable(int, int)));
// Allow keyboard interaction:
// Allow mouse and keyboard interaction:
setFocusPolicy(Qt::StrongFocus);
setMouseTracking(true);
}
@ -80,6 +81,27 @@ void BiomeView::setChunkSource(std::shared_ptr<ChunkSource> a_ChunkSource)
void BiomeView::setPosition(int a_BlockX, int a_BlockZ)
{
m_X = a_BlockX;
m_Z = a_BlockZ;
redraw();
}
void BiomeView::setZoomLevel(double a_ZoomLevel)
{
m_Zoom = a_ZoomLevel;
redraw();
}
void BiomeView::redraw()
{
if (!hasData())
@ -275,6 +297,12 @@ void BiomeView::mousePressEvent(QMouseEvent * a_Event)
void BiomeView::mouseMoveEvent(QMouseEvent * a_Event)
{
// If there's no data displayed, bail out:
if (!hasData())
{
return;
}
if (m_IsMouseDragging)
{
// The user is dragging the mouse, move the view around:
@ -286,7 +314,15 @@ void BiomeView::mouseMoveEvent(QMouseEvent * a_Event)
return;
}
// TODO: Update the status bar info for the biome currently pointed at
// Update the status bar info text:
int blockX = floor((a_Event->x() - width() / 2) / m_Zoom + m_X);
int blockZ = floor((a_Event->y() - height() / 2) / m_Zoom + m_Z);
int chunkX, chunkZ;
int relX = blockX, relY, relZ = blockZ;
cChunkDef::AbsoluteToRelative(relX, relY, relZ, chunkX, chunkZ);
auto chunk = m_Cache.fetch(chunkX, chunkZ);
int biome = (chunk.get() != nullptr) ? chunk->getBiome(relX, relZ) : biInvalidBiome;
emit hoverChanged(blockX, blockZ, biome);
}
@ -307,12 +343,12 @@ void BiomeView::wheelEvent(QWheelEvent * a_Event)
m_MouseWheelDelta += a_Event->delta();
while (m_MouseWheelDelta >= DELTA_STEP)
{
increaseZoom();
emit wheelUp();
m_MouseWheelDelta -= DELTA_STEP;
}
while (m_MouseWheelDelta <= -DELTA_STEP)
{
decreaseZoom();
emit wheelDown();
m_MouseWheelDelta += DELTA_STEP;
}
}
@ -360,14 +396,14 @@ void BiomeView::keyPressEvent(QKeyEvent * a_Event)
case Qt::Key_PageUp:
case Qt::Key_Q:
{
increaseZoom();
emit increaseZoom();
break;
}
case Qt::Key_PageDown:
case Qt::Key_E:
{
decreaseZoom();
emit decreaseZoom();
break;
}
}
@ -376,52 +412,3 @@ void BiomeView::keyPressEvent(QKeyEvent * a_Event)
void BiomeView::decreaseZoom()
{
if (m_Zoom > 1.001)
{
m_Zoom--;
if (m_Zoom < 1.0)
{
// Just crossed the 100%, fixate the 100% threshold:
m_Zoom = 1.0;
}
}
else if (m_Zoom > 0.01)
{
m_Zoom = m_Zoom / 2;
}
redraw();
}
void BiomeView::increaseZoom()
{
if (m_Zoom > 0.99)
{
if (m_Zoom > 20.0)
{
// Zoom too large
return;
}
m_Zoom++;
}
else
{
m_Zoom = m_Zoom * 2;
if (m_Zoom > 1.0)
{
// Just crossed the 100%, fixate the 100% threshold:
m_Zoom = 1.0;
}
}
redraw();
}

View File

@ -25,7 +25,27 @@ public:
The entire view is then invalidated and regenerated. */
void setChunkSource(std::shared_ptr<ChunkSource> a_ChunkSource);
/** Sets the position of the central pixel of the map to the specified point and redraws the view. */
void setPosition(int a_BlockX, int a_BlockZ);
/** Sets the zoom level to the specified value and redraws the view. */
void setZoomLevel(double a_ZoomLevel);
signals:
/** Signalled when the user uses the wheel to scroll upwards. */
void wheelUp();
/** Signalled when the user uses the wheel to scroll downwards. */
void wheelDown();
/** Signalled when the user presses a key to increase zoom. */
void increaseZoom();
/** Signalled when the user presses a key to decrease zoom. */
void decreaseZoom();
/** Emitted when the user moves the mouse, to reflect the current block under the cursor. */
void hoverChanged(int a_BlockX, int a_BlockZ, int a_Biome);
public slots:
/** Redraw the entire widget area. */
@ -86,12 +106,6 @@ protected:
/** Called when the user presses a key. */
virtual void keyPressEvent(QKeyEvent * a_Event) override;
/** Decreases the zoom level and queues a redraw. */
void decreaseZoom();
/** Increases the zoom level and queues a redraw. */
void increaseZoom();
};

View File

@ -10,135 +10,6 @@
/** Map for converting biome values to colors. Initialized from biomeColors[]. */
static uchar biomeToColor[256 * 4];
/** Map for converting biome values to colors. Used to initialize biomeToColor[].*/
static struct
{
EMCSBiome m_Biome;
uchar m_Color[3];
} biomeColors[] =
{
{ biOcean, { 0x00, 0x00, 0x70 }, },
{ biPlains, { 0x8d, 0xb3, 0x60 }, },
{ biDesert, { 0xfa, 0x94, 0x18 }, },
{ biExtremeHills, { 0x60, 0x60, 0x60 }, },
{ biForest, { 0x05, 0x66, 0x21 }, },
{ biTaiga, { 0x0b, 0x66, 0x59 }, },
{ biSwampland, { 0x2f, 0xff, 0xda }, },
{ biRiver, { 0x30, 0x30, 0xaf }, },
{ biHell, { 0x7f, 0x00, 0x00 }, },
{ biSky, { 0x00, 0x7f, 0xff }, },
{ biFrozenOcean, { 0xa0, 0xa0, 0xdf }, },
{ biFrozenRiver, { 0xa0, 0xa0, 0xff }, },
{ biIcePlains, { 0xff, 0xff, 0xff }, },
{ biIceMountains, { 0xa0, 0xa0, 0xa0 }, },
{ biMushroomIsland, { 0xff, 0x00, 0xff }, },
{ biMushroomShore, { 0xa0, 0x00, 0xff }, },
{ biBeach, { 0xfa, 0xde, 0x55 }, },
{ biDesertHills, { 0xd2, 0x5f, 0x12 }, },
{ biForestHills, { 0x22, 0x55, 0x1c }, },
{ biTaigaHills, { 0x16, 0x39, 0x33 }, },
{ biExtremeHillsEdge, { 0x7f, 0x8f, 0x7f }, },
{ biJungle, { 0x53, 0x7b, 0x09 }, },
{ biJungleHills, { 0x2c, 0x42, 0x05 }, },
{ biJungleEdge, { 0x62, 0x8b, 0x17 }, },
{ biDeepOcean, { 0x00, 0x00, 0x30 }, },
{ biStoneBeach, { 0xa2, 0xa2, 0x84 }, },
{ biColdBeach, { 0xfa, 0xf0, 0xc0 }, },
{ biBirchForest, { 0x30, 0x74, 0x44 }, },
{ biBirchForestHills, { 0x1f, 0x5f, 0x32 }, },
{ biRoofedForest, { 0x40, 0x51, 0x1a }, },
{ biColdTaiga, { 0x31, 0x55, 0x4a }, },
{ biColdTaigaHills, { 0x59, 0x7d, 0x72 }, },
{ biMegaTaiga, { 0x59, 0x66, 0x51 }, },
{ biMegaTaigaHills, { 0x59, 0x66, 0x59 }, },
{ biExtremeHillsPlus, { 0x50, 0x70, 0x50 }, },
{ biSavanna, { 0xbd, 0xb2, 0x5f }, },
{ biSavannaPlateau, { 0xa7, 0x9d, 0x64 }, },
{ biMesa, { 0xd9, 0x45, 0x15 }, },
{ biMesaPlateauF, { 0xb0, 0x97, 0x65 }, },
{ biMesaPlateau, { 0xca, 0x8c, 0x65 }, },
// M variants:
{ biSunflowerPlains, { 0xb5, 0xdb, 0x88 }, },
{ biDesertM, { 0xff, 0xbc, 0x40 }, },
{ biExtremeHillsM, { 0x88, 0x88, 0x88 }, },
{ biFlowerForest, { 0x2d, 0x8e, 0x49 }, },
{ biTaigaM, { 0x33, 0x8e, 0x81 }, },
{ biSwamplandM, { 0x07, 0xf9, 0xb2 }, },
{ biIcePlainsSpikes, { 0xb4, 0xdc, 0xdc }, },
{ biJungleM, { 0x7b, 0xa3, 0x31 }, },
{ biJungleEdgeM, { 0x62, 0x8b, 0x17 }, },
{ biBirchForestM, { 0x58, 0x9c, 0x6c }, },
{ biBirchForestHillsM, { 0x47, 0x87, 0x5a }, },
{ biRoofedForestM, { 0x68, 0x79, 0x42 }, },
{ biColdTaigaM, { 0x24, 0x3f, 0x36 }, },
{ biMegaSpruceTaiga, { 0x45, 0x4f, 0x3e }, },
{ biMegaSpruceTaigaHills, { 0x45, 0x4f, 0x4e }, },
{ biExtremeHillsPlusM, { 0x78, 0x98, 0x78 }, },
{ biSavannaM, { 0xe5, 0xda, 0x87 }, },
{ biSavannaPlateauM, { 0xa7, 0x9d, 0x74 }, },
{ biMesaBryce, { 0xff, 0x6d, 0x3d }, },
{ biMesaPlateauFM, { 0xd8, 0xbf, 0x8d }, },
{ biMesaPlateauM, { 0xf2, 0xb4, 0x8d }, },
} ;
static class BiomeColorsInitializer
{
public:
BiomeColorsInitializer(void)
{
// Reset all colors to gray:
for (size_t i = 0; i < ARRAYCOUNT(biomeToColor); i++)
{
biomeToColor[i] = 0x7f;
}
// Set known biomes to their colors:
for (size_t i = 0; i < ARRAYCOUNT(biomeColors); i++)
{
uchar * color = &biomeToColor[4 * biomeColors[i].m_Biome];
color[0] = biomeColors[i].m_Color[2];
color[1] = biomeColors[i].m_Color[1];
color[2] = biomeColors[i].m_Color[0];
color[3] = 0xff;
}
}
} biomeColorInitializer;
/** Converts biomes in an array into the chunk image data. */
static void biomesToImage(cChunkDef::BiomeMap & a_Biomes, Chunk::Image & a_Image)
{
// Make sure the two arrays are of the same size, compile-time.
// Note that a_Image is actually 4 items per pixel, so the array is 4 times bigger:
static const char Check1[4 * ARRAYCOUNT(a_Biomes) - ARRAYCOUNT(a_Image) + 1] = {};
static const char Check2[ARRAYCOUNT(a_Image) - 4 * ARRAYCOUNT(a_Biomes) + 1] = {};
// Convert the biomes into color:
for (size_t i = 0; i < ARRAYCOUNT(a_Biomes); i++)
{
a_Image[4 * i + 0] = biomeToColor[4 * a_Biomes[i] + 0];
a_Image[4 * i + 1] = biomeToColor[4 * a_Biomes[i] + 1];
a_Image[4 * i + 2] = biomeToColor[4 * a_Biomes[i] + 2];
a_Image[4 * i + 3] = biomeToColor[4 * a_Biomes[i] + 3];
}
}
////////////////////////////////////////////////////////////////////////////////
// BioGenSource:
@ -160,9 +31,7 @@ void BioGenSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChu
QMutexLocker lock(&m_Mtx);
m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, biomes);
}
Chunk::Image img;
biomesToImage(biomes, img);
a_DestChunk->setImage(img);
a_DestChunk->setBiomes(biomes);
}
@ -331,10 +200,7 @@ void AnvilSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChun
{
biomeMap[i] = (EMCSBiome)GetBEInt(beBiomes + 4 * i);
}
// Render the biomes:
Chunk::Image img;
biomesToImage(biomeMap, img);
a_DestChunk->setImage(img);
a_DestChunk->setBiomes(biomeMap);
return;
}
@ -350,10 +216,7 @@ void AnvilSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChun
{
biomeMap[i] = EMCSBiome(vanillaBiomes[i]);
}
// Render the biomes:
Chunk::Image img;
biomesToImage(biomeMap, img);
a_DestChunk->setImage(img);
a_DestChunk->setBiomes(biomeMap);
}

View File

@ -7,6 +7,7 @@
#include <QFileDialog>
#include <QSettings>
#include <QDirIterator>
#include <QStatusBar>
#include "inifile/iniFile.h"
#include "ChunkSource.h"
#include "src/Generating/BioGen.h"
@ -18,6 +19,15 @@
const double MainWindow::m_ViewZooms[] =
{
0.0625, 0.125, 0.25, 0.5, 1, 2, 4, 8, 16, 24,
};
MainWindow::MainWindow(QWidget * parent) :
QMainWindow(parent),
m_GeneratorSetup(nullptr),
@ -26,6 +36,20 @@ MainWindow::MainWindow(QWidget * parent) :
initMinecraftPath();
m_BiomeView = new BiomeView();
connect(m_BiomeView, SIGNAL(increaseZoom()), this, SLOT(increaseZoom()));
connect(m_BiomeView, SIGNAL(decreaseZoom()), this, SLOT(decreaseZoom()));
connect(m_BiomeView, SIGNAL(wheelUp()), this, SLOT(increaseZoom()));
connect(m_BiomeView, SIGNAL(wheelDown()), this, SLOT(decreaseZoom()));
m_StatusBar = new QStatusBar();
this->setStatusBar(m_StatusBar);
m_StatusBlockX = new QLabel(tr("X"));
m_StatusBlockZ = new QLabel(tr("Z"));
m_StatusBiome = new QLabel(tr("B"));
m_StatusBar->addPermanentWidget(m_StatusBlockX);
m_StatusBar->addPermanentWidget(m_StatusBlockZ);
m_StatusBar->addPermanentWidget(m_StatusBiome);
m_MainLayout = new QHBoxLayout();
m_MainLayout->addWidget(m_BiomeView, 1);
m_MainLayout->setMenuBar(menuBar());
@ -36,6 +60,8 @@ MainWindow::MainWindow(QWidget * parent) :
createActions();
createMenus();
connect(m_BiomeView, SIGNAL(hoverChanged(int, int, int)), this, SLOT(hoverChanged(int, int, int)));
}
@ -129,6 +155,79 @@ void MainWindow::openVanillaWorld()
void MainWindow::centerView()
{
m_BiomeView->setPosition(0, 0);
}
void MainWindow::setViewZoom()
{
// The zoom level is stored in the sender action's data, retrieve it:
QAction * action = qobject_cast<QAction *>(sender());
if (action == nullptr)
{
return;
}
double newZoom = m_ViewZooms[action->data().toInt()];
m_BiomeView->setZoomLevel(newZoom);
action->setChecked(true);
}
void MainWindow::increaseZoom()
{
// If already at max zoom, bail out:
if (m_CurrentZoomLevel >= ARRAYCOUNT(m_ViewZooms) - 1)
{
return;
}
// Increase the zoom level:
m_CurrentZoomLevel += 1;
m_actViewZoom[m_CurrentZoomLevel]->setChecked(true);
m_BiomeView->setZoomLevel(m_ViewZooms[m_CurrentZoomLevel]);
}
void MainWindow::decreaseZoom()
{
// If already at min zoom, bail out:
if (m_CurrentZoomLevel == 0)
{
return;
}
// Decrease the zoom level:
m_CurrentZoomLevel -= 1;
m_actViewZoom[m_CurrentZoomLevel]->setChecked(true);
m_BiomeView->setZoomLevel(m_ViewZooms[m_CurrentZoomLevel]);
}
void MainWindow::hoverChanged(int a_BlockX, int a_BlockZ, int a_Biome)
{
m_StatusBlockX->setText(tr("X: %1").arg(a_BlockX));
m_StatusBlockZ->setText(tr("Z: %1").arg(a_BlockZ));
m_StatusBiome->setText (tr("B: %1 (%2)").arg(BiomeToString(a_Biome).c_str()).arg(a_Biome));
}
void MainWindow::initMinecraftPath()
{
#ifdef Q_OS_MAC
@ -147,6 +246,7 @@ void MainWindow::initMinecraftPath()
void MainWindow::createActions()
{
// Map menu:
createWorldActions();
m_actNewGen = new QAction(tr("&New generator"), this);
@ -173,6 +273,26 @@ void MainWindow::createActions()
m_actExit->setShortcut(tr("Alt+X"));
m_actExit->setStatusTip(tr("Exit %1").arg(QApplication::instance()->applicationName()));
connect(m_actExit, SIGNAL(triggered()), this, SLOT(close()));
// View menu:
m_actViewCenter = new QAction(tr("&Reset to center"), this);
m_actViewCenter->setStatusTip(tr("Scrolls the view back to the map center"));
connect(m_actViewCenter, SIGNAL(triggered()), this, SLOT(centerView()));
QActionGroup * zoomGroup = new QActionGroup(this);
for (int i = 0; i < ARRAYCOUNT(m_ViewZooms); i++)
{
m_actViewZoom[i] = new QAction(tr("&Zoom %1%").arg(std::floor(m_ViewZooms[i] * 100)), this);
m_actViewZoom[i]->setCheckable(true);
if ((int)(m_ViewZooms[i] * 16) == 16)
{
m_actViewZoom[i]->setChecked(true);
m_CurrentZoomLevel = i;
}
m_actViewZoom[i]->setData(QVariant(i));
zoomGroup->addAction(m_actViewZoom[i]);
connect(m_actViewZoom[i], SIGNAL(triggered()), this, SLOT(setViewZoom()));
}
}
@ -220,11 +340,12 @@ void MainWindow::createWorldActions()
void MainWindow::createMenus()
{
// Map menu:
QMenu * file = menuBar()->addMenu(tr("&Map"));
file->addAction(m_actNewGen);
file->addAction(m_actOpenGen);
file->addSeparator();
QMenu * worlds = file->addMenu(tr("Open existing"));
QMenu * worlds = file->addMenu(tr("Open &existing"));
worlds->addActions(m_WorldActions);
if (m_WorldActions.empty())
{
@ -235,6 +356,15 @@ void MainWindow::createMenus()
file->addAction(m_actReload);
file->addSeparator();
file->addAction(m_actExit);
// View menu:
QMenu * view = menuBar()->addMenu(tr("&View"));
view->addAction(m_actViewCenter);
view->addSeparator();
for (size_t i = 0; i < ARRAYCOUNT(m_actViewZoom); i++)
{
view->addAction(m_actViewZoom[i]);
}
}

View File

@ -4,6 +4,7 @@
#include <QList>
#include <QMainWindow>
#include <QHBoxLayout>
#include <QLabel>
#include "BiomeView.h"
@ -39,13 +40,33 @@ private slots:
/** Opens a vanilla world that is specified by the calling action. */
void openVanillaWorld();
/** Moves the view to the map's center. */
void centerView();
/** Sets the zoom level specified in the triggering action. */
void setViewZoom();
/** Sets a zoom level one step larger than current, if allowed. */
void increaseZoom();
/** Sets a zoom level one step smaller than current, if allowed. */
void decreaseZoom();
/** Updates the statusbar for the specified info about the current block under the cursor. */
void hoverChanged(int a_BlockX, int a_BlockZ, int a_Biome);
protected:
/** The zoom levels */
static const double m_ViewZooms[10];
// Actions:
QAction * m_actNewGen;
QAction * m_actOpenGen;
QAction * m_actOpenWorld;
QAction * m_actReload;
QAction * m_actExit;
QAction * m_actViewCenter;
QAction * m_actViewZoom[ARRAYCOUNT(m_ViewZooms)];
/** List of actions that open the specific vanilla world. */
QList<QAction *> m_WorldActions;
@ -62,9 +83,19 @@ protected:
/** The layout for the window. */
QHBoxLayout * m_MainLayout;
/** The status bar that displays the current hover information. */
QStatusBar * m_StatusBar;
QLabel * m_StatusBlockX;
QLabel * m_StatusBlockZ;
QLabel * m_StatusBiome;
/** The separator line between biome view and generator setup. */
QWidget * m_LineSeparator;
/** Index into m_ViewZooms[] for the current zoom level. */
size_t m_CurrentZoomLevel;
/** Initializes the m_MinecraftPath based on the proper MC path */
void initMinecraftPath();

View File

@ -5,6 +5,138 @@
/** Map for converting biome values to colors. Initialized from biomeColors[]. */
static uchar biomeToColor[256 * 4];
/** Map for converting biome values to colors. Used to initialize biomeToColor[].*/
static struct
{
EMCSBiome m_Biome;
uchar m_Color[3];
} biomeColors[] =
{
{ biOcean, { 0x00, 0x00, 0x70 }, },
{ biPlains, { 0x8d, 0xb3, 0x60 }, },
{ biDesert, { 0xfa, 0x94, 0x18 }, },
{ biExtremeHills, { 0x60, 0x60, 0x60 }, },
{ biForest, { 0x05, 0x66, 0x21 }, },
{ biTaiga, { 0x0b, 0x66, 0x59 }, },
{ biSwampland, { 0x2f, 0xff, 0xda }, },
{ biRiver, { 0x30, 0x30, 0xaf }, },
{ biHell, { 0x7f, 0x00, 0x00 }, },
{ biSky, { 0x00, 0x7f, 0xff }, },
{ biFrozenOcean, { 0xa0, 0xa0, 0xdf }, },
{ biFrozenRiver, { 0xa0, 0xa0, 0xff }, },
{ biIcePlains, { 0xff, 0xff, 0xff }, },
{ biIceMountains, { 0xa0, 0xa0, 0xa0 }, },
{ biMushroomIsland, { 0xff, 0x00, 0xff }, },
{ biMushroomShore, { 0xa0, 0x00, 0xff }, },
{ biBeach, { 0xfa, 0xde, 0x55 }, },
{ biDesertHills, { 0xd2, 0x5f, 0x12 }, },
{ biForestHills, { 0x22, 0x55, 0x1c }, },
{ biTaigaHills, { 0x16, 0x39, 0x33 }, },
{ biExtremeHillsEdge, { 0x7f, 0x8f, 0x7f }, },
{ biJungle, { 0x53, 0x7b, 0x09 }, },
{ biJungleHills, { 0x2c, 0x42, 0x05 }, },
{ biJungleEdge, { 0x62, 0x8b, 0x17 }, },
{ biDeepOcean, { 0x00, 0x00, 0x30 }, },
{ biStoneBeach, { 0xa2, 0xa2, 0x84 }, },
{ biColdBeach, { 0xfa, 0xf0, 0xc0 }, },
{ biBirchForest, { 0x30, 0x74, 0x44 }, },
{ biBirchForestHills, { 0x1f, 0x5f, 0x32 }, },
{ biRoofedForest, { 0x40, 0x51, 0x1a }, },
{ biColdTaiga, { 0x31, 0x55, 0x4a }, },
{ biColdTaigaHills, { 0x59, 0x7d, 0x72 }, },
{ biMegaTaiga, { 0x59, 0x66, 0x51 }, },
{ biMegaTaigaHills, { 0x59, 0x66, 0x59 }, },
{ biExtremeHillsPlus, { 0x50, 0x70, 0x50 }, },
{ biSavanna, { 0xbd, 0xb2, 0x5f }, },
{ biSavannaPlateau, { 0xa7, 0x9d, 0x64 }, },
{ biMesa, { 0xd9, 0x45, 0x15 }, },
{ biMesaPlateauF, { 0xb0, 0x97, 0x65 }, },
{ biMesaPlateau, { 0xca, 0x8c, 0x65 }, },
// M variants:
{ biSunflowerPlains, { 0xb5, 0xdb, 0x88 }, },
{ biDesertM, { 0xff, 0xbc, 0x40 }, },
{ biExtremeHillsM, { 0x88, 0x88, 0x88 }, },
{ biFlowerForest, { 0x2d, 0x8e, 0x49 }, },
{ biTaigaM, { 0x33, 0x8e, 0x81 }, },
{ biSwamplandM, { 0x07, 0xf9, 0xb2 }, },
{ biIcePlainsSpikes, { 0xb4, 0xdc, 0xdc }, },
{ biJungleM, { 0x7b, 0xa3, 0x31 }, },
{ biJungleEdgeM, { 0x62, 0x8b, 0x17 }, },
{ biBirchForestM, { 0x58, 0x9c, 0x6c }, },
{ biBirchForestHillsM, { 0x47, 0x87, 0x5a }, },
{ biRoofedForestM, { 0x68, 0x79, 0x42 }, },
{ biColdTaigaM, { 0x24, 0x3f, 0x36 }, },
{ biMegaSpruceTaiga, { 0x45, 0x4f, 0x3e }, },
{ biMegaSpruceTaigaHills, { 0x45, 0x4f, 0x4e }, },
{ biExtremeHillsPlusM, { 0x78, 0x98, 0x78 }, },
{ biSavannaM, { 0xe5, 0xda, 0x87 }, },
{ biSavannaPlateauM, { 0xa7, 0x9d, 0x74 }, },
{ biMesaBryce, { 0xff, 0x6d, 0x3d }, },
{ biMesaPlateauFM, { 0xd8, 0xbf, 0x8d }, },
{ biMesaPlateauM, { 0xf2, 0xb4, 0x8d }, },
} ;
static class BiomeColorsInitializer
{
public:
BiomeColorsInitializer(void)
{
// Reset all colors to gray:
for (size_t i = 0; i < ARRAYCOUNT(biomeToColor); i++)
{
biomeToColor[i] = 0x7f;
}
// Set known biomes to their colors:
for (size_t i = 0; i < ARRAYCOUNT(biomeColors); i++)
{
uchar * color = &biomeToColor[4 * biomeColors[i].m_Biome];
color[0] = biomeColors[i].m_Color[2];
color[1] = biomeColors[i].m_Color[1];
color[2] = biomeColors[i].m_Color[0];
color[3] = 0xff;
}
}
} biomeColorInitializer;
/** Converts biomes in an array into the chunk image data. */
static void biomesToImage(const cChunkDef::BiomeMap & a_Biomes, Chunk::Image & a_Image)
{
// Make sure the two arrays are of the same size, compile-time.
// Note that a_Image is actually 4 items per pixel, so the array is 4 times bigger:
static const char Check1[4 * ARRAYCOUNT(a_Biomes) - ARRAYCOUNT(a_Image) + 1] = {};
static const char Check2[ARRAYCOUNT(a_Image) - 4 * ARRAYCOUNT(a_Biomes) + 1] = {};
// Convert the biomes into color:
for (size_t i = 0; i < ARRAYCOUNT(a_Biomes); i++)
{
a_Image[4 * i + 0] = biomeToColor[4 * a_Biomes[i] + 0];
a_Image[4 * i + 1] = biomeToColor[4 * a_Biomes[i] + 1];
a_Image[4 * i + 2] = biomeToColor[4 * a_Biomes[i] + 2];
a_Image[4 * i + 3] = biomeToColor[4 * a_Biomes[i] + 3];
}
}
////////////////////////////////////////////////////////////////////////////////
// Chunk:
Chunk::Chunk() :
m_IsValid(false)
{
@ -24,12 +156,35 @@ const uchar * Chunk::getImage(void) const
void Chunk::setImage(const Image & a_Image)
void Chunk::setBiomes(const cChunkDef::BiomeMap & a_Biomes)
{
memcpy(m_Image, a_Image, sizeof(a_Image));
memcpy(m_Biomes, a_Biomes, sizeof(m_Biomes));
renderBiomes();
m_IsValid = true;
}
EMCSBiome Chunk::getBiome(int a_RelX, int a_RelZ)
{
if (!m_IsValid)
{
return biInvalidBiome;
}
return cChunkDef::GetBiome(m_Biomes, a_RelX, a_RelZ);
}
void Chunk::renderBiomes()
{
biomesToImage(m_Biomes, m_Image);
}

View File

@ -21,8 +21,12 @@ public:
/** Returns the image of the chunk's biomes. Assumes that the chunk is valid. */
const uchar * getImage(void) const;
/** Sets the image data for this chunk. */
void setImage(const Image & a_Image);
/** Sets the biomes to m_Biomes and renders them into m_Image. */
void setBiomes(const cChunkDef::BiomeMap & a_Biomes);
/** Returns the biome at the specified relative coords, or biInvalidBiome if not valid.
Coords must be valid inside this chunk. */
EMCSBiome getBiome(int a_RelX, int a_RelZ);
protected:
/** Flag that specifies if the chunk data is valid - loaded or generated. */
@ -30,6 +34,13 @@ protected:
/** Cached rendered image of this chunk's biomes. Updated in render(). */
Image m_Image;
/** Biomes comprising the chunk, in the X + 16 * Z ordering. */
cChunkDef::BiomeMap m_Biomes;
/** Renders biomes from m_Biomes into m_Image. */
void renderBiomes();
};
typedef std::shared_ptr<Chunk> ChunkPtr;

View File

@ -27,6 +27,7 @@ $cfile "WebPlugin.h"
$cfile "LuaWindow.h"
$cfile "../BlockID.h"
$cfile "../Mobs/MonsterTypes.h"
$cfile "../BlockInfo.h"
$cfile "../StringUtils.h"
$cfile "../Defines.h"

View File

@ -861,6 +861,11 @@ void cLuaState::GetStackValue(int a_StackPos, eWeather & a_ReturnedVal)
void cLuaState::GetStackValue(int a_StackPos, pBoundingBox & a_ReturnedVal)
{
if (lua_isnil(m_LuaState, a_StackPos))
{
a_ReturnedVal = NULL;
return;
}
tolua_Error err;
if (tolua_isusertype(m_LuaState, a_StackPos, "cBoundingBox", false, &err))
{
@ -874,6 +879,11 @@ void cLuaState::GetStackValue(int a_StackPos, pBoundingBox & a_ReturnedVal)
void cLuaState::GetStackValue(int a_StackPos, pWorld & a_ReturnedVal)
{
if (lua_isnil(m_LuaState, a_StackPos))
{
a_ReturnedVal = NULL;
return;
}
tolua_Error err;
if (tolua_isusertype(m_LuaState, a_StackPos, "cWorld", false, &err))
{
@ -1396,10 +1406,8 @@ void cLuaState::LogStack(const char * a_Header)
void cLuaState::LogStack(lua_State * a_LuaState, const char * a_Header)
{
UNUSED(a_Header); // The param seems unused when compiling for release, so the compiler warns
// Format string consisting only of %s is used to appease the compiler
LOGD("%s", (a_Header != NULL) ? a_Header : "Lua C API Stack contents:");
LOG("%s", (a_Header != NULL) ? a_Header : "Lua C API Stack contents:");
for (int i = lua_gettop(a_LuaState); i > 0; i--)
{
AString Value;

View File

@ -304,7 +304,7 @@ public:
void ToString(int a_StackPos, AString & a_String);
/** Logs all the elements' types on the API stack, with an optional header for the listing. */
void LogStack(const char * a_Header);
void LogStack(const char * a_Header = NULL);
/** Logs all the elements' types on the API stack, with an optional header for the listing. */
static void LogStack(lua_State * a_LuaState, const char * a_Header = NULL);

View File

@ -697,8 +697,12 @@ static int tolua_ForEachInBox(lua_State * tolua_S)
Ty1 * Self = NULL;
cBoundingBox * Box = NULL;
L.GetStackValues(1, Self, Box);
ASSERT(Self != NULL); // We have verified the type at the top, so we should get valid objects here
ASSERT(Box != NULL);
if ((Self == NULL) || (Box == NULL))
{
LOGWARNING("Invalid world (%p) or boundingbox (%p)", Self, Box);
L.LogStackTrace();
return 0;
}
// Create a reference for the function:
cLuaState::cRef FnRef(L, 3);

View File

@ -253,57 +253,6 @@ AString ItemToFullString(const cItem & a_Item)
int StringToMobType(const AString & a_MobString)
{
static struct
{
int m_MobType;
const char * m_String;
} MobMap [] =
{
{mtCreeper, "Creeper"},
{mtSkeleton, "Skeleton"},
{mtSpider, "Spider"},
{mtGiant, "Giant"},
{mtZombie, "Zombie"},
{mtSlime, "Slime"},
{mtGhast, "Ghast"},
{mtZombiePigman, "ZombiePigman"},
{mtEnderman, "Enderman"},
{mtCaveSpider, "CaveSpider"},
{mtSilverfish, "SilverFish"},
{mtBlaze, "Blaze"},
{mtMagmaCube, "MagmaCube"},
{mtEnderDragon, "EnderDragon"},
{mtWither, "Wither"},
{mtBat, "Bat"},
{mtWitch, "Witch"},
{mtPig, "Pig"},
{mtSheep, "Sheep"},
{mtCow, "Cow"},
{mtChicken, "Chicken"},
{mtSquid, "Squid"},
{mtWolf, "Wolf"},
{mtMooshroom, "Mooshroom"},
{mtSnowGolem, "SnowGolem"},
{mtOcelot, "Ocelot"},
{mtIronGolem, "IronGolem"},
{mtVillager, "Villager"},
};
for (size_t i = 0; i < ARRAYCOUNT(MobMap); i++)
{
if (NoCaseCompare(MobMap[i].m_String, a_MobString) == 0)
{
return MobMap[i].m_MobType;
}
} // for i - MobMap[]
return -1;
}
eDimension StringToDimension(const AString & a_DimensionString)
{
// First try decoding as a number

View File

@ -555,10 +555,10 @@ enum
E_META_PRESSURE_PLATE_RAISED = 0,
E_META_PRESSURE_PLATE_DEPRESSED = 1,
// E_BLOCK_PRISMARINE:
E_META_PRISMRAINE_ROUGH = 0,
E_META_PRISMARINE_BRICKS = 1,
E_META_PRISMARINE_DARK = 2,
// E_BLOCK_PRISMARINE_BLOCK metas:
E_META_PRISMARINE_BLOCK_ROUGH = 0,
E_META_PRISMARINE_BLOCK_BRICKS = 1,
E_META_PRISMARINE_BLOCK_DARK = 2,
// E_BLOCK_QUARTZ_BLOCK metas:
E_META_QUARTZ_NORMAL = 0,
@ -577,7 +577,7 @@ enum
E_META_RAIL_CURVED_ZM_XM = 8,
E_META_RAIL_CURVED_ZM_XP = 9,
// E_BLOCK_RED_SANDSTONE:
// E_BLOCK_RED_SANDSTONE metas:
E_META_RED_SANDSTONE_NORMAL = 0,
E_META_RED_SANDSTONE_ORNAMENT = 1,
E_META_RED_SANDSTONE_SMOOTH = 2,
@ -746,7 +746,7 @@ enum
////////////////////////////////////////////////////////////////////////////////
// Item metas:
// E_ITEM_BANNER:
// E_ITEM_BANNER metas:
E_META_BANNER_BLACK = 0,
E_META_BANNER_RED = 1,
E_META_BANNER_GREEN = 2,
@ -790,7 +790,7 @@ enum
E_META_GOLDEN_APPLE_NORMAL = 0,
E_META_GOLDEN_APPLE_ENCHANTED = 1,
// E_ITEM_HEAD:
// E_ITEM_HEAD metas:
E_META_HEAD_SKELETON = 0,
E_META_HEAD_WITHER = 1,
E_META_HEAD_ZOMBIE = 2,
@ -1005,9 +1005,6 @@ extern AString ItemTypeToString(short a_ItemType);
/// Translates a full item into a fully-specified string (including meta and count). If the ItemType is not recognized, the ItemType number is output into the string.
extern AString ItemToFullString(const cItem & a_Item);
/// Translates a mob string ("ocelot") to mobtype (E_ENTITY_TYPE_OCELOT)
extern int StringToMobType(const AString & a_MobString);
/// Translates a dimension string to dimension enum. Takes either a number or a dimension alias (built-in). Returns dimOverworld on failure
extern eDimension StringToDimension(const AString & a_DimensionString);

View File

@ -535,6 +535,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_LAPIS_ORE ].m_FullyOccupiesVoxel = true;
a_Info[E_BLOCK_LOG ].m_FullyOccupiesVoxel = true;
a_Info[E_BLOCK_MELON ].m_FullyOccupiesVoxel = true;
a_Info[E_BLOCK_MOB_SPAWNER ].m_FullyOccupiesVoxel = true;
a_Info[E_BLOCK_MOSSY_COBBLESTONE ].m_FullyOccupiesVoxel = true;
a_Info[E_BLOCK_MYCELIUM ].m_FullyOccupiesVoxel = true;
a_Info[E_BLOCK_NETHERRACK ].m_FullyOccupiesVoxel = true;

View File

@ -24,32 +24,23 @@ public:
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
// Find proper placement of torch
BLOCKTYPE Block;
NIBBLETYPE Meta;
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true); // Set to clicked block
a_ChunkInterface.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, Block, Meta);
if ((a_BlockFace == BLOCK_FACE_TOP) || (a_BlockFace == BLOCK_FACE_BOTTOM))
if (!CanBePlacedOn(Block, Meta, a_BlockFace)) // Try to preserve original direction
{
a_BlockFace = FindSuitableFace(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); // Top or bottom faces clicked, find a suitable face
// Torch couldn't be placed on whatever face was clicked, last ditch resort - find another face
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, false); // Reset to torch block
a_BlockFace = FindSuitableFace(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); // Set a_BlockFace to a valid direction which will be converted later to a metadata
if (a_BlockFace == BLOCK_FACE_NONE)
{
// Client wouldn't have sent anything anyway, but whatever
// No attachable face found - don't place the torch
return false;
}
}
else
{
// Not top or bottom faces, try to preserve whatever face was clicked
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true); // Set to clicked block
if (!CanBePlacedOn(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ), a_BlockFace))
{
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, false); // Reset to torch block
// Torch couldn't be placed on whatever face was clicked, last ditch resort - find another face
a_BlockFace = FindSuitableFace(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
if (a_BlockFace == BLOCK_FACE_NONE)
{
return false;
}
}
}
a_BlockType = m_BlockType;
a_BlockMeta = DirectionToMetaData(a_BlockFace);
@ -97,48 +88,59 @@ public:
}
static bool CanBePlacedOn(BLOCKTYPE a_BlockType, eBlockFace a_BlockFace)
static bool CanBePlacedOn(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_BlockFace)
{
if (!cBlockInfo::FullyOccupiesVoxel(a_BlockType))
switch (a_BlockType)
{
return (a_BlockFace == BLOCK_FACE_TOP); // Allow placement only when torch upright (for glass, etc.); exceptions won't even be sent by client, no need to handle
}
else
{
return true;
case E_BLOCK_END_PORTAL_FRAME:
case E_BLOCK_SOULSAND:
{
// Exceptional vanilla behaviour
return true;
}
case E_BLOCK_GLASS:
case E_BLOCK_STAINED_GLASS:
case E_BLOCK_FENCE:
case E_BLOCK_NETHER_BRICK_FENCE:
case E_BLOCK_COBBLESTONE_WALL:
{
// Torches can only be placed on top of these blocks
return (a_BlockFace == BLOCK_FACE_YP);
}
case E_BLOCK_STONE_SLAB:
case E_BLOCK_WOODEN_SLAB:
{
// Toches can be placed on the top of these slabs only if the occupy the top half of the voxel
return ((a_BlockFace == BLOCK_FACE_YP) && ((a_BlockMeta & 0x08) == 0x08));
}
default:
{
if (cBlockInfo::FullyOccupiesVoxel(a_BlockType))
{
// Torches can be placed on all sides of full blocks except the bottom
return (a_BlockFace != BLOCK_FACE_YM);
}
return false;
}
}
}
/// Finds a suitable face to place the torch, returning BLOCK_FACE_NONE on failure
/** Finds a suitable face to place the torch, returning BLOCK_FACE_NONE on failure */
static eBlockFace FindSuitableFace(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
{
for (int i = BLOCK_FACE_YM; i <= BLOCK_FACE_XP; i++) // Loop through all directions
{
eBlockFace Face = static_cast<eBlockFace>(i);
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, Face, true);
BLOCKTYPE BlockInQuestion = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ);
BLOCKTYPE BlockInQuestion;
NIBBLETYPE BlockInQuestionMeta;
a_ChunkInterface.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockInQuestion, BlockInQuestionMeta);
// If on a block that can only hold a torch if torch is standing on it, return that face
if (
(
(BlockInQuestion == E_BLOCK_GLASS) ||
(BlockInQuestion == E_BLOCK_FENCE) ||
(BlockInQuestion == E_BLOCK_NETHER_BRICK_FENCE) ||
(BlockInQuestion == E_BLOCK_COBBLESTONE_WALL) ||
(BlockInQuestion == E_BLOCK_STONE_SLAB) ||
(BlockInQuestion == E_BLOCK_WOODEN_SLAB)
) &&
(Face == BLOCK_FACE_TOP)
)
if (CanBePlacedOn(BlockInQuestion, BlockInQuestionMeta, Face))
{
return Face;
}
else if (cBlockInfo::FullyOccupiesVoxel(BlockInQuestion) && (i != BLOCK_FACE_BOTTOM))
{
// Otherwise, if block in that direction is torch placeable and we haven't gotten to it via the bottom face, return that face
return Face;
}
else
{
// Reset coords in preparation for next iteration
@ -152,36 +154,16 @@ public:
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
eBlockFace Face = MetaDataToDirection(a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ));
AddFaceDirection(a_RelX, a_RelY, a_RelZ, Face, true);
BLOCKTYPE BlockInQuestion;
a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockInQuestion);
if (
(BlockInQuestion == E_BLOCK_GLASS) ||
(BlockInQuestion == E_BLOCK_STAINED_GLASS) ||
(BlockInQuestion == E_BLOCK_FENCE) ||
(BlockInQuestion == E_BLOCK_SOULSAND) ||
(BlockInQuestion == E_BLOCK_MOB_SPAWNER) ||
(BlockInQuestion == E_BLOCK_END_PORTAL_FRAME) || // Actual vanilla behaviour
(BlockInQuestion == E_BLOCK_NETHER_BRICK_FENCE) ||
(BlockInQuestion == E_BLOCK_COBBLESTONE_WALL) ||
(BlockInQuestion == E_BLOCK_STONE_SLAB) ||
(BlockInQuestion == E_BLOCK_WOODEN_SLAB)
)
{
// Torches can be placed on tops of glass and fences, despite them being 'untorcheable'
// No need to check for upright orientation, it was done when the torch was placed
return true;
}
else if (!cBlockInfo::FullyOccupiesVoxel(BlockInQuestion))
BLOCKTYPE BlockInQuestion;
NIBBLETYPE BlockInQuestionMeta;
if (!a_Chunk.UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockInQuestion, BlockInQuestionMeta))
{
return false;
}
else
{
return true;
}
return CanBePlacedOn(BlockInQuestion, BlockInQuestionMeta, Face);
}

View File

@ -92,7 +92,8 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) :
m_NumBlockChangeInteractionsThisTick(0),
m_UniqueID(0),
m_HasSentPlayerChunk(false),
m_Locale("en_GB")
m_Locale("en_GB"),
m_ProtocolVersion(0)
{
m_Protocol = new cProtocolRecognizer(this);
@ -672,15 +673,22 @@ void cClientHandle::HandlePing(void)
bool cClientHandle::HandleLogin(int a_ProtocolVersion, const AString & a_Username)
{
// If the protocol version hasn't been set yet, set it now:
if (m_ProtocolVersion == 0)
{
m_ProtocolVersion = a_ProtocolVersion;
}
m_Username = a_Username;
// Let the plugins know about this event, they may refuse the player:
if (cRoot::Get()->GetPluginManager()->CallHookLogin(this, a_ProtocolVersion, a_Username))
{
Destroy();
return false;
}
// Schedule for authentication; until then, let them wait (but do not block)
// Schedule for authentication; until then, let the player wait (but do not block)
m_State = csAuthenticating;
cRoot::Get()->GetAuthenticator().Authenticate(GetUniqueID(), GetUsername(), m_Protocol->GetAuthServerID());
return true;

View File

@ -320,6 +320,12 @@ public:
/** Called when the player will enchant a Item */
void HandleEnchantItem(Byte & a_WindowID, Byte & a_Enchantment);
/** Called by the protocol recognizer when the protocol version is known. */
void SetProtocolVersion(UInt32 a_ProtocolVersion) { m_ProtocolVersion = a_ProtocolVersion; }
/** Returns the protocol version number of the protocol that the client is talking. Returns zero if the protocol version is not (yet) known. */
UInt32 GetProtocolVersion(void) const { return m_ProtocolVersion; } // tolua_export
private:
@ -431,6 +437,9 @@ private:
/** The brand identification of the client, as received in the MC|Brand plugin message or set from a plugin. */
AString m_ClientBrand;
/** The version of the protocol that the client is talking, or 0 if unknown. */
UInt32 m_ProtocolVersion;
/** Handles the block placing packet when it is a real block placement (not block-using, item-using or eating) */
void HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, cItemHandler & a_ItemHandler);

View File

@ -422,7 +422,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
// Gravel vein
cStructGenOreNests::OreInfo GravelVein;
GravelVein.BlockType = E_BLOCK_DIRT;
GravelVein.BlockType = E_BLOCK_GRAVEL;
GravelVein.MaxHeight = 127;
GravelVein.NumNests = 20;
GravelVein.NestSize = 32;

View File

@ -574,6 +574,7 @@ bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType)
case E_BLOCK_COBBLESTONE_WALL:
case E_BLOCK_DIAMOND_BLOCK:
case E_BLOCK_DIAMOND_ORE:
case E_BLOCK_DOUBLE_NEW_STONE_SLAB:
case E_BLOCK_DOUBLE_STONE_SLAB:
case E_BLOCK_EMERALD_ORE:
case E_BLOCK_ENCHANTMENT_TABLE:
@ -587,6 +588,7 @@ bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType)
case E_BLOCK_LAPIS_BLOCK:
case E_BLOCK_LAPIS_ORE:
case E_BLOCK_LIT_FURNACE:
case E_BLOCK_MOB_SPAWNER:
case E_BLOCK_MOSSY_COBBLESTONE:
case E_BLOCK_NETHER_BRICK:
case E_BLOCK_NETHER_BRICK_STAIRS:
@ -594,6 +596,7 @@ bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType)
case E_BLOCK_NETHERRACK:
case E_BLOCK_NEW_STONE_SLAB:
case E_BLOCK_OBSIDIAN:
case E_BLOCK_PACKED_ICE:
case E_BLOCK_PRISMARINE_BLOCK:
case E_BLOCK_RED_SANDSTONE:
case E_BLOCK_RED_SANDSTONE_STAIRS:
@ -608,8 +611,6 @@ bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType)
case E_BLOCK_STONE_PRESSURE_PLATE:
case E_BLOCK_STONE_SLAB:
case E_BLOCK_VINES:
case E_BLOCK_PACKED_ICE:
case E_BLOCK_MOB_SPAWNER:
{
return false;
}

View File

@ -41,11 +41,11 @@ public:
case E_BLOCK_DIAMOND_BLOCK:
case E_BLOCK_DIAMOND_ORE:
case E_BLOCK_EMERALD_ORE:
case E_BLOCK_GOLD_BLOCK:
case E_BLOCK_GOLD_ORE:
case E_BLOCK_REDSTONE_ORE:
case E_BLOCK_REDSTONE_ORE_GLOWING:
case E_BLOCK_EMERALD_ORE:
{
return PickaxeLevel() >= 3;
}
@ -59,29 +59,34 @@ public:
}
case E_BLOCK_ANVIL:
case E_BLOCK_ENCHANTMENT_TABLE:
case E_BLOCK_FURNACE:
case E_BLOCK_LIT_FURNACE:
case E_BLOCK_COAL_ORE:
case E_BLOCK_STONE:
case E_BLOCK_COBBLESTONE:
case E_BLOCK_END_STONE:
case E_BLOCK_MOSSY_COBBLESTONE:
case E_BLOCK_SANDSTONE_STAIRS:
case E_BLOCK_SANDSTONE:
case E_BLOCK_STONE_BRICKS:
case E_BLOCK_NETHER_BRICK:
case E_BLOCK_NETHERRACK:
case E_BLOCK_STONE_SLAB:
case E_BLOCK_DOUBLE_STONE_SLAB:
case E_BLOCK_STONE_PRESSURE_PLATE:
case E_BLOCK_BRICK:
case E_BLOCK_CAULDRON:
case E_BLOCK_COAL_ORE:
case E_BLOCK_COBBLESTONE:
case E_BLOCK_COBBLESTONE_STAIRS:
case E_BLOCK_COBBLESTONE_WALL:
case E_BLOCK_STONE_BRICK_STAIRS:
case E_BLOCK_NETHER_BRICK_STAIRS:
case E_BLOCK_CAULDRON:
case E_BLOCK_DOUBLE_NEW_STONE_SLAB:
case E_BLOCK_DOUBLE_STONE_SLAB:
case E_BLOCK_ENCHANTMENT_TABLE:
case E_BLOCK_END_STONE:
case E_BLOCK_FURNACE:
case E_BLOCK_LIT_FURNACE:
case E_BLOCK_MOB_SPAWNER:
case E_BLOCK_MOSSY_COBBLESTONE:
case E_BLOCK_NETHER_BRICK:
case E_BLOCK_NETHER_BRICK_STAIRS:
case E_BLOCK_NETHERRACK:
case E_BLOCK_NEW_STONE_SLAB:
case E_BLOCK_PRISMARINE_BLOCK:
case E_BLOCK_RED_SANDSTONE:
case E_BLOCK_RED_SANDSTONE_STAIRS:
case E_BLOCK_SANDSTONE:
case E_BLOCK_SANDSTONE_STAIRS:
case E_BLOCK_STONE:
case E_BLOCK_STONE_BRICKS:
case E_BLOCK_STONE_BRICK_STAIRS:
case E_BLOCK_STONE_PRESSURE_PLATE:
case E_BLOCK_STONE_SLAB:
{
return PickaxeLevel() >= 1;
}

View File

@ -54,6 +54,7 @@ SET (HDRS
IronGolem.h
MagmaCube.h
Monster.h
MonsterTypes.h
Mooshroom.h
Ocelot.h
PassiveAggressiveMonster.h

View File

@ -62,6 +62,16 @@ static const struct
eMonsterType StringToMobType(const AString & a_MobString)
{
LOGWARNING("%s: Function is obsolete, use cMonster::StringToMobType() instead", __FUNCTION__);
return cMonster::StringToMobType(a_MobString);
}
////////////////////////////////////////////////////////////////////////////////
// cMonster:

View File

@ -25,9 +25,6 @@ class cMonster :
typedef cPawn super;
public:
// Deprecated
typedef eMonsterType eType;
enum eFamily
{
mfHostile = 0, // Spider, Zombies ...

View File

@ -37,5 +37,18 @@ enum eMonsterType
mtZombie = E_META_SPAWN_EGG_ZOMBIE,
mtZombiePigman = E_META_SPAWN_EGG_ZOMBIE_PIGMAN,
} ;
/** Translates a mob string ("ocelot") to mobtype (mtOcelot).
OBSOLETE, use cMonster::StringToMobType() instead.
Implemented in Monster.cpp. */
extern eMonsterType StringToMobType(const AString & a_MobString);
// tolua_end

View File

@ -39,6 +39,6 @@ if(NOT MSVC)
add_library(OSSupport ${SRCS} ${HDRS})
if(UNIX)
target_link_libraries(OSSupport pthread)
target_link_libraries(OSSupport pthread rt)
endif()
endif()

View File

@ -102,6 +102,53 @@ void cEvent::Wait(void)
bool cEvent::Wait(int a_TimeoutMSec)
{
#ifdef _WIN32
DWORD res = WaitForSingleObject(m_Event, (DWORD)a_TimeoutMSec);
switch (res)
{
case WAIT_OBJECT_0: return true; // Regular event signalled
case WAIT_TIMEOUT: return false; // Regular event timeout
default:
{
LOGWARN("cEvent: waiting for the event failed: %u, GLE = %u. Continuing, but server may be unstable.", (unsigned)res, (unsigned)GetLastError());
return false;
}
}
#else
// Get the current time:
timespec timeout;
if (clock_gettime(CLOCK_REALTIME, &timeout) == -1)
{
LOGWARN("cEvent: Getting current time failed: %i, err = %s. Continuing, but the server may be unstable.", errno, GetOSErrorString(errno).c_str());
return false;
}
// Add the specified timeout:
timeout.tv_sec += a_TimeoutMSec / 1000;
timeout.tv_nsec += (a_TimeoutMSec % 1000) * 1000000; // 1 msec = 1000000 usec
// Wait with timeout:
int res = sem_timedwait(m_Event, &timeout);
switch (res)
{
case 0: return true; // Regular event signalled
case ETIMEDOUT: return false; // Regular even timeout
default:
{
AString error = GetOSErrorString(errno);
LOGWARN("cEvent: waiting for the event failed: %i, err = %s. Continuing, but server may be unstable.", res, error.c_str());
return false;
}
}
#endif
}
void cEvent::Set(void)
{
#ifdef _WIN32

View File

@ -24,6 +24,10 @@ public:
void Wait(void);
void Set (void);
/** Waits for the event until either it is signalled, or the (relative) timeout is passed.
Returns true if the event was signalled, false if the timeout was hit or there was an error. */
bool Wait(int a_TimeoutMSec);
private:

View File

@ -905,6 +905,7 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema
{
return false;
}
m_Client->SetProtocolVersion(ProtocolVersion);
switch (ProtocolVersion)
{
case PROTO_VERSION_1_7_2:

View File

@ -134,7 +134,7 @@ protected:
/// Tries to recognize protocol based on m_Buffer contents; returns true if recognized
bool TryRecognizeProtocol(void);
/** Tries to recognize a protocol in the leghted family (1.7+), based on m_Buffer; returns true if recognized.
/** Tries to recognize a protocol in the lengthed family (1.7+), based on m_Buffer; returns true if recognized.
The packet length and type have already been read, type is 0
The number of bytes remaining in the packet is passed as a_PacketLengthRemaining
**/