1
0

Merge branch 'master' into c++11Events

This commit is contained in:
Mattes D 2014-11-04 15:45:08 +01:00
commit 6201b3602c
57 changed files with 4982 additions and 927 deletions

View File

@ -37,6 +37,21 @@ if(DEFINED ENV{MCSERVER_BUILD_ID})
endif()
endif()
# We need C++11 features, Visual Studio has those from VS2012, but it needs a new platform toolset for those; VS2013 supports them natively:
# Adapted from http://binglongx.wordpress.com/2013/06/28/set-non-default-platform-toolset-in-cmake/
if(MSVC OR MSVC_IDE)
if( MSVC_VERSION LESS 1700 ) # VC10- / VS2010-
message(FATAL_ERROR "The project requires C++11 features. "
"You need at least Visual Studio 11 (Microsoft Visual Studio 2012), "
"with Microsoft Visual C++ Compiler Nov 2012 CTP (v120_CTP_Nov2012).")
elseif( MSVC_VERSION EQUAL 1700 ) # VC11 / VS2012
message( "VC11: using Microsoft Visual Studio 2012 "
"with Microsoft Visual C++ Compiler Nov 2012 CTP (v120_CTP_Nov2012)" )
set(CMAKE_GENERATOR_TOOLSET "v120_CTP_Nov2012" CACHE STRING "Platform Toolset" FORCE)
else() # VC12+, assuming C++11 supported.
endif()
endif()
# This has to be done before any flags have been set up.
if(${BUILD_TOOLS})
add_subdirectory(Tools/MCADefrag/)

View File

@ -123,35 +123,47 @@ return
cSplashPotionEntity =
{
Desc = "",
Functions = {},
Desc = [[
Represents a thrown splash potion.
]],
Functions =
{
GetEntityEffect = { Params = "", Return = "{{cEntityEffect}}", Notes = "Returns the entity effect in this potion" },
GetEntityEffectType = { Params = "", Return = "{{cEntityEffect|Entity effect type}}", Notes = "Returns the effect type of this potion" },
GetPotionColor = { Params = "", Return = "number", Notes = "Returns the color index of the particles emitted by this potion" },
SetEntityEffect = { Params = "{{cEntityEffect}}", Return = "", Notes = "Sets the entity effect for this potion" },
SetEntityEffectType = { Params = "{{cEntityEffect|Entity effect type}}", Return = "", Notes = "Sets the effect type of this potion" },
SetPotionColor = { Params = "number", Return = "", Notes = "Sets the color index of the particles for this potion" },
},
Inherits = "cProjectileEntity",
}, -- cSplashPotionEntity
cThrownEggEntity =
{
Desc = "",
Desc = [[
Represents a thrown egg.
]],
Functions = {},
Inherits = "cProjectileEntity",
}, -- cThrownEggEntity
cThrownEnderPearlEntity =
{
Desc = "",
Desc = "Represents a thrown ender pearl.",
Functions = {},
Inherits = "cProjectileEntity",
}, -- cThrownEnderPearlEntity
cThrownSnowballEntity =
{
Desc = "",
Desc = "Represents a thrown snowball.",
Functions = {},
Inherits = "cProjectileEntity",
}, -- cThrownSnowballEntity
cWitherSkullEntity =
{
Desc = "",
Desc = "Represents a wither skull being shot.",
Functions = {},
Inherits = "cProjectileEntity",
}, -- cWitherSkullEntity

View File

@ -0,0 +1,2 @@
Hello! Welcome to the MCServer WebAdmin.<br>
This is a default message, edit <b>files/guest.html</b> to add your own custom message.

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 995 B

View File

@ -0,0 +1,219 @@
/* Copyright Justin S and MCServer Team, licensed under CC-BY-SA 3.0 */
* {
margin: 0;
}
body {
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
-webkit-font-smoothing: antialiased;
background: #fff url(header.png) repeat-x top left;
width: 100%;
min-width: 100%;
overflow: hidden;
}
a:link {
color: #555;
text-decoration: none;
}
a:visited {
color: #444;
text-decoration: none;
}
a:hover, a:active {
color: #000;
text-decoration: underline;
}
img {
border: none;
}
h1 {
color: #069;
}
.row1 {
border-bottom: 1px solid #000;
height: 100px;
max-height: 100px;
}
.row2 {
margin: 0 auto;
text-align: center;
vertical-align: middle;
}
.contention {
color: #000;
text-align: left;
line-height: 1.4;
margin: 0;
font-family: Tahoma,Verdana,Arial,Sans-Serif;
font-size: 13px;
}
button {
background: #fff;
color: #000;
border: 1px solid #ccc;
padding: 3px;
font-family: Tahoma,Verdana,Arial,Sans-Serif;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
margin: -3px 0;
}
button:hover {
border-top-color: #28597a;
background: #28597a;
color: #ccc;
}
button:active {
border-top-color: #1b435e;
background: #1b435e;
}
.push10 {
padding-bottom: 75px;
}
#panel .upper {
background: #dcdbdc url(tcat.png) repeat-x;
border-top: 1px solid #fff;
border-bottom: 1px solid #bbb;
padding: 7px;
}
#footer {
z-index: 99999;
}
#footer ul.menu {
margin: 0;
padding: 0;
list-style: none;
}
#footer ul.menu li {
margin: 0 5px;
display: inline;
}
#footer .upper {
background: #dcdbdc url(tcat.png) repeat-x;
border-top: 1px solid #bbb;
padding: 6px;
overflow: hidden;
font-size: 12px;
}
#footer .upper ul.bottom_links {
float: left;
margin: 3px 0 0 -5px;
}
#footer .lower {
background: #a1a2a2 url(thead.png) top left repeat-x;
color: #fff;
border-top: 1px solid #ccc;
border-bottom: 1px solid #ddd;
overflow: hidden;
padding: 8px;
font-size: 11px;
}
#footer .lower a:link, #footer .lower a:visited {
color: #fff;
font-weight: 700;
}
#footer .lower a:hover, #footer .lower a:active {
color: #fff;
font-weight: 700;
}
#footer .lower #current_time {
float: right;
padding-right: 6px;
}
.wrapper {
width: 85%;
min-width: 970px;
max-width: 1500px;
margin: auto;
}
#footer {
position: fixed;
left: 0;
bottom: 0;
height: 60px;
width: 100%;
background: #999;
border-top: 1px #000 solid;
}
* html #footer {
position: absolute;
top: expression((0-(footer.offsetHeight)+(document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight)+(ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop))+'px');
}
tr td.trow2:first-child {
border-left: 0;
}
tr td.trow2:last-child {
border-right: 0;
}
.tborder {
-moz-border-radius: 7px;
-webkit-border-radius: 7px;
border-radius: 7px;
}
.thead, .rounded_top {
-moz-border-radius-topleft: 6px;
-moz-border-radius-topright: 6px;
-webkit-border-top-left-radius: 6px;
-webkit-border-top-right-radius: 6px;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
}
table {
color: #000;
font-size: 13px;
}
.tborder {
background: #fff;
width: 100%;
margin: auto;
border: 1px solid #ccc;
padding: 1px;
}
.thead {
background: #a1a2a2 url(thead.png) top left repeat-x;
color: #fff;
border-bottom: 1px solid #8e8f8f;
padding: 8px;
}
.trow2 {
background: #efefef;
border: 1px solid;
border-color: #fff #ddd #ddd #fff;
}
.padtopp {
padding-top: 25px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 995 B

View File

@ -1,353 +1,433 @@
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);
/* Copyright Justin S and MCServer Team, licensed under CC-BY-SA 3.0 */
* {
margin: 0;
}
.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);
body {
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
-webkit-font-smoothing: antialiased;
background: #fff;
width: 100%;
min-width: 100%;
overflow-y: scroll;
overflow-x: hidden;
}
.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;
a:link {
color: #555;
text-decoration: none;
}
#sidebar
{
float: left;
width: 20%;
a:visited {
color: #444;
text-decoration: none;
}
.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);
a:hover, a:active {
color: #000;
text-decoration: underline;
}
.sideNav li
{
padding: 10px;
color: rgba(0, 0, 0, 0.54);
img {
border: none;
}
.sideNav li.link
{
padding-left: 30px;
h1 {
color: #069;
text-shadow: 2px 2px #000;
}
.sideNav li.link a
{
text-decoration: none;
color: rgba(0, 0, 0, 0.87);
.row1 {
border-bottom: 1px #000 solid;
height: 100px;
max-height: 100px;
background: #fff url(header.png) repeat-x top left;
}
#container
{
margin: 0;
padding: 0;
overflow: hidden;
background-color: #f5f5f5;
.row2 {
margin: 0 auto;
text-align: center;
vertical-align: middle;
margin-top: 125px;
}
#main
{
float: right;
width: 80%;
padding: 0 15px 20px 15px;
box-sizing: border-box;
-moz-box-sizing: border-box;
.contention {
color: #000;
text-align: left;
line-height: 1.4;
margin: 0;
font-family: Tahoma,Verdana,Arial,Sans-Serif;
font-size: 13px;
}
.clear
{
clear: both;
.push10 {
padding-bottom: 75px;
}
table
{
width: 100%;
border-collapse: collapse;
#panel ul.menu {
margin: 0;
padding: 0;
list-style: none;
}
table td
{
padding: 5px;
#panel ul.menu li {
margin: 0 5px;
display: inline;
}
table th
{
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
padding: 5px;
text-align: center;
#panel ul.menu li a {
padding-left: 20px;
background-repeat: no-repeat;
background-position: left center;
}
table tr:nth-child(odd)
{
background-color: rgba(0, 0, 0, 0.015);
#panel .upper ul.top_links {
float: right;
font-weight: 700;
}
p
{
margin: 8px 0;
padding: 8px 3px;
#panel .upper {
background: #dcdbdc url(tcat.png) repeat-x;
border-top: 1px solid #fff;
border-bottom: 1px solid #bbb;
padding: 7px;
}
a
{
text-decoration: none;
color: #0277bd;
-webkit-transition: color 0.1s linear;
-moz-transition: color 0.1s linear;
transition: color 0.1s linear;
#footer {
z-index: 99999;
}
a:hover
{
color: #01579b;
#footer ul.menu {
margin: 0;
padding: 0;
list-style: none;
}
.welcome-msg
{
color: rgba(0, 0, 0, 0.54);
#footer ul.menu li {
margin: 0 5px;
display: inline;
}
.username
{
text-transform: capitalize;
color: rgba(0, 0, 0, 0.87);
#footer .upper {
background: #dcdbdc url(tcat.png) repeat-x;
border-top: 1px solid #bbb;
padding: 6px;
overflow: hidden;
font-size: 12px;
}
a:hover
{
color: black;
#footer .upper ul.bottom_links {
float: left;
margin: 3px 0 0 -5px;
}
input, select
{
padding: 8px;
#footer .lower {
background: #a1a2a2 url(thead.png) top left repeat-x;
color: #fff;
border-top: 1px solid #ccc;
border-bottom: 1px solid #ddd;
overflow: hidden;
padding: 8px;
font-size: 11px;
}
form
{
padding: 4px;
#footer .lower a:link,#footer .lower a:visited {
color: #fff;
font-weight: 700;
}
.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;
#footer .lower a:hover,#footer .lower a:active {
color: #fff;
font-weight: 700;
}
.err
{
color: white;
display: block;
background-color: #e51c23 !important;
padding: 15px;
line-height: 30px;
min-height: 30px;
#footer .lower #current_time {
float: right;
padding-right: 6px;
}
.err:before
{
content: "ERROR: ";
.wrapper {
width: 85%;
min-width: 970px;
max-width: 1500px;
margin: auto;
}
.warn
{
color: white;
display: block;
background-color: #ff5722 !important;
padding: 15px;
line-height: 30px;
min-height: 30px;
#footer {
position: fixed;
left: 0;
bottom: 0;
height: 60px;
width: 100%;
background: #999;
border-top: 1px #000 solid;
}
.warn:before
{
content: "WARNING: ";
* html #footer {
position: absolute;
top: expression((0-(footer.offsetHeight)+(document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight)+(ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop))+'px');
}
.info
{
color: white;
display: block;
background-color: #5677fc !important;
padding: 15px;
line-height: 30px;
min-height: 30px;
tr td.trow1:first-child, tr td.trow2:first-child {
border-left: 0;
}
.info:before
{
content: "INFORMATION: ";
tr td.trow1:last-child, tr td.trow2:last-child {
border-right: 0;
}
#footer .fleft
{
float: left;
.tborder {
-moz-border-radius: 7px;
-webkit-border-radius: 7px;
border-radius: 7px;
}
#footer .fright
{
float: right;
text-align: right;
.thead {
-moz-border-radius-topleft: 6px;
-moz-border-radius-topright: 6px;
-webkit-border-top-left-radius: 6px;
-webkit-border-top-right-radius: 6px;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
}
#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;
table {
color: #000;
font-size: 13px;
}
#footer a
{
text-transform: none;
color: white;
.tborder {
background: #fff;
width: 100%;
margin: auto;
border: 1px solid #ccc;
padding: 1px;
}
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;
.thead {
background: #a1a2a2 url(thead.png) top left repeat-x;
color: #fff;
border-bottom: 1px solid #8e8f8f;
padding: 8px;
}
input[type="submit"]:hover, button:hover, input[type="button"]:hover
{
background-color: #ffca28;
.tcat {
background: #dcdbdc url(tcat.png) repeat-x;
color: #fff;
border-bottom: 1px solid #bbb;
padding: 6px;
font-size: 12px;
}
input[type="submit"]:active, button:active, input[type="button"]:active
{
background-color: #ffd54f;
-webkit-transform: translateY(1px);
-moz-transform: translateY(1px);
transform: translateY(1px);
.trow1 {
background: #f5f5f5;
border: 1px solid;
border-color: #fff #ddd #ddd #fff;
}
hr
{
border: none;
height: 1px;
background-color: rgba(0, 0, 0, 0.12);
.trow2 {
background: #efefef;
border: 1px solid;
border-color: #fff #ddd #ddd #fff;
padding: 15px;
box-sizing: border-box;
-moz-box-sizing: border-box;
}
h4
{
padding-bottom: 10px;
margin-bottom: 12px;
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
.padtopp {
padding-top: 25px;
}
/**** PAGE SPECIFIC CSS ****/
/* remove the * for disabling: */
.page-core-server-settings table td
{
text-align: center;
width: 25%;
table {
color: #000;
font-size: 13px;
text-align: left;
}
.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);
.tborder {
background: #fff;
width: 100%;
margin: auto;
border: 1px solid #ccc;
padding: 1px;
}
.page-core-server-settings.param-tab-monsters table td:nth-child(2) a
{
font-weight: 600;
color: rgba(0, 0, 0, 0.87);
.thead {
background: #a1a2a2 url(thead.png) top left repeat-x;
color: #fff;
border-bottom: 1px solid #8e8f8f;
padding: 8px;
}
.page-core-server-settings.param-tab-worlds table td:nth-child(3) a
{
font-weight: 600;
color: rgba(0, 0, 0, 0.87);
.tcat {
background: #dcdbdc url(tcat.png) repeat-x;
color: #fff;
border-bottom: 1px solid #bbb;
padding: 6px;
font-size: 12px;
}
.page-core-server-settings.param-tab-world table td:nth-child(4) a
{
font-weight: 600;
color: rgba(0, 0, 0, 0.87);
.trow1 {
background: #f5f5f5;
border: 1px solid;
border-color: #fff #ddd #ddd #fff;
}
.page-core-permissions form table tr,
.page-core-permissions form table td,
.page-core-permissions form table th
{
border: none;
background-color: transparent;
.trow2 {
background: #efefef;
border: 1px solid;
border-color: #fff #ddd #ddd #fff;
}
.page-core-permissions form table tr:nth-child(1) th
{
width: 35%;
.smalltext {
font-size: 11px;
}
.page-core-permissions form table tr:nth-child(1) td
{
width: 65%;
textarea {
background: #fff;
color: #000;
border: 1px solid #ccc;
padding: 2px;
line-height: 1.4;
font-family: Tahoma,Verdana,Arial,Sans-Serif;
font-size: 13px;
}
.page-core-permissions form table td input
{
width: 100%;
box-sizing: border-box;
-moz-box-sizing: border-box;
margin: 0;
select {
background: #fff;
padding: 3px;
border: 1px solid #ccc;
font-family: Tahoma,Verdana,Arial,Sans-Serif;
}
#ChatDiv
{
margin-bottom: 10px;
.usercp_nav_item {
display: block;
padding: 1px 0 1px 23px;
}
#ChatMessage
{
width: 100%;
box-sizing: border-box;
-moz-box-sizing: border-box;
.usercp_nav_pmfolder {
background: url(pmfolder.gif) no-repeat left center;
}
/**/
.usercp_nav_sub_pmfolder {
padding-left: 40px;
background: url(sub_pmfolder.gif) no-repeat left center;
}
.usercp_nav_home {
background: url(home.gif) no-repeat left center;
}
.pagehead {
position: fixed;
z-index: 99999;
top: 0;
left: 0;
width: 100%;
}
table {
width: 100%;
}
table th {
border-bottom: 1px solid rgba(0,0,0,0.12);
padding: 5px;
text-align: left;
}
table tr:nth-child(odd) {
background-color: rgba(0,0,0,0.015);
}
p {
margin: 4px 0;
padding: 4px 3px;
}
a {
text-decoration: none;
color: #000;
-webkit-transition: color .1s linear;
-moz-transition: color .1s linear;
transition: color .1s linear;
}
a:hover {
color: #888;
}
input[type="text"] {
background: #fff;
color: #000;
border: 1px solid #ccc;
padding: 2px;
line-height: 1.4;
font-family: Tahoma,Verdana,Arial,Sans-Serif;
font-size: 13px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
}
input[type="text"]:hover {
background-color: #E5E4E2;
}
input[type="text"]:focus {
background-color: #E5E4E2;
}
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);
}
#ChatDiv {
margin-bottom: 10px;
}
#ChatMessage {
width: 92%;
margin-right: 5px;
box-sizing: border-box;
-moz-box-sizing: border-box;
}
input[type="submit"] {
padding: 3px;
padding-left: 5px;
padding-right: 5px;
cursor: pointer;
font-family: Tahoma,Verdana,Arial,Sans-Serif;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
background: #f5f5f5;
border: 1px solid #ccc;
}
input[type="submit"]:hover {
background-color: #E5E4E2;
}
button:disabled,input:disabled {
padding: 3px;
padding-left: 5px;
padding-right: 5px;
cursor: pointer;
font-family: Tahoma,Verdana,Arial,Sans-Serif;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
border: none!important;
color: #fff!important;
background-color: #ccc!important;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1022 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 B

View File

@ -1,25 +1,70 @@
/* Copyright Justin S and MCServer Team, licensed under CC-BY-SA 3.0 */
<html>
<head>
<title>MCServer WebAdmin - Login</title>
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link href="login.css" rel="stylesheet" type="text/css">
<link rel="icon" href="favicon.ico">
<style type="text/css">
header {
margin: 0 auto;
text-align: center;
vertical-align: middle;
}
</style>
</head>
<body>
<header>
<img src="mc-logo.png" alt="MCServer Logo" class="logo">
<h1>MCServer - WebAdmin</h1>
<form method="get" action="webadmin/">
<input type="submit" value="Log in">
</form>
</header>
<div class="contention">
<div class="row1">
<div class="wrapper">
<img src="logo_login.png" alt="MCServer Logo" class="logo">
</div>
</div>
<div id="panel">
<div class="upper">
<div class="wrapper">
<div>
<form method="get" action="webadmin/" />
<button type="submit" value="Log in" style="width:150px;height:25px;font-family:'Source Sans Pro',sans-serif;background:transparent;border:none!important;vertical-align:middle">
<strong><img src="login.gif" style="vertical-align:bottom" /> WebAdmin Log in</strong>
</button>
</form>
</div>
</div>
</div>
</div>
<div class="row2 push10">
<div class="wrapper padtopp">
<table border="0" cellspacing="0" cellpadding="5" class="tborder" style="margin-bottom:5px">
<tbody>
<tr>
<td class="thead rounded_top">
<div style="float:left!important"><strong>MCServer WebAdmin</strong></div>
</td>
</tr>
<tr>
<td class="trow2 post_content">
<div class="post_body">
<iframe width="100%" height="100%" style="border:none;min-height:350px;max-height:450px" src="/guest.html"></iframe>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div id="footer">
<div class="upper">
<div class="wrapper">
<ul class="menu bottom_links">
<li><a href="http://www.mc-server.org" target="_blank">MCServer</a></li>
<li><a href="http://forum.mc-server.org" target="_blank">Forums</a></li>
<li><a href="http://builds.cuberite.org" target="_blank">Buildserver</a></li>
<li><a href="http://mc-server.xoft.cz/LuaAPI" target="_blank">API Documentation</a></li>
<li><a href="http://book.mc-server.org/" target="_blank">User's Manual</a></li>
</ul>
</div>
</div>
<div class="lower">
<div class="wrapper">
<span id="current_time"><strong>Current time:</strong> <script type="text/javascript">document.write('Time: <strong><span id="date-time">',new Date().toLocaleString(),"</span></strong>");if(document.getElementById){onload=function(){setInterval("document.getElementById ('date-time').firstChild.data = new Date().toLocaleString()",50)}};</script></span>
<span id="copyright">Copyright © <a href="http://www.mc-server.org" target="_blank">MCServer Team</a> 2014.</span>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1 @@

View File

@ -81,22 +81,56 @@ function ShowPage(WebAdmin, TemplateRequest)
end
Output([[
<!DOCTYPE html>
/* Copyright Justin S and MCServer Team, licensed under CC-BY-SA 3.0 */
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="icon" href="/favicon.ico">
<title>]] .. Title .. [[</title>
<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">
<title>]] .. Title .. [[</title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="/style.css">
<link rel="icon" href="/favicon.ico">
</head>
<body>
<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>
<div class="contention">
<div class="pagehead">
<div class="row1">
<div class="wrapper">
<img src="/logo_login.png" alt="MCServer Logo" class="logo">
</div>
</div>
<div id="panel">
<div class="upper">
<div class="wrapper">
<ul class="menu top_links">
<li><a>Server Name: <strong>]] .. cRoot:Get():GetServer():GetServerID() .. [[</strong></a></li>
<li><a>Memory: <strong>]] .. MemoryUsageKiB / 1024 .. [[MB</strong></a></li>
<li><a>Chunks: <strong>]] .. NumChunks .. [[</strong></a></li>
</ul>
<div class="welcome"><strong>Welcome back, ]] .. TemplateRequest.Request.Username .. [[</strong>&nbsp;&nbsp;&nbsp;<a href=".././"><img src="/log_out.png" style="vertical-align:bottom;"> Log Out</a></div>
</div>
</div>
</div>
</div>
<div class="row2 push10">
<div class="wrapper padtopp">
<table width="100%" border="0" align="center">
<tbody>
<tr>
<td width="180" valign="top">
<table border="0" cellspacing="0" cellpadding="5" class="tborder">
<tbody>
<tr>
<td class="thead"><strong>Menu</strong></td>
</tr>
<tr>
<td class="trow1 smalltext"><a href=']] .. BaseURL .. [[' class='usercp_nav_item usercp_nav_home'>Home</a></td>
</tr>
<tr>
<td class="tcat"><div><span class="smalltext"><strong><font color="#000">Server Management</font></strong></span></div></td>
</tr>
</tbody>
<tbody style="" id="usercppms_e">
<tr>
<td class="trow1 smalltext">
]])
@ -105,30 +139,59 @@ function ShowPage(WebAdmin, TemplateRequest)
local PluginWebTitle = value:GetWebTitle()
local TabNames = value:GetTabNames()
if (GetTableSize(TabNames) > 0) then
Output("<li>"..PluginWebTitle.."</li>\n");
Output("<div><a class='usercp_nav_item usercp_nav_pmfolder' style='text-decoration:none;'><b>"..PluginWebTitle.."</b></a></div>\n");
for webname,prettyname in pairs(TabNames) do
Output("<li class='link'><a href='" .. BaseURL .. PluginWebTitle .. "/" .. webname .. "'>" .. prettyname .. "</a></li>\n")
Output("<div><a href='" .. BaseURL .. PluginWebTitle .. "/" .. webname .. "' class='usercp_nav_item usercp_nav_sub_pmfolder'>" .. prettyname .. "</a></div>\n")
end
Output("<br>\n");
end
end
Output([[
</ul>
</div>
<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>
</td>
</tr>
</tbody>
</table>
</td>
<td valign="top" style='padding-left:25px;'>
<table border="0" cellspacing="0" cellpadding="5" class="tborder">
<tbody>
<tr>
<td class="thead" colspan="2"><strong>]] .. SubTitle .. [[</strong></td>
</tr>
<tr>
<td class="trow2">]] .. PageContent .. [[</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div id="footer">
<div class="upper">
<div class="wrapper">
<ul class="menu bottom_links">
<li><a href="http://www.mc-server.org" target="_blank">MCServer</a></li>
<li><a href="http://forum.mc-server.org" target="_blank">Forums</a></li>
<li><a href="http://builds.cuberite.org" target="_blank">Buildserver</a></li>
<li><a href="http://mc-server.xoft.cz/LuaAPI" target="_blank">API Documentation</a></li>
<li><a href="http://book.mc-server.org/" target="_blank">User's Manual</a></li>
</ul>
</div>
</div>
<div class="lower">
<div class="wrapper">
<span id="current_time"><strong>Current time:</strong> <script type="text/javascript">document.write('Time: <strong><span id="date-time">',new Date().toLocaleString(),"</span></strong>");if(document.getElementById){onload=function(){setInterval("document.getElementById ('date-time').firstChild.data = new Date().toLocaleString()",50)}};</script></span>
<span id="copyright">Copyright © <a href="http://www.mc-server.org" target="_blank">MCServer Team</a> 2014.</span>
</div>
</div>
<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>

View File

@ -10,6 +10,8 @@ We currently support Release 1.7 and 1.8 (not beta) Minecraft protocol versions.
Installation
------------
[![Install on DigitalOcean](http://doinstall.bearbin.net/button.svg)](http://doinstall.bearbin.net/install?url=https://github.com/mc-server/MCServer)
For Linux there is an easy installation method, just run this in your terminal:
curl -s https://raw.githubusercontent.com/mc-server/MCServer/master/easyinstall.sh | sh

View File

@ -1,8 +1,8 @@
#include "Globals.h"
#include "BiomeView.h"
#include "QtChunk.h"
#include <QPainter>
#include <QResizeEvent>
#include "Region.h"
@ -14,6 +14,116 @@ static const int DELTA_STEP = 120; // The normal per-notch wheel delta
/** 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;
////////////////////////////////////////////////////////////////////////////////
// BiomeView:
BiomeView::BiomeView(QWidget * parent) :
super(parent),
m_X(0),
@ -40,7 +150,7 @@ BiomeView::BiomeView(QWidget * parent) :
redraw();
// Add a chunk-update callback mechanism:
connect(&m_Cache, SIGNAL(chunkAvailable(int, int)), this, SLOT(chunkAvailable(int, int)));
connect(&m_Cache, SIGNAL(regionAvailable(int, int)), this, SLOT(regionAvailable(int, int)));
// Allow mouse and keyboard interaction:
setFocusPolicy(Qt::StrongFocus);
@ -143,9 +253,15 @@ void BiomeView::redraw()
void BiomeView::chunkAvailable(int a_ChunkX, int a_ChunkZ)
void BiomeView::regionAvailable(int a_RegionX, int a_RegionZ)
{
drawChunk(a_ChunkX, a_ChunkZ);
for (int z = 0; z < 32; z++)
{
for (int x = 0; x < 32; x++)
{
drawChunk(a_RegionX * 32 + x, a_RegionZ * 32 + z);
}
}
update();
}
@ -175,8 +291,11 @@ void BiomeView::drawChunk(int a_ChunkX, int a_ChunkZ)
return;
}
//fetch the chunk:
ChunkPtr chunk = m_Cache.fetch(a_ChunkX, a_ChunkZ);
// Fetch the region:
int regionX;
int regionZ;
Region::chunkToRegion(a_ChunkX, a_ChunkZ, regionX, regionZ);
RegionPtr region = m_Cache.fetch(regionX, regionZ);
// Figure out where on the screen this chunk should be drawn:
// first find the center chunk
@ -194,11 +313,10 @@ void BiomeView::drawChunk(int a_ChunkX, int a_ChunkZ)
centerx += (a_ChunkX - centerchunkx) * chunksize;
centery += (a_ChunkZ - centerchunkz) * chunksize;
int srcoffset = 0;
uchar * bits = m_Image.bits();
int imgstride = m_Image.bytesPerLine();
int skipx = 0,skipy = 0;
int skipx = 0, skipy = 0;
int blockwidth = chunksize, blockheight = chunksize;
// now if we're off the screen we need to crop
if (centerx < 0)
@ -227,29 +345,52 @@ void BiomeView::drawChunk(int a_ChunkX, int a_ChunkZ)
int imgoffset = centerx * 4 + centery * imgstride;
// If the chunk is valid, use its data; otherwise use the empty placeholder:
const uchar * src = m_EmptyChunkImage;
if (chunk.get() != nullptr)
const short * src = m_EmptyChunkBiomes;
if (region.get() != nullptr)
{
src = chunk->getImage();
int relChunkX = a_ChunkX - regionX * 32;
int relChunkZ = a_ChunkZ - regionZ * 32;
Chunk & chunk = region->getRelChunk(relChunkX, relChunkZ);
if (chunk.isValid())
{
src = chunk.getBiomes();
}
}
// Blit or scale-blit the image:
// Scale-blit the image:
for (int z = skipy; z < blockheight; z++, imgoffset += imgstride)
{
srcoffset = floor((double)z / m_Zoom) * 16 * 4;
if (m_Zoom == 1.0)
size_t srcoffset = static_cast<size_t>(std::floor((double)z / m_Zoom)) * 16;
int imgxoffset = imgoffset;
for (int x = skipx; x < blockwidth; x++)
{
memcpy(bits + imgoffset, src + srcoffset + skipx * 4, (blockwidth - skipx) * 4);
}
else
{
int xofs = 0;
for (int x = skipx; x < blockwidth; x++, xofs +=4)
short biome = src[srcoffset + static_cast<size_t>(std::floor((double)x / m_Zoom))];
const uchar * color;
if (biome < 0)
{
memcpy(bits + imgoffset + xofs, src + srcoffset + (int)floor((double)x / m_Zoom) * 4, 4);
static const uchar emptyBiome1[] = { 0x44, 0x44, 0x44, 0xff };
static const uchar emptyBiome2[] = { 0x88, 0x88, 0x88, 0xff };
color = ((x & 8) ^ (z & 8)) ? emptyBiome1 : emptyBiome2;
}
}
}
else
{
if (biome * 4 >= ARRAYCOUNT(biomeToColor))
{
static const uchar errorImage[] = { 0xff, 0x00, 0x00, 0xff };
color = errorImage;
}
else
{
color = biomeToColor + biome * 4;
}
}
bits[imgxoffset] = color[0];
bits[imgxoffset + 1] = color[1];
bits[imgxoffset + 2] = color[2];
bits[imgxoffset + 3] = color[3];
imgxoffset += 4;
} // for x
} // for z
}
@ -317,11 +458,12 @@ void BiomeView::mouseMoveEvent(QMouseEvent * a_Event)
// 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;
int regionX, regionZ;
Region::blockToRegion(blockX, blockZ, regionX, regionZ);
int relX = blockX - regionX * 512;
int relZ = blockZ - regionZ * 512;
auto region = m_Cache.fetch(regionX, regionZ);
int biome = (region.get() != nullptr) ? region->getRelBiome(relX, relZ) : biInvalidBiome;
emit hoverChanged(blockX, blockZ, biome);
}

View File

@ -2,7 +2,7 @@
#include <QWidget>
#include <memory>
#include "ChunkCache.h"
#include "RegionCache.h"
#include "ChunkSource.h"
@ -51,8 +51,8 @@ public slots:
/** Redraw the entire widget area. */
void redraw();
/** A specified chunk has become available, redraw it. */
void chunkAvailable(int a_ChunkX, int a_ChunkZ);
/** A specified region has become available, redraw it. */
void regionAvailable(int a_RegionX, int a_RegionZ);
/** Reloads the current chunk source and redraws the entire workspace. */
void reload();
@ -62,7 +62,7 @@ protected:
double m_Zoom;
/** Cache for the loaded chunk data. */
ChunkCache m_Cache;
RegionCache m_Cache;
/** The entire view's contents in an offscreen image. */
QImage m_Image;
@ -79,6 +79,9 @@ protected:
/** Data used for rendering a chunk that hasn't been loaded yet */
uchar m_EmptyChunkImage[16 * 16 * 4];
/** Data placeholder for chunks that aren't valid. */
short m_EmptyChunkBiomes[16 * 16];
/** Draws the specified chunk into m_Image */
void drawChunk(int a_ChunkX, int a_ChunkZ);

View File

@ -1,126 +0,0 @@
#include "Globals.h"
#include "ChunkCache.h"
#include <QMutexLocker>
#include <QThreadPool>
#include "ChunkSource.h"
#include "ChunkLoader.h"
ChunkCache::ChunkCache(QObject * parent) :
super(parent)
{
m_Cache.setMaxCost(1024 * 1024 * 1024); // 1 GiB of memory for the cache
}
ChunkPtr ChunkCache::fetch(int a_ChunkX, int a_ChunkZ)
{
// Retrieve from the cache:
quint32 hash = getChunkHash(a_ChunkX, a_ChunkZ);
ChunkPtr * res;
{
QMutexLocker lock(&m_Mtx);
res = m_Cache[hash];
// If succesful and chunk loaded, return the retrieved value:
if ((res != nullptr) && (*res)->isValid())
{
return *res;
}
}
// If the chunk is in cache but not valid, it means it has been already queued for rendering, do nothing now:
if (res != nullptr)
{
return ChunkPtr(nullptr);
}
// There's no such item in the cache, create it now:
res = new ChunkPtr(new Chunk);
if (res == nullptr)
{
return ChunkPtr(nullptr);
}
{
QMutexLocker lock(&m_Mtx);
m_Cache.insert(hash, res, sizeof(Chunk));
}
// Queue the chunk for rendering:
queueChunkRender(a_ChunkX, a_ChunkZ, *res);
// Return failure, the chunk is not yet rendered:
return ChunkPtr(nullptr);
}
void ChunkCache::setChunkSource(std::shared_ptr<ChunkSource> a_ChunkSource)
{
// Replace the chunk source:
m_ChunkSource = a_ChunkSource;
// Clear the cache:
QMutexLocker lock(&m_Mtx);
m_Cache.clear();
}
void ChunkCache::reload()
{
assert(m_ChunkSource.get() != nullptr);
// Reload the chunk source:
m_ChunkSource->reload();
// Clear the cache:
QMutexLocker lock(&m_Mtx);
m_Cache.clear();
}
void ChunkCache::gotChunk(int a_ChunkX, int a_ChunkZ)
{
emit chunkAvailable(a_ChunkX, a_ChunkZ);
}
quint32 ChunkCache::getChunkHash(int a_ChunkX, int a_ChunkZ)
{
// Simply join the two coords into a single int
// The coords will never be larger than 16-bits, so we can do this safely
return (((static_cast<quint32>(a_ChunkX) & 0xffff) << 16) | (static_cast<quint32>(a_ChunkZ) & 0xffff));
}
void ChunkCache::queueChunkRender(int a_ChunkX, int a_ChunkZ, ChunkPtr & a_Chunk)
{
// Create a new loader task:
ChunkLoader * loader = new ChunkLoader(a_ChunkX, a_ChunkZ, a_Chunk, m_ChunkSource);
connect(loader, SIGNAL(loaded(int, int)), this, SLOT(gotChunk(int, int)));
QThreadPool::globalInstance()->start(loader);
}

View File

@ -1,29 +0,0 @@
#include "Globals.h"
#include "ChunkLoader.h"
#include "ChunkSource.h"
ChunkLoader::ChunkLoader(int a_ChunkX, int a_ChunkZ, ChunkPtr a_Chunk, ChunkSourcePtr a_ChunkSource) :
m_ChunkX(a_ChunkX),
m_ChunkZ(a_ChunkZ),
m_Chunk(a_Chunk),
m_ChunkSource(a_ChunkSource)
{
}
void ChunkLoader::run()
{
m_ChunkSource->getChunkBiomes(m_ChunkX, m_ChunkZ, m_Chunk);
emit loaded(m_ChunkX, m_ChunkZ);
}

View File

@ -1,45 +0,0 @@
#pragma once
#include <QObject>
#include <QRunnable>
#include <memory>
// fwd:
class Chunk;
typedef std::shared_ptr<Chunk> ChunkPtr;
class ChunkSource;
typedef std::shared_ptr<ChunkSource> ChunkSourcePtr;
class ChunkLoader :
public QObject,
public QRunnable
{
Q_OBJECT
public:
ChunkLoader(int a_ChunkX, int a_ChunkZ, ChunkPtr a_Chunk, ChunkSourcePtr a_ChunkSource);
virtual ~ChunkLoader() {}
signals:
void loaded(int a_ChunkX, int a_ChunkZ);
protected:
virtual void run() override;
private:
int m_ChunkX, m_ChunkZ;
ChunkPtr m_Chunk;
ChunkSourcePtr m_ChunkSource;
};

View File

@ -24,14 +24,14 @@ BioGenSource::BioGenSource(cIniFilePtr a_IniFile) :
void BioGenSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk)
void BioGenSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, Chunk & a_DestChunk)
{
cChunkDef::BiomeMap biomes;
{
QMutexLocker lock(&m_Mtx);
m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, biomes);
}
a_DestChunk->setBiomes(biomes);
int tag;
cBiomeGenPtr biomeGen = getBiomeGen(tag);
biomeGen->GenBiomes(a_ChunkX, a_ChunkZ, biomes);
releaseBiomeGen(std::move(biomeGen), tag);
a_DestChunk.setBiomes(biomes);
}
@ -40,10 +40,53 @@ void BioGenSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChu
void BioGenSource::reload()
{
int seed = m_IniFile->GetValueSetI("Seed", "Seed", 0);
bool unused = false;
QMutexLocker lock(&m_Mtx);
m_BiomeGen = cBiomeGen::CreateBiomeGen(*m_IniFile, seed, unused);
m_CurrentTag += 1;
m_BiomeGens.clear();
}
cBiomeGenPtr BioGenSource::getBiomeGen(int & a_Tag)
{
QMutexLocker lock(&m_Mtx);
a_Tag = m_CurrentTag;
if (m_BiomeGens.empty())
{
// Create a new biogen:
lock.unlock();
int seed = m_IniFile->GetValueSetI("Seed", "Seed", 0);
bool unused;
cBiomeGenPtr res = cBiomeGen::CreateBiomeGen(*m_IniFile, seed, unused);
return res;
}
else
{
// Return an existing biogen:
cBiomeGenPtr res = m_BiomeGens.back();
m_BiomeGens.pop_back();
return res;
}
}
void BioGenSource::releaseBiomeGen(cBiomeGenPtr && a_BiomeGen, int a_Tag)
{
QMutexLocker lock(&m_Mtx);
// If the tag differs, the source has been reloaded and this biogen is old, dispose:
if (a_Tag != m_CurrentTag)
{
return;
}
// The tag is the same, put the biogen back to list:
m_BiomeGens.push_back(std::move(a_BiomeGen));
}
@ -160,7 +203,7 @@ AnvilSource::AnvilSource(QString a_WorldRegionFolder) :
void AnvilSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk)
void AnvilSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, Chunk & a_DestChunk)
{
// Load the compressed data:
AString compressedChunkData = getCompressedChunkData(a_ChunkX, a_ChunkZ);
@ -200,7 +243,7 @@ void AnvilSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChun
{
biomeMap[i] = (EMCSBiome)GetBEInt(beBiomes + 4 * i);
}
a_DestChunk->setBiomes(biomeMap);
a_DestChunk.setBiomes(biomeMap);
return;
}
@ -216,7 +259,7 @@ void AnvilSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChun
{
biomeMap[i] = EMCSBiome(vanillaBiomes[i]);
}
a_DestChunk->setBiomes(biomeMap);
a_DestChunk.setBiomes(biomeMap);
}
@ -260,7 +303,7 @@ AnvilSource::AnvilFilePtr AnvilSource::getAnvilFile(int a_ChunkX, int a_ChunkZ)
// Search the cache for the file:
QMutexLocker lock(&m_Mtx);
for (auto itr = m_Files.cbegin(), end = m_Files.cend(); itr != end; ++itr)
for (auto itr = m_Files.begin(), end = m_Files.end(); itr != end; ++itr)
{
if (((*itr)->m_RegionX == RegionX) && ((*itr)->m_RegionZ == RegionZ))
{

View File

@ -10,7 +10,7 @@
// fwd:
class cBiomeGen;
typedef std::shared_ptr<cBiomeGen> cBiomeGenPtr;
typedef SharedPtr<cBiomeGen> cBiomeGenPtr;
class cIniFile;
typedef std::shared_ptr<cIniFile> cIniFilePtr;
@ -26,7 +26,7 @@ public:
/** Fills the a_DestChunk with the biomes for the specified coords.
It is expected to be thread-safe and re-entrant. Usually QThread::idealThreadCount() threads are used. */
virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk) = 0;
virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, Chunk & a_DestChunk) = 0;
/** Forces a fresh reload of the source. Useful mainly for the generator, whose underlying definition file may have been changed. */
virtual void reload() = 0;
@ -45,7 +45,7 @@ public:
BioGenSource(cIniFilePtr a_IniFile);
// ChunkSource overrides:
virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk) override;
virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, Chunk & a_DestChunk) override;
virtual void reload(void) override;
protected:
@ -53,10 +53,30 @@ protected:
cIniFilePtr m_IniFile;
/** The generator used for generating biomes. */
cBiomeGenPtr m_BiomeGen;
std::vector<cBiomeGenPtr> m_BiomeGens;
/** Guards m_BiomeGen against multithreaded access. */
/** Guards m_BiomeGens against multithreaded access. */
QMutex m_Mtx;
/** Keeps track of the current settings of the biomegens.
Incremented by one each time reload() is called. Provides the means of releasing old biomegens that were
in use while reload() was being processed and thus couldn't be changed back then. releaseBiomeGen() does
the job of filtering the biogens before reusing them. */
int m_CurrentTag;
/** Retrieves one cBiomeGenPtr from m_BiomeGens.
If there's no biogen available there, creates a new one based on the ini file.
When done with it, the caller should call releaseBiomeGen() to put the biogen back to m_BiomeGens.
a_Tag receives the value of m_CurrentTag from when the lock was held; it should be passed to
releaseBiomeGen() together with the biogen. */
cBiomeGenPtr getBiomeGen(int & a_Tag);
/** Marks the specified biogen as available for reuse (puts it back into m_BiomeGens).
a_Tag is the value of m_CurrentTag from the time when the biogen was retrieved; if it is different from
current m_CurrentTagValue, the biogen will be disposed of (because reload() has been called in the
meantime). */
void releaseBiomeGen(cBiomeGenPtr && a_BiomeGen, int a_Tag);
};
@ -70,7 +90,7 @@ public:
AnvilSource(QString a_WorldRegionFolder);
// ChunkSource overrides:
virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk) override;
virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, Chunk & a_DestChunk) override;
virtual void reload() override;
protected:

View File

@ -14,6 +14,8 @@ static const QString s_GeneratorNames[] =
QString("Checkerboard"),
QString("Constant"),
QString("DistortedVoronoi"),
QString("Grown"),
QString("GrownProt"),
QString("MultiStepMap"),
QString("TwoLevel"),
QString("Voronoi"),

View File

@ -8,12 +8,13 @@
#include <QSettings>
#include <QDirIterator>
#include <QStatusBar>
#include "src/IniFile.h"
#include "ChunkSource.h"
#include "src/IniFile.h"
#include "src/Generating/BioGen.h"
#include "src/StringCompression.h"
#include "src/WorldStorage/FastNBT.h"
#include "GeneratorSetup.h"
#include "RegionLoader.h"
@ -31,7 +32,8 @@ const double MainWindow::m_ViewZooms[] =
MainWindow::MainWindow(QWidget * parent) :
QMainWindow(parent),
m_GeneratorSetup(nullptr),
m_LineSeparator(nullptr)
m_LineSeparator(nullptr),
m_CurrentZoomLevel(2)
{
initMinecraftPath();
@ -40,6 +42,7 @@ MainWindow::MainWindow(QWidget * parent) :
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_BiomeView->setZoomLevel(m_ViewZooms[m_CurrentZoomLevel]);
m_StatusBar = new QStatusBar();
this->setStatusBar(m_StatusBar);
@ -70,7 +73,7 @@ MainWindow::MainWindow(QWidget * parent) :
MainWindow::~MainWindow()
{
RegionLoader::shutdown();
}
@ -172,7 +175,8 @@ void MainWindow::setViewZoom()
{
return;
}
double newZoom = m_ViewZooms[action->data().toInt()];
m_CurrentZoomLevel = action->data().toInt();
double newZoom = m_ViewZooms[m_CurrentZoomLevel];
m_BiomeView->setZoomLevel(newZoom);
action->setChecked(true);
}
@ -284,15 +288,11 @@ void MainWindow::createActions()
{
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()));
}
m_actViewZoom[m_CurrentZoomLevel]->setChecked(true);
}

View File

@ -12,76 +12,86 @@ TARGET = QtBiomeVisualiser
TEMPLATE = app
SOURCES +=\
MainWindow.cpp \
BiomeView.cpp \
../../src/Generating/BioGen.cpp \
../../src/VoronoiMap.cpp \
../../src/Noise.cpp \
../../src/StringUtils.cpp \
../../src/LoggerListeners.cpp \
../../src/Logger.cpp \
../../src/IniFile.cpp \
../../src/OSSupport/File.cpp \
../../src/OSSupport/CriticalSection.cpp \
../../src/OSSupport/IsThread.cpp \
../../src/BiomeDef.cpp \
ChunkCache.cpp \
ChunkSource.cpp \
ChunkLoader.cpp \
../../src/StringCompression.cpp \
../../src/WorldStorage/FastNBT.cpp \
../../lib/zlib/adler32.c \
../../lib/zlib/compress.c \
../../lib/zlib/crc32.c \
../../lib/zlib/deflate.c \
../../lib/zlib/gzclose.c \
../../lib/zlib/gzlib.c \
../../lib/zlib/gzread.c \
../../lib/zlib/gzwrite.c \
../../lib/zlib/infback.c \
../../lib/zlib/inffast.c \
../../lib/zlib/inflate.c \
../../lib/zlib/inftrees.c \
../../lib/zlib/trees.c \
../../lib/zlib/uncompr.c \
../../lib/zlib/zutil.c \
GeneratorSetup.cpp \
QtBiomeVisualiser.cpp \
QtChunk.cpp
SOURCES += \
MainWindow.cpp \
BiomeView.cpp \
../../src/Generating/BioGen.cpp \
../../src/VoronoiMap.cpp \
../../src/Noise.cpp \
../../src/StringUtils.cpp \
../../src/LoggerListeners.cpp \
../../src/Logger.cpp \
../../src/IniFile.cpp \
../../src/OSSupport/File.cpp \
../../src/OSSupport/CriticalSection.cpp \
../../src/OSSupport/IsThread.cpp \
../../src/BiomeDef.cpp \
../../src/StringCompression.cpp \
../../src/WorldStorage/FastNBT.cpp \
../../lib/zlib/adler32.c \
../../lib/zlib/compress.c \
../../lib/zlib/crc32.c \
../../lib/zlib/deflate.c \
../../lib/zlib/gzclose.c \
../../lib/zlib/gzlib.c \
../../lib/zlib/gzread.c \
../../lib/zlib/gzwrite.c \
../../lib/zlib/infback.c \
../../lib/zlib/inffast.c \
../../lib/zlib/inflate.c \
../../lib/zlib/inftrees.c \
../../lib/zlib/trees.c \
../../lib/zlib/uncompr.c \
../../lib/zlib/zutil.c \
GeneratorSetup.cpp \
QtBiomeVisualiser.cpp \
QtChunk.cpp \
RegionCache.cpp \
Region.cpp \
ChunkSource.cpp \
RegionLoader.cpp
HEADERS += \
MainWindow.h \
QtChunk.h \
Globals.h \
BiomeView.h \
../../src/Generating/BioGen.h \
../../src/Generating/IntGen.h \
../../src/Generating/ProtIntGen.h \
../../src/VoronoiMap.h \
../../src/Noise.h \
../../src/StringUtils.h \
../../src/LoggerListeners.h \
../../src/Logger.h \
../../src/IniFile.h \
../../src/OSSupport/File.h \
../../src/OSSupport/CriticalSection.h \
../../src/OSSupport/IsThread.h \
../../src/BiomeDef.h \
../../src/StringCompression.h \
../../src/WorldStorage/FastNBT.h \
../../lib/zlib/crc32.h \
../../lib/zlib/deflate.h \
../../lib/zlib/gzguts.h \
../../lib/zlib/inffast.h \
../../lib/zlib/inffixed.h \
../../lib/zlib/inflate.h \
../../lib/zlib/inftrees.h \
../../lib/zlib/trees.h \
../../lib/zlib/zconf.h \
../../lib/zlib/zlib.h \
../../lib/zlib/zutil.h \
GeneratorSetup.h \
QtChunk.h \
RegionCache.h \
Region.h \
ChunkSource.h \
RegionLoader.h
HEADERS += MainWindow.h \
Globals.h \
BiomeView.h \
../../src/Generating/BioGen.h \
../../src/VoronoiMap.h \
../../src/Noise.h \
../../src/StringUtils.h \
../../src/LoggerListeners.h \
../../src/Logger.h \
../../src/IniFile.h \
../../src/OSSupport/File.h \
../../src/OSSupport/CriticalSection.h \
../../src/OSSupport/IsThread.h \
../../src/BiomeDef.h \
ChunkCache.h \
ChunkSource.h \
ChunkLoader.h \
../../src/StringCompression.h \
../../src/WorldStorage/FastNBT.h \
../../lib/zlib/crc32.h \
../../lib/zlib/deflate.h \
../../lib/zlib/gzguts.h \
../../lib/zlib/inffast.h \
../../lib/zlib/inffixed.h \
../../lib/zlib/inflate.h \
../../lib/zlib/inftrees.h \
../../lib/zlib/trees.h \
../../lib/zlib/zconf.h \
../../lib/zlib/zlib.h \
../../lib/zlib/zutil.h \
GeneratorSetup.h \
QtChunk.h
INCLUDEPATH += $$_PRO_FILE_PWD_ \
$$_PRO_FILE_PWD_/../../lib \

View File

@ -5,138 +5,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(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)
{
@ -146,20 +14,12 @@ Chunk::Chunk() :
const uchar * Chunk::getImage(void) const
{
ASSERT(m_IsValid);
return m_Image;
}
void Chunk::setBiomes(const cChunkDef::BiomeMap & a_Biomes)
{
memcpy(m_Biomes, a_Biomes, sizeof(m_Biomes));
renderBiomes();
for (size_t idx = 0; idx < ARRAYCOUNT(a_Biomes); ++idx)
{
m_Biomes[idx] = static_cast<short>(a_Biomes[idx]);
}
m_IsValid = true;
}
@ -173,16 +33,7 @@ EMCSBiome Chunk::getBiome(int a_RelX, int a_RelZ)
{
return biInvalidBiome;
}
return cChunkDef::GetBiome(m_Biomes, a_RelX, a_RelZ);
}
void Chunk::renderBiomes()
{
biomesToImage(m_Biomes, m_Image);
return static_cast<EMCSBiome>(m_Biomes[a_RelX + 16 * a_RelZ]);
}

View File

@ -18,9 +18,6 @@ public:
/** Returns true iff the chunk data is valid - loaded or generated. */
bool isValid(void) const { return m_IsValid; }
/** Returns the image of the chunk's biomes. Assumes that the chunk is valid. */
const uchar * getImage(void) const;
/** Sets the biomes to m_Biomes and renders them into m_Image. */
void setBiomes(const cChunkDef::BiomeMap & a_Biomes);
@ -28,19 +25,16 @@ public:
Coords must be valid inside this chunk. */
EMCSBiome getBiome(int a_RelX, int a_RelZ);
/** Returns the raw biome data for this chunk. */
const short * getBiomes(void) const { return m_Biomes; }
protected:
/** Flag that specifies if the chunk data is valid - loaded or generated. */
bool m_IsValid;
/** 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();
/** Biomes comprising the chunk, in the X + 16 * Z ordering.
Typed as short to save on memory, converted automatically when needed. */
short m_Biomes[16 * 16];
};
typedef std::shared_ptr<Chunk> ChunkPtr;

View File

@ -0,0 +1,72 @@
#include "Globals.h"
#include "Region.h"
Region::Region()
{
}
Chunk & Region::getRelChunk(int a_RelChunkX, int a_RelChunkZ)
{
ASSERT(a_RelChunkX >= 0);
ASSERT(a_RelChunkZ >= 0);
ASSERT(a_RelChunkX < 32);
ASSERT(a_RelChunkZ < 32);
return m_Chunks[a_RelChunkX + a_RelChunkZ * 32];
}
int Region::getRelBiome(int a_RelBlockX, int a_RelBlockZ)
{
ASSERT(a_RelBlockX >= 0);
ASSERT(a_RelBlockZ >= 0);
ASSERT(a_RelBlockX < 512);
ASSERT(a_RelBlockZ < 512);
int chunkX = a_RelBlockX / 16;
int chunkZ = a_RelBlockZ / 16;
Chunk & chunk = m_Chunks[chunkX + 32 * chunkZ];
if (chunk.isValid())
{
return chunk.getBiome(a_RelBlockX - 16 * chunkX, a_RelBlockZ - 16 * chunkZ);
}
else
{
return biInvalidBiome;
}
}
void Region::blockToRegion(int a_BlockX, int a_BlockZ, int & a_RegionX, int & a_RegionZ)
{
a_RegionX = static_cast<int>(std::floor(static_cast<float>(a_BlockX) / 512));
a_RegionZ = static_cast<int>(std::floor(static_cast<float>(a_BlockZ) / 512));
}
void Region::chunkToRegion(int a_ChunkX, int a_ChunkZ, int & a_RegionX, int & a_RegionZ)
{
a_RegionX = static_cast<int>(std::floor(static_cast<float>(a_ChunkX) / 32));
a_RegionZ = static_cast<int>(std::floor(static_cast<float>(a_ChunkZ) / 32));
}

View File

@ -0,0 +1,46 @@
#pragma once
#include "QtChunk.h"
class Region
{
public:
Region();
/** Retrieves the chunk with the specified relative coords. */
Chunk & getRelChunk(int a_RelChunkX, int a_RelChunkZ);
/** Returns true iff the chunk data for all chunks has been loaded.
This doesn't mean that all the chunks are valid, only that the entire region has been processed and should
be displayed. */
bool isValid(void) const { return m_IsValid; }
/** Returns the biome in the block coords relative to this region.
Returns biInvalidBiome if the underlying chunk is not valid. */
int getRelBiome(int a_RelBlockX, int a_RelBlockZ);
/** Converts block coordinates into region coordinates. */
static void blockToRegion(int a_BlockX, int a_BlockZ, int & a_RegionX, int & a_RegionZ);
/** Converts chunk coordinates into region coordinates. */
static void chunkToRegion(int a_ChunkX, int a_ChunkZ, int & a_RegionX, int & a_RegionZ);
protected:
friend class RegionLoader;
Chunk m_Chunks[32 * 32];
/** True iff the data for all the chunks has been loaded.
This doesn't mean that all the chunks are valid, only that the entire region has been processed and should
be displayed. */
bool m_IsValid;
};

View File

@ -0,0 +1,138 @@
#include "Globals.h"
#include "RegionCache.h"
#include <QMutexLocker>
#include <QThreadPool>
#include "ChunkSource.h"
#include "RegionLoader.h"
#include "Region.h"
RegionCache::RegionCache(QObject * parent) :
super(parent)
{
m_Cache.setMaxCost(1024 * 1024 * 1024); // 1 GiB of memory for the cache
}
RegionPtr RegionCache::fetch(int a_RegionX, int a_RegionZ)
{
// Retrieve from the cache:
quint32 hash = getRegionHash(a_RegionX, a_RegionZ);
RegionPtr * res;
{
QMutexLocker lock(&m_Mtx);
res = m_Cache[hash];
// If succesful and region loaded, return the retrieved value:
if ((res != nullptr) && (*res)->isValid())
{
return *res;
}
}
// If the region is in cache but not valid, it means it has been already queued for rendering, do nothing now:
if (res != nullptr)
{
return RegionPtr(nullptr);
}
// There's no such item in the cache, create it now:
try
{
res = new RegionPtr(new Region);
}
catch (const std::bad_alloc &)
{
/* Allocation failed (32-bit process hit the 2 GiB barrier?)
This may happen even with the cache set to 1 GiB, because it contains shared ptrs and so they may be
held by another place in the code even when they are removed from cache.
*/
return RegionPtr(nullptr);
}
if (res == nullptr)
{
return RegionPtr(nullptr);
}
{
QMutexLocker lock(&m_Mtx);
m_Cache.insert(hash, res, sizeof(Region));
}
// Queue the region for rendering:
queueRegionRender(a_RegionX, a_RegionZ, *res);
// Return failure, the region is not yet rendered:
return RegionPtr(nullptr);
}
void RegionCache::setChunkSource(std::shared_ptr<ChunkSource> a_ChunkSource)
{
// Replace the chunk source:
m_ChunkSource = a_ChunkSource;
// Clear the cache:
QMutexLocker lock(&m_Mtx);
m_Cache.clear();
}
void RegionCache::reload()
{
assert(m_ChunkSource.get() != nullptr);
// Reload the chunk source:
m_ChunkSource->reload();
// Clear the cache:
QMutexLocker lock(&m_Mtx);
m_Cache.clear();
}
void RegionCache::gotRegion(int a_RegionX, int a_RegionZ)
{
emit regionAvailable(a_RegionX, a_RegionZ);
}
quint32 RegionCache::getRegionHash(int a_RegionX, int a_RegionZ)
{
// Simply join the two coords into a single int
// The coords will never be larger than 16-bits, so we can do this safely
return (((static_cast<quint32>(a_RegionX) & 0xffff) << 16) | (static_cast<quint32>(a_RegionZ) & 0xffff));
}
void RegionCache::queueRegionRender(int a_RegionX, int a_RegionZ, RegionPtr & a_Region)
{
// Create a new loader task:
RegionLoader * loader = new RegionLoader(a_RegionX, a_RegionZ, a_Region, m_ChunkSource);
connect(loader, SIGNAL(loaded(int, int)), this, SLOT(gotRegion(int, int)));
QThreadPool::globalInstance()->start(loader);
}

View File

@ -9,8 +9,9 @@
class Chunk;
typedef std::shared_ptr<Chunk> ChunkPtr;
// fwd:
class Region;
typedef std::shared_ptr<Region> RegionPtr;
class ChunkSource;
@ -18,19 +19,19 @@ class ChunkSource;
/** Caches chunk data for reuse */
class ChunkCache :
/** Caches regions' chunk data for reuse */
class RegionCache :
public QObject
{
typedef QObject super;
Q_OBJECT
public:
explicit ChunkCache(QObject * parent = NULL);
explicit RegionCache(QObject * parent = NULL);
/** Retrieves the specified chunk from the cache.
Only returns valid chunks; if the chunk is invalid, queues it for rendering and returns an empty ptr. */
ChunkPtr fetch(int a_ChunkX, int a_ChunkZ);
/** Retrieves the specified region from the cache.
Only returns valid regions; if the region is invalid, queues it for rendering and returns an empty ptr. */
RegionPtr fetch(int a_RegionX, int a_RegionZ);
/** Replaces the chunk source used by the biome view to get the chunk biome data.
The cache is then invalidated. */
@ -43,16 +44,16 @@ public:
void reload();
signals:
void chunkAvailable(int a_ChunkX, int a_ChunkZ);
void regionAvailable(int a_RegionX, int a_RegionZ);
protected slots:
void gotChunk(int a_ChunkX, int a_ChunkZ);
void gotRegion(int a_RegionX, int a_RegionZ);
protected:
/** The cache of the chunks */
QCache<quint32, ChunkPtr> m_Cache;
QCache<quint32, RegionPtr> m_Cache;
/** Locks te cache against multithreaded access */
/** Locks the cache against multithreaded access */
QMutex m_Mtx;
/** The source used to get the biome data. */
@ -60,10 +61,10 @@ protected:
/** Returns the hash used by the chunk in the cache */
quint32 getChunkHash(int a_ChunkX, int a_ChunkZ);
quint32 getRegionHash(int a_RegionX, int a_RegionZ);
/** Queues the specified chunk for rendering by m_ChunkSource. */
void queueChunkRender(int a_ChunkX, int a_ChunkZ, ChunkPtr & a_Chunk);
/** Queues the specified region for rendering by m_RegionSource. */
void queueRegionRender(int a_RegionX, int a_RegionZ, RegionPtr & a_Region);
};

View File

@ -0,0 +1,49 @@
#include "Globals.h"
#include "RegionLoader.h"
#include "ChunkSource.h"
#include "Region.h"
volatile bool RegionLoader::m_IsShuttingDown = false;
RegionLoader::RegionLoader(int a_RegionX, int a_RegionZ, RegionPtr a_Region, ChunkSourcePtr a_ChunkSource) :
m_RegionX(a_RegionX),
m_RegionZ(a_RegionZ),
m_Region(a_Region),
m_ChunkSource(a_ChunkSource)
{
}
void RegionLoader::run()
{
// Load all the chunks in this region:
for (int z = 0; z < 32; z++)
{
for (int x = 0; x < 32; x++)
{
m_ChunkSource->getChunkBiomes(m_RegionX * 32 + x, m_RegionZ * 32 + z, m_Region->getRelChunk(x, z));
if (m_IsShuttingDown)
{
return;
}
}
}
m_Region->m_IsValid = true;
emit loaded(m_RegionX, m_RegionZ);
}

View File

@ -0,0 +1,56 @@
#pragma once
#include <QObject>
#include <QRunnable>
#include <memory>
// fwd:
class Region;
typedef std::shared_ptr<Region> RegionPtr;
class ChunkSource;
typedef std::shared_ptr<ChunkSource> ChunkSourcePtr;
class RegionLoader :
public QObject,
public QRunnable
{
Q_OBJECT
public:
RegionLoader(int a_RegionX, int a_RegionZ, RegionPtr a_Region, ChunkSourcePtr a_ChunkSource);
virtual ~RegionLoader() {}
/** Signals to all loaders that the app is shutting down and the loading should be aborted. */
static void shutdown() { m_IsShuttingDown = true; }
signals:
void loaded(int a_RegionX, int a_RegionZ);
protected:
virtual void run() override;
private:
/** Coords of the region to be loaded. */
int m_RegionX, m_RegionZ;
/** The region to be loaded. */
RegionPtr m_Region;
/** The chunk source to be used for individual chunks within the region. */
ChunkSourcePtr m_ChunkSource;
/** Flag that is set upon app exit to terminate the queued loaders faster. */
static volatile bool m_IsShuttingDown;
};

11
app.yml Normal file
View File

@ -0,0 +1,11 @@
name: MCServer
image: ubuntu-14-04-x64
config:
#cloud-config
packages:
- curl
- screen
runcmd:
- mkdir /minecraft
- cd /minecraft && curl -s https://raw.githubusercontent.com/mc-server/MCServer/master/easyinstall.sh | sh
- cd /minecraft/MCServer && screen -S mcserver -d -m ./MCServer

View File

@ -247,7 +247,11 @@ public:
template <typename FnT, typename... Args>
bool Call(const FnT & a_Function, Args &&... args)
{
PushFunction(a_Function);
if (!PushFunction(a_Function))
{
// Pushing the function failed
return false;
}
return PushCallPop(args...);
}

View File

@ -160,3 +160,65 @@ bool IsBiomeNoDownfall(EMCSBiome a_Biome)
}
}
}
bool IsBiomeVeryCold(EMCSBiome a_Biome)
{
switch (a_Biome)
{
case biFrozenOcean:
case biFrozenRiver:
case biIcePlains:
case biIceMountains:
case biColdBeach:
case biColdTaiga:
case biColdTaigaHills:
case biIcePlainsSpikes:
case biColdTaigaM:
{
return true;
}
default:
{
return false;
}
}
}
bool IsBiomeCold(EMCSBiome a_Biome)
{
switch (a_Biome)
{
case biExtremeHills:
case biTaiga:
case biTaigaHills:
case biExtremeHillsEdge:
case biStoneBeach:
case biMegaTaiga:
case biMegaTaigaHills:
case biExtremeHillsPlus:
case biExtremeHillsM:
case biTaigaM:
case biColdTaigaM:
case biMegaSpruceTaiga:
case biMegaSpruceTaigaHills:
case biExtremeHillsPlusM:
{
return true;
}
default:
{
return false;
}
}
}

View File

@ -113,5 +113,20 @@ extern AString BiomeToString(int a_Biome);
/** Returns true if the biome has no downfall - deserts and savannas */
extern bool IsBiomeNoDownfall(EMCSBiome a_Biome);
/** Returns true if the biome is an ocean biome. */
inline bool IsBiomeOcean(int a_Biome)
{
return ((a_Biome == biOcean) || (a_Biome == biDeepOcean));
}
/** Returns true if the biome is very cold
(has snow on ground everywhere, turns top water to ice, has snowfall instead of rain everywhere).
Doesn't report mildly cold biomes (where it snows above certain elevation), use IsBiomeCold() for those. */
extern bool IsBiomeVeryCold(EMCSBiome a_Biome);
/** Returns true if the biome is cold
(has snow and snowfall at higher elevations but not at regular heights).
Doesn't report Very Cold biomes, use IsBiomeVeryCold() for those. */
extern bool IsBiomeCold(EMCSBiome a_Biome);
// tolua_end

View File

@ -217,7 +217,12 @@ BLOCKTYPE BlockStringToType(const AString & a_BlockTypeString)
bool StringToItem(const AString & a_ItemTypeString, cItem & a_Item)
{
return gsBlockIDMap.ResolveItem(TrimString(a_ItemTypeString), a_Item);
AString ItemName = TrimString(a_ItemTypeString);
if (ItemName.substr(0, 10) == "minecraft:")
{
ItemName = ItemName.substr(10);
}
return gsBlockIDMap.ResolveItem(ItemName, a_Item);
}

View File

@ -1,7 +1,13 @@
#pragma once
// The following hackery is to allow typed C++ enum for C++ code, yet have ToLua process the values.
// ToLua doesn't understand typed enums, so we use preprocessor to hide it from ToLua.
enum ENUM_BLOCK_ID : BLOCKTYPE
#if 0
enum ENUM_BLOCK_ID // tolua_export
#endif
// tolua_begin
enum ENUM_BLOCK_ID
{
E_BLOCK_AIR = 0,
E_BLOCK_STONE = 1,
@ -221,6 +227,10 @@ enum ENUM_BLOCK_ID
};
// tolua_end
// tolua_begin
enum ENUM_ITEM_ID
{

View File

@ -822,6 +822,7 @@ void cChunkMap::WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_M
int MinChunkX, MinChunkZ, MaxChunkX, MaxChunkZ;
cChunkDef::BlockToChunk(a_MinBlockX, a_MinBlockZ, MinChunkX, MinChunkZ);
cChunkDef::BlockToChunk(a_MaxBlockX, a_MaxBlockZ, MaxChunkX, MaxChunkZ);
cCSLock Lock(m_CSLayers);
for (int z = MinChunkZ; z <= MaxChunkZ; z++)
{
int MinZ = std::max(a_MinBlockZ, z * cChunkDef::Width);

View File

@ -184,7 +184,7 @@ void cChunkSender::Execute(void)
while (!m_ShouldTerminate)
{
cCSLock Lock(m_CS);
while (m_ChunksReady.empty() && m_SendChunksLowPriority.empty() && m_SendChunksHighPriority.empty())
while (m_ChunksReady.empty() && m_SendChunksLowPriority.empty() && m_SendChunksMediumPriority.empty() && m_SendChunksHighPriority.empty())
{
int RemoveCount = m_RemoveCount;
m_RemoveCount = 0;

View File

@ -557,7 +557,7 @@ void cClientHandle::UnloadOutOfRangeChunks(void)
for (cChunkCoordsList::iterator itr = ChunksToRemove.begin(); itr != ChunksToRemove.end(); ++itr)
{
m_Player->GetWorld()->RemoveChunkClient(itr->m_ChunkX, itr->m_ChunkZ, this);
m_Protocol->SendUnloadChunk(itr->m_ChunkX, itr->m_ChunkZ);
SendUnloadChunk(itr->m_ChunkX, itr->m_ChunkZ);
}
}

View File

@ -5,6 +5,10 @@
#include "Globals.h"
#include "BioGen.h"
#include <chrono>
#include <iostream>
#include "IntGen.h"
#include "ProtIntGen.h"
#include "../IniFile.h"
#include "../LinearUpscale.h"
@ -916,6 +920,214 @@ void cBioGenTwoLevel::InitializeBiomeGen(cIniFile & a_IniFile)
////////////////////////////////////////////////////////////////////////////////
// cBioGenGrown:
class cBioGenGrown:
public cBiomeGen
{
public:
cBioGenGrown(int a_Seed)
{
auto FinalRivers =
std::make_shared<cIntGenSmooth<8>> (a_Seed + 1,
std::make_shared<cIntGenZoom <10>> (a_Seed + 2,
std::make_shared<cIntGenRiver <7>> (a_Seed + 3,
std::make_shared<cIntGenZoom <9>> (a_Seed + 4,
std::make_shared<cIntGenSmooth<6>> (a_Seed + 5,
std::make_shared<cIntGenZoom <8>> (a_Seed + 8,
std::make_shared<cIntGenSmooth<6>> (a_Seed + 5,
std::make_shared<cIntGenZoom <8>> (a_Seed + 9,
std::make_shared<cIntGenSmooth<6>> (a_Seed + 5,
std::make_shared<cIntGenZoom <8>> (a_Seed + 10,
std::make_shared<cIntGenSmooth<6>> (a_Seed + 5,
std::make_shared<cIntGenSmooth<8>> (a_Seed + 6,
std::make_shared<cIntGenZoom <10>> (a_Seed + 11,
std::make_shared<cIntGenChoice<2, 7>>(a_Seed + 12
))))))))))))));
auto alteration =
std::make_shared<cIntGenZoom <8>>(a_Seed,
std::make_shared<cIntGenLandOcean<6>>(a_Seed, 20
));
auto alteration2 =
std::make_shared<cIntGenZoom <8>>(a_Seed + 1,
std::make_shared<cIntGenZoom <6>>(a_Seed + 2,
std::make_shared<cIntGenZoom <5>>(a_Seed + 1,
std::make_shared<cIntGenZoom <4>>(a_Seed + 2,
std::make_shared<cIntGenLandOcean<4>>(a_Seed + 1, 10
)))));
auto FinalBiomes =
std::make_shared<cIntGenSmooth <8>> (a_Seed + 1,
std::make_shared<cIntGenZoom <10>>(a_Seed + 15,
std::make_shared<cIntGenSmooth <7>> (a_Seed + 1,
std::make_shared<cIntGenZoom <9>> (a_Seed + 16,
std::make_shared<cIntGenBeaches <6>> (
std::make_shared<cIntGenZoom <8>> (a_Seed + 1,
std::make_shared<cIntGenAddIslands <6>> (a_Seed + 2004, 10,
std::make_shared<cIntGenAddToOcean <6>> (a_Seed + 10, 500, biDeepOcean,
std::make_shared<cIntGenReplaceRandomly<8>> (a_Seed + 1, biPlains, biSunflowerPlains, 20,
std::make_shared<cIntGenMBiomes <8>> (a_Seed + 5, alteration2,
std::make_shared<cIntGenAlternateBiomes<8>> (a_Seed + 1, alteration,
std::make_shared<cIntGenBiomeEdges <8>> (a_Seed + 3,
std::make_shared<cIntGenZoom <10>>(a_Seed + 2,
std::make_shared<cIntGenZoom <7>> (a_Seed + 4,
std::make_shared<cIntGenReplaceRandomly<5>> (a_Seed + 99, biIcePlains, biIcePlainsSpikes, 50,
std::make_shared<cIntGenZoom <5>> (a_Seed + 8,
std::make_shared<cIntGenAddToOcean <4>> (a_Seed + 10, 300, biDeepOcean,
std::make_shared<cIntGenAddToOcean <6>> (a_Seed + 9, 8, biMushroomIsland,
std::make_shared<cIntGenBiomes <8>> (a_Seed + 3000,
std::make_shared<cIntGenAddIslands <8>> (a_Seed + 2000, 200,
std::make_shared<cIntGenZoom <8>> (a_Seed + 5,
std::make_shared<cIntGenRareBiomeGroups<6>> (a_Seed + 5, 50,
std::make_shared<cIntGenBiomeGroupEdges<6>> (
std::make_shared<cIntGenAddIslands <8>> (a_Seed + 2000, 200,
std::make_shared<cIntGenZoom <8>> (a_Seed + 7,
std::make_shared<cIntGenSetRandomly <6>> (a_Seed + 8, 50, bgOcean,
std::make_shared<cIntGenReplaceRandomly<6>> (a_Seed + 101, bgIce, bgTemperate, 150,
std::make_shared<cIntGenAddIslands <6>> (a_Seed + 2000, 200,
std::make_shared<cIntGenSetRandomly <6>> (a_Seed + 9, 50, bgOcean,
std::make_shared<cIntGenZoom <6>> (a_Seed + 10,
std::make_shared<cIntGenLandOcean <5>> (a_Seed + 100, 30
)))))))))))))))))))))))))))))));
m_Gen =
std::make_shared<cIntGenSmooth <16>>(a_Seed,
std::make_shared<cIntGenZoom <18>>(a_Seed,
std::make_shared<cIntGenSmooth <11>>(a_Seed,
std::make_shared<cIntGenZoom <13>>(a_Seed,
std::make_shared<cIntGenMixRivers<8>> (
FinalBiomes, FinalRivers
)))));
}
virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_Biomes) override
{
cIntGen<16, 16>::Values vals;
m_Gen->GetInts(a_ChunkX * cChunkDef::Width, a_ChunkZ * cChunkDef::Width, vals);
for (int z = 0; z < cChunkDef::Width; z++)
{
for (int x = 0; x < cChunkDef::Width; x++)
{
cChunkDef::SetBiome(a_Biomes, x, z, (EMCSBiome)vals[x + cChunkDef::Width * z]);
}
}
}
protected:
std::shared_ptr<cIntGen<16, 16>> m_Gen;
};
////////////////////////////////////////////////////////////////////////////////
// cBioGenGrown:
class cBioGenProtGrown:
public cBiomeGen
{
public:
cBioGenProtGrown(int a_Seed)
{
auto FinalRivers =
std::make_shared<cProtIntGenSmooth>(a_Seed + 1,
std::make_shared<cProtIntGenZoom >(a_Seed + 2,
std::make_shared<cProtIntGenRiver >(a_Seed + 3,
std::make_shared<cProtIntGenZoom >(a_Seed + 4,
std::make_shared<cProtIntGenSmooth>(a_Seed + 5,
std::make_shared<cProtIntGenZoom >(a_Seed + 8,
std::make_shared<cProtIntGenSmooth>(a_Seed + 5,
std::make_shared<cProtIntGenZoom >(a_Seed + 9,
std::make_shared<cProtIntGenSmooth>(a_Seed + 5,
std::make_shared<cProtIntGenZoom >(a_Seed + 10,
std::make_shared<cProtIntGenSmooth>(a_Seed + 5,
std::make_shared<cProtIntGenSmooth>(a_Seed + 6,
std::make_shared<cProtIntGenZoom >(a_Seed + 11,
std::make_shared<cProtIntGenChoice>(a_Seed + 12, 2
))))))))))))));
auto alteration =
std::make_shared<cProtIntGenZoom >(a_Seed,
std::make_shared<cProtIntGenLandOcean>(a_Seed, 20
));
auto alteration2 =
std::make_shared<cProtIntGenZoom >(a_Seed + 1,
std::make_shared<cProtIntGenZoom >(a_Seed + 2,
std::make_shared<cProtIntGenZoom >(a_Seed + 1,
std::make_shared<cProtIntGenZoom >(a_Seed + 2,
std::make_shared<cProtIntGenLandOcean>(a_Seed + 1, 10
)))));
auto FinalBiomes =
std::make_shared<cProtIntGenSmooth >(a_Seed + 1,
std::make_shared<cProtIntGenZoom >(a_Seed + 15,
std::make_shared<cProtIntGenSmooth >(a_Seed + 1,
std::make_shared<cProtIntGenZoom >(a_Seed + 16,
std::make_shared<cProtIntGenBeaches >(
std::make_shared<cProtIntGenZoom >(a_Seed + 1,
std::make_shared<cProtIntGenAddIslands >(a_Seed + 2004, 10,
std::make_shared<cProtIntGenAddToOcean >(a_Seed + 10, 500, biDeepOcean,
std::make_shared<cProtIntGenReplaceRandomly>(a_Seed + 1, biPlains, biSunflowerPlains, 20,
std::make_shared<cProtIntGenMBiomes >(a_Seed + 5, alteration2,
std::make_shared<cProtIntGenAlternateBiomes>(a_Seed + 1, alteration,
std::make_shared<cProtIntGenBiomeEdges >(a_Seed + 3,
std::make_shared<cProtIntGenZoom >(a_Seed + 2,
std::make_shared<cProtIntGenZoom >(a_Seed + 4,
std::make_shared<cProtIntGenReplaceRandomly>(a_Seed + 99, biIcePlains, biIcePlainsSpikes, 50,
std::make_shared<cProtIntGenZoom >(a_Seed + 8,
std::make_shared<cProtIntGenAddToOcean >(a_Seed + 10, 300, biDeepOcean,
std::make_shared<cProtIntGenAddToOcean >(a_Seed + 9, 8, biMushroomIsland,
std::make_shared<cProtIntGenBiomes >(a_Seed + 3000,
std::make_shared<cProtIntGenAddIslands >(a_Seed + 2000, 200,
std::make_shared<cProtIntGenZoom >(a_Seed + 5,
std::make_shared<cProtIntGenRareBiomeGroups>(a_Seed + 5, 50,
std::make_shared<cProtIntGenBiomeGroupEdges>(
std::make_shared<cProtIntGenAddIslands >(a_Seed + 2000, 200,
std::make_shared<cProtIntGenZoom >(a_Seed + 7,
std::make_shared<cProtIntGenSetRandomly >(a_Seed + 8, 50, bgOcean,
std::make_shared<cProtIntGenReplaceRandomly>(a_Seed + 101, bgIce, bgTemperate, 150,
std::make_shared<cProtIntGenAddIslands >(a_Seed + 2000, 200,
std::make_shared<cProtIntGenSetRandomly >(a_Seed + 9, 50, bgOcean,
std::make_shared<cProtIntGenZoom >(a_Seed + 10,
std::make_shared<cProtIntGenLandOcean >(a_Seed + 100, 30
)))))))))))))))))))))))))))))));
m_Gen =
std::make_shared<cProtIntGenSmooth >(a_Seed,
std::make_shared<cProtIntGenZoom >(a_Seed,
std::make_shared<cProtIntGenSmooth >(a_Seed,
std::make_shared<cProtIntGenZoom >(a_Seed,
std::make_shared<cProtIntGenMixRivers>(
FinalBiomes, FinalRivers
)))));
}
virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_Biomes) override
{
int vals[16 * 16];
m_Gen->GetInts(a_ChunkX * cChunkDef::Width, a_ChunkZ * cChunkDef::Width, 16, 16, vals);
for (int z = 0; z < cChunkDef::Width; z++)
{
for (int x = 0; x < cChunkDef::Width; x++)
{
cChunkDef::SetBiome(a_Biomes, x, z, (EMCSBiome)vals[x + cChunkDef::Width * z]);
}
}
}
protected:
std::shared_ptr<cProtIntGen> m_Gen;
};
////////////////////////////////////////////////////////////////////////////////
// cBiomeGen:
@ -952,6 +1164,14 @@ cBiomeGenPtr cBiomeGen::CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool &
{
res = new cBioGenTwoLevel(a_Seed);
}
else if (NoCaseCompare(BiomeGenName, "grown") == 0)
{
res = new cBioGenGrown(a_Seed);
}
else if (NoCaseCompare(BiomeGenName, "grownprot") == 0)
{
res = new cBioGenProtGrown(a_Seed);
}
else
{
if (NoCaseCompare(BiomeGenName, "multistepmap") != 0)
@ -981,3 +1201,51 @@ cBiomeGenPtr cBiomeGen::CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool &
////////////////////////////////////////////////////////////////////////////////
// Performance tests:
// Change to 1 to enable the perf test:
#if 0
class cBioGenPerfTest
{
public:
cBioGenPerfTest()
{
std::cout << "BioGen performance tests commencing, please wait..." << std::endl;
TestGen("MultiStepMap", std::make_unique<cBioGenMultiStepMap>(1).get());
TestGen("Grown", std::make_unique<cBioGenGrown>(1).get());
TestGen("GrownProt", std::make_unique<cBioGenProtGrown>(1).get());
std::cout << "BioGen performance tests complete." << std::endl;
}
protected:
void TestGen(const AString && a_GenName, cBiomeGen * a_BioGen)
{
// Initialize the default settings for the generator:
cIniFile iniFile;
a_BioGen->InitializeBiomeGen(iniFile);
// Generate the biomes:
auto start = std::chrono::system_clock::now();
for (int z = 0; z < 100; z++)
{
for (int x = 0; x < 100; x++)
{
cChunkDef::BiomeMap biomes;
a_BioGen->GenBiomes(x, z, biomes);
} // for x
} // for z
auto dur = std::chrono::system_clock::now() - start;
double milliseconds = static_cast<double>((std::chrono::duration_cast<std::chrono::milliseconds>(dur)).count());
std::cout << a_GenName << ": " << 1000.0 * 100.0 * 100.0 / milliseconds << " chunks per second" << std::endl;
}
} g_BioGenPerfTest;
#endif

View File

@ -46,6 +46,7 @@ SET (HDRS
FinishGen.h
GridStructGen.h
HeiGen.h
IntGen.h
MineShafts.h
NetherFortGen.h
Noise3DGenerator.h
@ -53,6 +54,7 @@ SET (HDRS
PieceGenerator.h
Prefab.h
PrefabPiecePool.h
ProtIntGen.h
RainbowRoadsGen.h
Ravines.h
RoughRavines.h

View File

@ -227,15 +227,15 @@ const cDistortedHeightmap::sGenParam cDistortedHeightmap::m_GenParam[256] =
/* biMesaPlateau */ { 2.0f, 2.0f}, // 39
// biomes 40 .. 128 are unused, 89 empty placeholders here:
{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 40 .. 49
{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 50 .. 59
{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 60 .. 69
{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 70 .. 79
{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 80 .. 89
{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 90 .. 99
{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 100 .. 109
{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 110 .. 119
{}, {}, {}, {}, {}, {}, {}, {}, {}, // 120 .. 128
{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 40 .. 49
{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 50 .. 59
{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 60 .. 69
{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 70 .. 79
{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 80 .. 89
{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 90 .. 99
{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 100 .. 109
{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 110 .. 119
{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 120 .. 128
// Release 1.7 /* biome variants:
/* biSunflowerPlains */ { 1.0f, 1.0f}, // 129
@ -246,22 +246,22 @@ const cDistortedHeightmap::sGenParam cDistortedHeightmap::m_GenParam[256] =
/* biSwamplandM */ { 0.0f, 0.0f}, // 134
// Biomes 135 .. 139 unused, 5 empty placeholders here:
{}, {}, {}, {}, {}, // 135 .. 139
{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 135 .. 139
/* biIcePlainsSpikes */ { 1.0f, 1.0f}, // 140
// Biomes 141 .. 148 unused, 8 empty placeholders here:
{}, {}, {}, {}, {}, {}, {}, {}, // 141 .. 148
{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 141 .. 148
/* biJungleM */ { 4.0f, 4.0f}, // 149
{}, // 150
{0.0f, 0.0f}, // 150
/* biJungleEdgeM */ { 3.0f, 3.0f}, // 151
{}, {}, {}, // 152 .. 154
{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 152 .. 154
/* biBirchForestM */ { 3.0f, 3.0f}, // 155
/* biBirchForestHillsM */ { 5.0f, 5.0f}, // 156
/* biRoofedForestM */ { 2.0f, 2.0f}, // 157
/* biColdTaigaM */ { 1.0f, 1.0f}, // 158
{}, // 159
{0.0f, 0.0f}, // 159
/* biMegaSpruceTaiga */ { 3.0f, 3.0f}, // 160
/* biMegaSpruceTaigaHills */ { 3.0f, 3.0f}, // 161
/* biExtremeHillsPlusM */ {32.0f, 32.0f}, // 162

View File

@ -414,6 +414,11 @@ void cFinishGenSnow::GenFinish(cChunkDesc & a_ChunkDesc)
}
break;
}
default:
{
// There's no snow in the other biomes.
break;
}
}
}
} // for z
@ -454,6 +459,11 @@ void cFinishGenIce::GenFinish(cChunkDesc & a_ChunkDesc)
}
break;
}
default:
{
// No icy water in other biomes.
break;
}
}
}
} // for z

View File

@ -16,81 +16,6 @@
////////////////////////////////////////////////////////////////////////////////
// cTerrainHeightGen:
cTerrainHeightGenPtr cTerrainHeightGen::CreateHeightGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault)
{
AString HeightGenName = a_IniFile.GetValueSet("Generator", "HeightGen", "");
if (HeightGenName.empty())
{
LOGWARN("[Generator] HeightGen value not set in world.ini, using \"Biomal\".");
HeightGenName = "Biomal";
}
a_CacheOffByDefault = false;
cTerrainHeightGen * res = nullptr;
if (NoCaseCompare(HeightGenName, "flat") == 0)
{
res = new cHeiGenFlat;
a_CacheOffByDefault = true; // We're generating faster than a cache would retrieve data
}
else if (NoCaseCompare(HeightGenName, "classic") == 0)
{
res = new cHeiGenClassic(a_Seed);
}
else if (NoCaseCompare(HeightGenName, "DistortedHeightmap") == 0)
{
res = new cDistortedHeightmap(a_Seed, a_BiomeGen);
}
else if (NoCaseCompare(HeightGenName, "End") == 0)
{
res = new cEndGen(a_Seed);
}
else if (NoCaseCompare(HeightGenName, "Mountains") == 0)
{
res = new cHeiGenMountains(a_Seed);
}
else if (NoCaseCompare(HeightGenName, "Noise3D") == 0)
{
res = new cNoise3DComposable(a_Seed);
}
else if (NoCaseCompare(HeightGenName, "biomal") == 0)
{
res = new cHeiGenBiomal(a_Seed, a_BiomeGen);
/*
// Performance-testing:
LOGINFO("Measuring performance of cHeiGenBiomal...");
clock_t BeginTick = clock();
for (int x = 0; x < 500; x++)
{
cChunkDef::HeightMap Heights;
res->GenHeightMap(x * 5, x * 5, Heights);
}
clock_t Duration = clock() - BeginTick;
LOGINFO("HeightGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC);
//*/
}
else
{
// No match found, force-set the default and retry
LOGWARN("Unknown HeightGen \"%s\", using \"Biomal\" instead.", HeightGenName.c_str());
a_IniFile.DeleteValue("Generator", "HeightGen");
a_IniFile.SetValue("Generator", "HeightGen", "Biomal");
return CreateHeightGen(a_IniFile, a_BiomeGen, a_Seed, a_CacheOffByDefault);
}
// Read the settings:
res->InitializeHeightGen(a_IniFile);
return cTerrainHeightGenPtr(res);
}
////////////////////////////////////////////////////////////////////////////////
// cHeiGenFlat:
@ -430,15 +355,15 @@ const cHeiGenBiomal::sGenParam cHeiGenBiomal::m_GenParam[256] =
/* biMesaPlateau */ { 0.1f, 1.0f, 0.05f, 1.5f, 0.01f, 4.0f, 80},
// biomes 40 .. 128 are unused, 89 empty placeholders here:
{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 40 .. 49
{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 50 .. 59
{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 60 .. 69
{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 70 .. 79
{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 80 .. 89
{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 90 .. 99
{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 100 .. 109
{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, // 110 .. 119
{}, {}, {}, {}, {}, {}, {}, {}, {}, // 120 .. 128
{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 40 .. 49
{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 50 .. 59
{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 60 .. 69
{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 70 .. 79
{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 80 .. 89
{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 90 .. 99
{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 100 .. 109
{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 110 .. 119
{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 120 .. 128
/* biSunflowerPlains */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 129
/* biDesertM */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 130
@ -448,22 +373,22 @@ const cHeiGenBiomal::sGenParam cHeiGenBiomal::m_GenParam[256] =
/* biSwamplandM */ { 1.0f, 3.0f, 1.10f, 7.0f, 0.01f, 0.01f, 60}, // 134
// Biomes 135 .. 139 unused, 5 empty placeholders here:
{}, {}, {}, {}, {}, // 135 .. 139
{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 135 .. 139
/* biIcePlainsSpikes */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 140
// Biomes 141 .. 148 unused, 8 empty placeholders here:
{}, {}, {}, {}, {}, {}, {}, {}, // 141 .. 148
{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 141 .. 148
/* biJungleM */ { 0.1f, 3.0f, 0.05f, 6.0f, 0.01f, 6.0f, 70}, // 149
{}, // 150
{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 150
/* biJungleEdgeM */ { 0.1f, 3.0f, 0.05f, 6.0f, 0.01f, 6.0f, 70}, // 151
{}, {}, {}, // 152 .. 154
{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 152 .. 154
/* biBirchForestM */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70}, // 155
/* biBirchForestHillsM */ { 0.2f, 2.0f, 0.05f, 10.0f, 0.01f, 8.0f, 80}, // 156
/* biRoofedForestM */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70}, // 157
/* biColdTaigaM */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70}, // 158
{}, // 159
{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0}, // 159
/* biMegaSpruceTaiga */ { 0.1f, 1.0f, 0.05f, 2.0f, 0.01f, 4.0f, 70}, // 160
/* biMegaSpruceTaigaHills */ { 0.2f, 2.0f, 0.05f, 10.0f, 0.01f, 8.0f, 80}, // 161
/* biExtremeHillsPlusM */ { 0.2f, 4.0f, 0.05f, 20.0f, 0.01f, 16.0f, 120}, // 162
@ -611,3 +536,283 @@ NOISE_DATATYPE cHeiGenBiomal::GetHeightAt(int a_RelX, int a_RelZ, int a_ChunkX,
////////////////////////////////////////////////////////////////////////////////
// cHeiGenMinMax:
class cHeiGenMinMax:
public cTerrainHeightGen
{
typedef cTerrainHeightGen super;
/** Size of the averaging process, in columns (for each direction). Must be less than 16. */
static const int AVERAGING_SIZE = 4;
public:
cHeiGenMinMax(int a_Seed, cBiomeGenPtr a_BiomeGen):
m_Noise(a_Seed),
m_BiomeGen(a_BiomeGen),
m_TotalWeight(0)
{
// Initialize the weights:
for (int z = 0; z <= AVERAGING_SIZE * 2; z++)
{
for (int x = 0; x <= AVERAGING_SIZE * 2; x++)
{
m_Weights[z][x] = 1 + 2 * AVERAGING_SIZE - std::abs(x - AVERAGING_SIZE) - std::abs(z - AVERAGING_SIZE);
m_TotalWeight += m_Weights[z][x];
}
}
// Initialize the Perlin generator:
m_Perlin.AddOctave(0.04f, 0.2f);
m_Perlin.AddOctave(0.02f, 0.1f);
m_Perlin.AddOctave(0.01f, 0.05f);
}
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
{
// Generate the biomes for the 3*3 neighbors:
cChunkDef::BiomeMap neighborBiomes[3][3];
for (int z = 0; z < 3; z++) for (int x = 0; x < 3; x++)
{
m_BiomeGen->GenBiomes(a_ChunkX + x - 1, a_ChunkZ + z - 1, neighborBiomes[z][x]);
}
// Get the min and max heights based on the biomes:
double minHeight[cChunkDef::Width * cChunkDef::Width];
double maxHeight[cChunkDef::Width * cChunkDef::Width];
for (int z = 0; z < cChunkDef::Width; z++)
{
for (int x = 0; x < cChunkDef::Width; x++)
{
// For each column, sum the min and max values of the neighborhood around it:
double min = 0, max = 0;
for (int relz = 0; relz <= AVERAGING_SIZE * 2; relz++)
{
int bz = z + 16 + relz - AVERAGING_SIZE; // Biome Z coord relative to the neighborBiomes start
int cz = bz / 16; // Chunk Z coord relative to the neighborBiomes start
bz = bz % 16; // Biome Z coord relative to cz in neighborBiomes
for (int relx = 0; relx <= AVERAGING_SIZE * 2; relx++)
{
int bx = x + 16 + relx - AVERAGING_SIZE; // Biome X coord relative to the neighborBiomes start
int cx = bx / 16; // Chunk X coord relative to the neighborBiomes start
bx = bx % 16; // Biome X coord relative to cz in neighborBiomes
// Get the biome's min and max heights:
double bmin, bmax;
getBiomeMinMax(cChunkDef::GetBiome(neighborBiomes[cz][cx], bx, bz), bmin, bmax);
// Add them to the total, with the weight depending on their relative position to the column:
min += bmin * m_Weights[relz][relx];
max += bmax * m_Weights[relz][relx];
} // for relx
} // for relz
minHeight[x + z * cChunkDef::Width] = min / m_TotalWeight;
maxHeight[x + z * cChunkDef::Width] = max / m_TotalWeight;
} // for x
} // for z
// Generate the base noise:
NOISE_DATATYPE noise[cChunkDef::Width * cChunkDef::Width];
NOISE_DATATYPE workspace[cChunkDef::Width * cChunkDef::Width];
NOISE_DATATYPE startX = static_cast<float>(a_ChunkX * cChunkDef::Width);
NOISE_DATATYPE endX = startX + cChunkDef::Width - 1;
NOISE_DATATYPE startZ = static_cast<float>(a_ChunkZ * cChunkDef::Width);
NOISE_DATATYPE endZ = startZ + cChunkDef::Width - 1;
m_Perlin.Generate2D(noise, 16, 16, startX, endX, startZ, endZ, workspace);
// Make the height by ranging the noise between min and max:
for (int z = 0; z < cChunkDef::Width; z++)
{
for (int x = 0; x < cChunkDef::Width; x++)
{
double min = minHeight[x + z * cChunkDef::Width];
double max = maxHeight[x + z * cChunkDef::Width];
double h = (max + min) / 2 + noise[x + z * cChunkDef::Width] * (max - min);
cChunkDef::SetHeight(a_HeightMap, x, z, static_cast<HEIGHTTYPE>(h));
}
}
}
virtual void InitializeHeightGen(cIniFile & a_IniFile)
{
// No settings available
}
protected:
cNoise m_Noise;
cPerlinNoise m_Perlin;
/** The biome generator to query for the underlying biomes. */
cBiomeGenPtr m_BiomeGen;
/** Weights applied to each of the min / max values in the neighborhood of the currently evaluated column. */
double m_Weights[AVERAGING_SIZE * 2 + 1][AVERAGING_SIZE * 2 + 1];
/** Sum of all the m_Weights items. */
double m_TotalWeight;
/** Returns the minimum and maximum heights for the given biome. */
void getBiomeMinMax(EMCSBiome a_Biome, double & a_Min, double & a_Max)
{
switch (a_Biome)
{
case biBeach: a_Min = 61; a_Max = 64; break;
case biBirchForest: a_Min = 63; a_Max = 75; break;
case biBirchForestHills: a_Min = 63; a_Max = 90; break;
case biBirchForestHillsM: a_Min = 63; a_Max = 90; break;
case biBirchForestM: a_Min = 63; a_Max = 75; break;
case biColdBeach: a_Min = 61; a_Max = 64; break;
case biColdTaiga: a_Min = 63; a_Max = 75; break;
case biColdTaigaHills: a_Min = 63; a_Max = 90; break;
case biColdTaigaM: a_Min = 63; a_Max = 75; break;
case biDeepOcean: a_Min = 30; a_Max = 60; break;
case biDesert: a_Min = 63; a_Max = 70; break;
case biDesertHills: a_Min = 63; a_Max = 85; break;
case biDesertM: a_Min = 63; a_Max = 70; break;
case biEnd: a_Min = 10; a_Max = 100; break;
case biExtremeHills: a_Min = 60; a_Max = 120; break;
case biExtremeHillsEdge: a_Min = 63; a_Max = 100; break;
case biExtremeHillsM: a_Min = 60; a_Max = 120; break;
case biExtremeHillsPlus: a_Min = 60; a_Max = 140; break;
case biExtremeHillsPlusM: a_Min = 60; a_Max = 140; break;
case biFlowerForest: a_Min = 63; a_Max = 75; break;
case biForest: a_Min = 63; a_Max = 75; break;
case biForestHills: a_Min = 63; a_Max = 90; break;
case biFrozenOcean: a_Min = 45; a_Max = 64; break;
case biFrozenRiver: a_Min = 60; a_Max = 62; break;
case biIceMountains: a_Min = 63; a_Max = 90; break;
case biIcePlains: a_Min = 63; a_Max = 70; break;
case biIcePlainsSpikes: a_Min = 60; a_Max = 70; break;
case biJungle: a_Min = 60; a_Max = 80; break;
case biJungleEdge: a_Min = 62; a_Max = 75; break;
case biJungleEdgeM: a_Min = 62; a_Max = 75; break;
case biJungleHills: a_Min = 60; a_Max = 90; break;
case biJungleM: a_Min = 60; a_Max = 75; break;
case biMegaSpruceTaiga: a_Min = 63; a_Max = 75; break;
case biMegaSpruceTaigaHills: a_Min = 63; a_Max = 90; break;
case biMegaTaiga: a_Min = 63; a_Max = 75; break;
case biMegaTaigaHills: a_Min = 63; a_Max = 90; break;
case biMesa: a_Min = 63; a_Max = 90; break;
case biMesaBryce: a_Min = 60; a_Max = 67; break;
case biMesaPlateau: a_Min = 75; a_Max = 85; break;
case biMesaPlateauF: a_Min = 80; a_Max = 90; break;
case biMesaPlateauFM: a_Min = 80; a_Max = 90; break;
case biMesaPlateauM: a_Min = 75; a_Max = 85; break;
case biMushroomIsland: a_Min = 63; a_Max = 90; break;
case biMushroomShore: a_Min = 60; a_Max = 75; break;
case biNether: a_Min = 10; a_Max = 100; break;
case biOcean: a_Min = 45; a_Max = 64; break;
case biPlains: a_Min = 63; a_Max = 70; break;
case biRiver: a_Min = 60; a_Max = 62; break;
case biRoofedForest: a_Min = 63; a_Max = 75; break;
case biRoofedForestM: a_Min = 63; a_Max = 75; break;
case biSavanna: a_Min = 63; a_Max = 75; break;
case biSavannaM: a_Min = 63; a_Max = 80; break;
case biSavannaPlateau: a_Min = 75; a_Max = 100; break;
case biSavannaPlateauM: a_Min = 80; a_Max = 160; break;
case biStoneBeach: a_Min = 60; a_Max = 64; break;
case biSunflowerPlains: a_Min = 63; a_Max = 70; break;
case biSwampland: a_Min = 60; a_Max = 67; break;
case biSwamplandM: a_Min = 61; a_Max = 67; break;
case biTaiga: a_Min = 63; a_Max = 75; break;
case biTaigaHills: a_Min = 63; a_Max = 90; break;
case biTaigaM: a_Min = 63; a_Max = 80; break;
default:
{
ASSERT(!"Unknown biome");
a_Min = 10;
a_Max = 10;
break;
}
}
}
};
////////////////////////////////////////////////////////////////////////////////
// cTerrainHeightGen:
cTerrainHeightGenPtr cTerrainHeightGen::CreateHeightGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault)
{
AString HeightGenName = a_IniFile.GetValueSet("Generator", "HeightGen", "");
if (HeightGenName.empty())
{
LOGWARN("[Generator] HeightGen value not set in world.ini, using \"Biomal\".");
HeightGenName = "Biomal";
}
a_CacheOffByDefault = false;
cTerrainHeightGen * res = nullptr;
if (NoCaseCompare(HeightGenName, "flat") == 0)
{
res = new cHeiGenFlat;
a_CacheOffByDefault = true; // We're generating faster than a cache would retrieve data
}
else if (NoCaseCompare(HeightGenName, "classic") == 0)
{
res = new cHeiGenClassic(a_Seed);
}
else if (NoCaseCompare(HeightGenName, "DistortedHeightmap") == 0)
{
res = new cDistortedHeightmap(a_Seed, a_BiomeGen);
}
else if (NoCaseCompare(HeightGenName, "End") == 0)
{
res = new cEndGen(a_Seed);
}
else if (NoCaseCompare(HeightGenName, "MinMax") == 0)
{
res = new cHeiGenMinMax(a_Seed, a_BiomeGen);
}
else if (NoCaseCompare(HeightGenName, "Mountains") == 0)
{
res = new cHeiGenMountains(a_Seed);
}
else if (NoCaseCompare(HeightGenName, "Noise3D") == 0)
{
res = new cNoise3DComposable(a_Seed);
}
else if (NoCaseCompare(HeightGenName, "biomal") == 0)
{
res = new cHeiGenBiomal(a_Seed, a_BiomeGen);
/*
// Performance-testing:
LOGINFO("Measuring performance of cHeiGenBiomal...");
clock_t BeginTick = clock();
for (int x = 0; x < 500; x++)
{
cChunkDef::HeightMap Heights;
res->GenHeightMap(x * 5, x * 5, Heights);
}
clock_t Duration = clock() - BeginTick;
LOGINFO("HeightGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC);
//*/
}
else
{
// No match found, force-set the default and retry
LOGWARN("Unknown HeightGen \"%s\", using \"Biomal\" instead.", HeightGenName.c_str());
a_IniFile.DeleteValue("Generator", "HeightGen");
a_IniFile.SetValue("Generator", "HeightGen", "Biomal");
return CreateHeightGen(a_IniFile, a_BiomeGen, a_Seed, a_CacheOffByDefault);
}
// Read the settings:
res->InitializeHeightGen(a_IniFile);
return cTerrainHeightGenPtr(res);
}

1406
src/Generating/IntGen.h Normal file

File diff suppressed because it is too large Load Diff

1351
src/Generating/ProtIntGen.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,7 @@
// Email: Shane.Hill@dsto.defence.gov.au
// Reason: Remove dependancy on MFC. Code should compile on any
// platform.
//////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/*
!! MODIFIED BY FAKETRUTH and xoft !!
@ -79,7 +79,7 @@ bool cIniFile::ReadFile(const AString & a_FileName, bool a_AllowExampleRedirect)
}
}
bool IsFirstLine = true;
bool IsFirstLine = true;
while (getline(f, line))
{
@ -866,7 +866,7 @@ AString cIniFile::CheckCase(const AString & s) const
void cIniFile::RemoveBom(AString & a_line) const
{
// The BOM sequence for UTF-8 is 0xEF,0xBB,0xBF
// The BOM sequence for UTF-8 is 0xEF, 0xBB, 0xBF
static unsigned const char BOM[] = { 0xEF, 0xBB, 0xBF };
// The BOM sequence, if present, is always th e first three characters of the input.

View File

@ -9,7 +9,7 @@
// Email: Shane.Hill@dsto.defence.gov.au
// Reason: Remove dependancy on MFC. Code should compile on any
// platform. Tested on Windows/Linux/Irix
//////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/*
!! MODIFIED BY FAKETRUTH and madmaxoft!!

View File

@ -604,6 +604,28 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
m_Writer.AddByte("IsConverting", (((const cZombie *)a_Monster)->IsConverting() ? 1 : 0));
break;
}
case mtInvalidType:
case mtBlaze:
case mtCaveSpider:
case mtChicken:
case mtCow:
case mtEnderDragon:
case mtGhast:
case mtGiant:
case mtIronGolem:
case mtMooshroom:
case mtOcelot:
case mtPig:
case mtSilverfish:
case mtSnowGolem:
case mtSpider:
case mtSquid:
case mtWitch:
case mtZombiePigman:
{
// Other mobs have no special tags.
break;
}
}
m_Writer.EndCompound();
}

View File

@ -696,11 +696,28 @@ cBlockEntity * cWSSAnvil::LoadBlockEntityFromNBT(const cParsedNBT & a_NBT, int a
bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_TagIdx)
{
int Type = a_NBT.FindChildByName(a_TagIdx, "id");
if ((Type < 0) || (a_NBT.GetType(Type) != TAG_Short))
if (Type <= 0)
{
return false;
}
a_Item.m_ItemType = a_NBT.GetShort(Type);
if (a_NBT.GetType(Type) == TAG_String)
{
if (!StringToItem(a_NBT.GetString(Type), a_Item))
{
// Can't resolve item type
return false;
}
}
else if (a_NBT.GetType(Type) == TAG_Short)
{
a_Item.m_ItemType = a_NBT.GetShort(Type);
}
else
{
return false;
}
if (a_Item.m_ItemType < 0)
{
a_Item.Empty();