This tutorial is set by the author's setting without permission.
If you have read the previous chapter and complete the development of the development environment, then now we will officially enter the module development process of Craftsmanship 2!
Writing
Reminder before watching, if you want to know this part, it is recommended to learn Java without required too much. You can finish the data type, conditional sentences, circulation, and operators.
Configure your module
Before writing the entry, you need to configure your module, such as named it
The SRC/main/Java directory developed in the MC module development project structure stored the Java source code of MOD, SRC/main/Resources directory stored MOD resource files
Now let's solve the Java code
Open your src -Main — Java folder, you may see such a series of file com.example.examplemod. This is the package name of your module. Obviously, we are unwilling to use the package of its example.name.
So now, you need to choose a suitable package name for your module first, but before taking the package name, you need to know these
The package name usually has the following regulations:
● The package name should not be used by numbers and lowercase letters. The first character of each section separated by the decimal point should not be numbers.
● If there are multiple words in each section of the package name, then it should be simply spliced together without using characters such as the lower drawing line.
Under the actual situation, the author name/ID+project name is generally named, such as my bag name
And its modification method is also very simple, right -click the target, choose to renovate the naming
There is still a COM here just because I am lazy and neglected ()
After the name is named, open the ExampleMod file (I have changed here, but the problem is not big, the structure is the same)
@mod (modid = parasiticticalNOLOGYMIXILIATION.MOD, name = parasiticticalmixinaffiliation.name, VersS Ion = ParasiticticalNOLOGYMIXINAFILION.Version)// ParasiticticalNOLOGYMIXINAFFILIATION is your class name of this class. This class is also the main class of your MOD.
Public Class ParassiticalNOLOGYMIXINAFILION
// After class, ParasitalNOLOGYMIXINAFFILIATION is your class name. Since this class is modified by Public, this class name should be the same as the file name
{{
Public Static Final String Modid = "Parasitic_technology_mixin_Affiliation"; // Your modid, affecting the registration name
Public Static Final String name = "Parasitic Technology Mixin Affiliation"; // Your MOD name, affecting the names of your MOD displayed
Public Static Final String Version = "0.1"; // Your MOD version, take it casually, what 0.1 version 0.2
// The following content is omitted for the time being
Private Static Logger Logger;
@EventHandler Public Void Prebinit (FMLPreinitialization Event)
{{
Logger = Event.getmodLog ();
}
@Eventhandler
Public Void Init
{{
// aME Example Code
Logger.info ("Dirt Block >> {}", blocks.dirt.getregition ());
}
}
Then it is the information file of the MOD
Open the mcmod.info file
[{{
// Note, do not modify the part of not playing //
"Modid": "Parasitic_technology_mixin_affiLiation", // Fill the modid you previously written
"Name": "Parasitic Technology Mixin Affiliation", //
"Description": "Mixin module of parasitic technology integrated package", // Description of module content
"Version": "$ {version}",
"Mcversion": "$ {mcversion}",
"Url": "",
"Updateurl": "",
"Authorlist": ["cszxymzx"], // MOD author list
"Credits": "Thank you those who have helped me on my learning path", // can write some words of XXX
"Logofile": "",,,,
"ScreenShots": [],,,
"Dependencies": [] []
}
]
Finally, configure the configuration information when configured to build mods, I know that these things are troublesome, but you still have to do
Open the build.gradle file, you need to modify this code
Version = '0.1' // The first line of code sets the MOD version number, please keep it consistent with the data in the @mod annotation. Liaation '// The second line of code is set to set the name of the MOD, please keep it consistent with the package name you setArchivesBasename = 'Parasitic_technology_mixin_Affiliation' // The third line code is set to set the MOD in front of the file name. In most cases, its name should be consistent with the name of the MOD.
good!Finally, I modify the described information related to the MOD, and work hard, then enter the formal development next!
Entry
The first thing you need to understand is that if you want to write a entry, you need to go through three steps, which are the implementation entries, registered entries, and key value Sinicization
Here I take you as an example to take you the process as an example
Entry
@mod.eventbussubscriber ()//Mod.eventbussubscriber is an annotation to record a class in the Minecraft FORGE MOD, so that it can register to the FORGE event bus
// When a class uses@mod.eventbussubscriber, it indicates that this class is an event subscriber that can monitor and handle specific types of events.
// In the claiming class, you can add methods to handle events, and use event annotations @SubscripeEvent to mark these methods.
// That is to say if you want to register an event with @SubscripeEvent, then you must add this annotation to the class head. Of course, don't add it if there is no subscription event
Public Class TrartCorpseMountain Extends Abstracttrait
// First create a new class and give it a suitable name. Since we write the craftsmanship entries, here I suggest the way of the TRAIT+entry name (for the sake of easy reading, it is recommended that the first letter of the word)
// Then use Extends to inherit the ABSTRACTRAIT class. This is an abstract class of the craftsmanship entry. Of course, you don’t need to abstract what is for the time being. You just need to know that the entry must inherit it.
{{
Public traitcorpsemountain ()
// Each class must have its structure method.
{{
Super ("Trait_corpse_mountain", 0xff0000);
// The first parameter is the registered name, that is, "Trait_corpse_mountain" (note that the registration name cannot be in capital), and the registered registered name can be added to the material you want through the registered file of the magic artisan soul.
// Of course please see the relevant tutorial
// The second parameter is the color of the characteristic, that is, red (0xff0000)
}
// Realize the core of killing growth
@SubscripeEvent // Register an event for triggering
Public Static Void Ontargetkilled
// The role of the above annotation is to register a method as an event monitor, that is, Ontargetkilled, and the listener requires a parameter (event)
// and the LivingDeathevent event is triggered when a biological entity dies, the information of the incident will be passed to the Event parameter that the method is passed on
// Therefore, in OntargetKilled (LivingDeathevent Event) method, you can obtain information about death entities through the event parameters, so as to perform corresponding processing
{{
If (event.getsource (). GettrueSource () Instanceof EntityPlayer && Event.
// Instanceof is a Java keyword to check whether an object is an example of a specific class. The grammar is Object Instanceof Class
// Object is the object to be checked. Class is a class to check.If Object is an instance of class, the result of the expression is true, otherwise it is false
// && is a logic and operational symbol, which is used to determine whether both Boolean values are True
// If the two operations are true, the expression returns true, otherwise False will return
// So the judgment of if is
// Whether the source of the real damage is the player (left)
// Is the body of this death a creature (right)
// It means that if the source of the damage is the player and the death of death is the code that performs the following code
{{
World w = event.getsource (). GettrueSource (). World;
// Get the world where the attacker is located.
//Event.getsource () Return to the source of this event, that is, the cause of damage.In this incident, the source is an object of DamageSource type.
//Event.getsource (). GettrueSource () returns the entity that causes damage, that is, an attacker.In this incident, the attacker is an entity object.
//Event.getsource ().gettrueSource ().World returns the world where the attacker is located, that is, the world's world object.
// Therefore, the role of this line of code is to obtain the world where the attacker is located.
ItemStack Tool = (entityplayer) event.getsource (). GettrueSource ()).
// means to get the main items in the hands of the player in the LivingDeathevent event and save it into the TOOL variable
//Event.getsource ()
// Return to event source objects, the type is DamageSource, which means the source of damage, such as physical, environment, magic, and so on.
//Event.getsource (). GettrueSource ()
// Return to the actual source of damage. The type is entity, which means the entity that causes damage, such as players, biology, traps, and so on.If the source of damage is not a physical entity, return NULL.// (entityplayer) Event.getsource (). GettrueSource ().
// Convert the actual source of damage to the player object, the type is EntityPlayer.If the actual source of damage is not a player, the ClassCastexception is thrown.
// ((entityplayer) event.getsource (). GettrueSource ()).
// Get the main item in the player's hand, the type is Itemstack, that is, the items corresponding to a item bar in the item bar.If there are no items in your hand, return an empty Itemstack object.
// Get the main items in the hands of the physical player in the event and save it in the Itemstack type variable TOOL
Nbttagcompound tag = tagutil.GetextRatag (Tool);
// Get the NBTTAGCOMPOUND object added with the additional tags in the TOOL item bar and record it as a TAG
Cxmxnbtdata data = cxmxnbtdata.read (tag);
// Read the data of the CXMXNBTDATA class in the tool and store it in the new CXMXNBTDATA DATA object
// Notice!Notice!Notice!The CXMXNBTDATA here is a tool class I have customized. What are the specific data?
If (! W.isremote && Tinkerutil.hastrait (tagutil.Gettgsafe (Tool), "Trait_corpse_mountain") && data.bonus <50)
// Determine whether the current code running environment is the client:! W.isremote
// Check whether the handheld item (that is, the main item) contains the trait (tract) tinkerutil.hastrait (tagutil.gettgsafe (Tool), Identifier)
// && is a logic and operational symbol, which is used to determine whether both Boolean values are True
// If the two operations are true, the expression returns true, otherwise False will return
//Tinkerutil.haastrait () method is used to check whether the specified item contains the specified characteristics
// Tagutil.gettgsafe () method is used to obtain the NBT tag data of items to determine whether the item contains the specified characteristics.
// This means that if the current code running environment is not the client, and the items held when killing the creature contain the craftsmanship entry named Trait_corpse_mountain
{{
Float health = (entityliving) event.getitity ()). Getmaxhealth (); //event.getitity () obtained the entity that was injured when the event triggered.
// Compulsory type converted to EntityLiving
// Since Entityliving inherits the EntityLivingbase class
// Use the getMaxhealth () method to get the maximum health value
// Eventually store the value in the variable of Float type health
// When getting an event trigger, the entity's maximum health and stored in the Health type of Float type
Data.killcount+= 1;
// Kill count plus one
Data.health = health;
// Record the maximum health of the killing target
Float Divisor = 25000F;
// Define a Float type variable divisor and assign it to 25000F for subsequent numerical calculations.
Float bonus = math.round (random.nextfloat ()*health*100)/divisor;
// Randomly generate a floating point number with a range of 0 to 1. Multiplying the maximum health of the entity and multiplying at 100 to get a value.
// Remove the value obtained in the previous step with Divisor, get the value of Bonus, and enter the nearest integer.
// Define a floating -point variable BONUS, and through a series
Data.bonus+= bonus;
// Growth rewards increase
Data.bonus = (float) math.round (data.bonus*100F)/100F; //math.round (da.bonus*100F)/100F means to multiply data.bonus as closestInteger
// Then remove two decimals with 100.Finally, the calculated result is assigned to the data.bonus variable
// The role is to keep the value of the data.bonus variable after calculating the two decimals
Data.write (tag);
// Write data in the data object into the Tag object
Tagutil.SetextRatag (Tool, TAG);
// Tagutil is a tool class that provides a set of convenient static methods to operate NBT tag data
// SetextRatag method is used to set up an additional NBT tag data in the item bar
// The first parameter of this method is an ITEMSTACK object, which means that items that need to be set to set label data, // The second parameter is an NBTTAGCOMPOUND object, indicating that the NBT tag data needs to be written.
// That is, the increased damage tag object after calculation is written as an additional data into the Tool item bar for saving
// Mc want to save data, you need to use NBT for saving
}
}
}
// Use the above results to change the damage
@OunRide // cover method
Public Float Damage
(Itemstack Tool, EntitylivingBase Player, EntityLivingBase Target,
Float Damage, Float NewDamage, Boolean Iscripical)
// The name of this method is damage, returning a value of a float type.There are 6 parameters in this method:
// Tool: a parameter of Itemstack, indicating the tools that are using.
// Player: A parameter of EntityLivingbase, indicating the player using tools.
// Target: A parameter of an EntityLivingbase type, indicating the entity that was attacked.
// Damage: A Float type parameter, indicating the original damage value.
// NewDamage: A Float type parameter, indicating the damage value after calculation.
// iScripical: A Boolean type parameter, indicating whether the attack is a crit.// The role of this method is calculated and returned to the modified damage value based on the different tools used by the player and the attack target.
// In addition, there are many methods to modify the effects of different behaviors of craftsmanship tools in inheriting the abstract class of ABSTRACTTRAIT inherited by this class. If you want to view these methods, you can use CTRL to click DAMAGE's method name jump to view
{{
Nbttagcompound tag = tagutil.GetextRatag (Tool);
// Get the NBTTAGCOMPOUND object added with the additional tags in the TOOL item bar and record it as a TAG
Cxmxnbtdata data = cxmxnbtdata.read (tag);
// Read the data of the CXMXNBTDATA class in the tool and store it in the new CXMXNBTDATA DATA object
Float bonus = data.bonus;
// Get growth reward
Return newDamage+Bonus;
// Add the source damage and return this new damage, that is, modify the damage
}
// Display information
@Sideonly (size.client)
// Only run at the client
//Notice!Notice!This is important!Some things that only appear on the client must use this @sideonly (SIDE.Client) annotation, because the server cannot call the way you do not have, if you do not want the game to collapse ()
@SubscripeEvent
Public Static Void OnitemTooltip (ItemTooltipevent E)
// Subscribe to the itemToolTipevent event, which will be triggered when the player views the prompt information of the item
// E is an event object that is triggered, that is, the item that is viewed {
Itemstack tool = e.getItemstack ();
// Get the item stack currently being displayed by Tooltip, and the variables that are assigned to the Itemstack class TOOL
If (TINKERUTIL.haastrait (Tagutil.gettgsafe (Tool), "Trait_corpse_mountain"))))
// Check whether the TOOL has a designated craftsmanship entry
{{
Nbttagcompound tag = tagutil.GetextRatag (Tool);
// Get the NBTTAGCOMPOUND object added with the additional tags in the TOOL item bar and record it as a TAG
Cxmxnbtdata data = cxmxnbtdata.read (tag);
// Read the data of the CXMXNBTDATA class in the tool and store it in the new CXMXNBTDATA DATA object
If (data.killcount! = 0)
// Judging whether the data of Killcount is 0, if it is zero, skip
{{
E.gettooltip (). Add (textformatting.white+"killed:"+textFormting.white+data.killcount); //e.gettooltip () Return a list of current prompt information containing the current prompt information of the item
// add () method can add a string to the end of the list
//TextFormatting.white is an enumeration value that indicates that the adding string color is white
// "Killed:" It is a string to be added.
//Data.killcount is an integer value, indicating that the number of entity that has been killed will be converted into a string and adds it to the prompt information list
// Add a text string to the prompt information list of the item
E.gettooltip (). Add (textformatting.white+"bonus:"+textFormting.white+data.bonus);
// Ibid
}
}
}
}
The above is the realization of the craftsmanship entry
Attached CXMXNBTDATA code
Public Class CXMXNBTDATA EXTENDS NBTTAGCOMPOUND {Public int killcount; public float health;
Public int Brokenblocks;
Public float bonus;
Public int curse;
Public string name;
Public float Radius;
Public int Hunger;
Public float dfloat;
Pubble int dint;
Public int Times;
Public boolean action;
Pubble int Soul;
Public float damage;
Public boolean cxmxswitch;
Public Static CXMXNBTDATA Read (NBTTAGCOMPOUND TAG) {
Cxmxnbtdata data = new cxmxnbtdata ();
Data.killcount = tag.getinteger ("Killcount");
Data.BrokenBlocks = tag.getinteger ("" BrokenBlocks ");
Data.health = tag.getfloat ("health");
Data.bonus = tag.getfloat ("bonus");
Data.curse = tag.getinteger ("curse");
Data.Name = tag.getstring ("name");
Data.radius = tag.getfloat ("radius"); data.dfloat = tag.getfloat ("dFloat");
Data.Hunmer = tag.getinteger ("hun");
Data.dint = tag.getinteger ("dint");
Data.times = tag.getinteger ("times");
Data.active = tag.getBoolean ("active");
Data.soul = tag.getinteger ("soul");
Data.damage = tag.getfloat ("damage");
Data.cxmxswitch = tag.getBoolean ("cxmxswitch");
Return data;
}
Public void write (nbttgcompound tag) {
Tag.setinteger ("killcount", killcount);
Tag.Setinteger ("Brokenblocks", Brokenblocks); Brokenblocks;
Tag.setfloat ("health", health);
Tag.setfloat ("bonus", bonus;
Tag.setinteger ("Curse", CURSE);
Tag.setString ("name", name);
Tag.setfloat ("radius", radius); tag.setinteger ("dint", dint);
Tag.setInteger ("HUNGER", Hunger);
Tag.setinteger ("Times", Times;
Tag.setfloat ("dfloat", dfloat);
Tag.setBoolean ("active", active);
Tag.setinteger ("soul", soul);
Tag.setfloat ("damage", damage);
Tag.setBoolean ("CXMXSWITCH", CXMXSWITCH); CXMXSWITCH);
}
}
Register
Next, you need to register the entry for the game. If you do not register, it does not know that you add the entry to it, and you cannot use it
Now go back to the MOD main class you wrote before
@mod (modid = parasiticticalNOLOGYMIXILIATION.MOD, name = parasiticticalmixinaffiliation.name, VersS Ion = ParasiticticalNOLOGYMIXINAFILION.Version)Public Class ParassiticalNOLOGYMIXINAFILION
{{
Public Static Final String Modid = "Parasitic_technology_mixin_Affiliation";
Public Static Final String name = "Parasitic Technology Mixin Affiliation";
Public Static Final String Version = "0.1";
Private Static Logger Logger;
@EventHandler Public Void Prebinit (FMLPreinitialization Event)
{{
TinkerRegistry.addtrait (New Traitcorpsemountain ());
// Here
// Trartcorpsemountain () can be replaced with other construction methods you want to register. If there are parameters in the construction method, then you need to fill in the parameters
Logger = Event.getmodLog ();
}
@Eventhandler
Public Void Init
{{
// aME Example Code
Logger.info ("Dirt Block >> {}", blocks.dirt.getregition ());
}
}
Key Chinese
If you are not Chinese, then the entry is displayed in the book of craftsmanship, which is a strange symbol, which is naturally not what we want, so enter the Chineseization
Create a new Assets. +Modid package under the Resources folder, such as this
Then create a new package named LANG under this package. This package stores MC language files. We can create a new Lang file to store language. It is named ZH_CN that it is a Chinese -based file that Chinese is Chinese.
Then open this file to write the text
The Chinese format format of the craftsmanship is
Modifier. + Eclause registration name + .Name = word entry name
Modifier. + Eclause registration name + .desc = Cord Description
Among them, §O represents the text followed by it as the iTalic style
§R is used to reset the text style, and reset the previously set style (such as color, coarse body, oblique body, etc.) to the default style. You can use "§R" in the text to ensure that the later text is not subject to the previous styleInfluence
It is a change line, which represents the output of the change of the line
If you want to know the knowledge of more format, you can look at this format code -Minecraft Wiki, the most detailed World Encyclopedia
modifier.trait_corpse_mountain.name = corpse mountainmodifier.trait_corpse_mountain.desc = §O -the more corpses, the larger its body shape.And it will never be satisfied; §R
The weapon will gradually increase the damage with the blood on your blade, and increase the maximum increase of 50
The specific effect is as follows
If you do not add words to the materials, you can see Daxuan's tutorial 1.12.2 Modeling of Modern Craftsmanship 2 -Tweakers Constructure -MC Encyclopedia | The largest MineCraft Chinese Mod Encyclopedia (MCMOD.cn)
The position of its configuration file in the IDEA development environment is here to use Mixin
(Note: Non -necessary, don't look at it, just understand it)
The first is that Mixin's purpose of artisan soul weapons will cause special damage particles according to the damage after attack, which has no effect on the general situation, but in the integrated package with a very high average blood volume of monstersThe effect of tens of thousands of damage particles is very burst and can make the computer card for a while, so we must close it.But I did n’t expect that ordinary red heart is the original version of the damage particles. Which kind of kind big brother can help me point me to point out which method of the code that hurts the red heart.
Finding the root cause of the code is not a simple job, especially to find the entry point, it has no fixed formula, so I can only start with you when you initially find the entry point
In order to eliminate the damage particles of the weapon attack, we can try to turn the source code of the weapon. After careful reading, we are lucky to find it., That's really a ghost
We can see that there is a spawnattackparticle () method. The translation is to produce attack particles. Based on the previous article, we can see that there is a conditional statement here to check whether the attack is hit and the attacker is ready to perform special attacks.If the conditions are met, it will make it Tinkertools.proxy call the Spawnattackparticle method to generate a special attack particle effect.
Do we just mixin here?
Obviously not, because the tools have the method of producing particles by themselves. If Mixin then means that each tool must be mixin again, this is a very stupid and dangerous trouble.Unable to be executed.
So if we hold down Ctrl and click this spawnattackparticle () method, IDEA will automatically jump to the source of this method
There are many methods of the same name look terrible?
No rush, after careful observation, you find that the most important thing is this paragraph
The section of the horizontal line uses a network channel to distribute a communication package to the client to notify the client for rendering particles. We only need to stop it from communicating, but let's not worry.File code of similar content will be stored together.
Sure enough, we found the ClientProxy client code file under the folder where the Commonproxy was located
There is this method in it
We also mixin, so the specific code is as follows
@mixin (value = clientproxy.class, remap = false// Instructions Mixin will be applied to the ClientProxy class, and the REMAP parameter is set to FALSE, indicating that the category and method names will not be resumed in the confusing code
Public Abstract ClientProxymixin EXTENDS CommonProxy
// This is an abstract class that expands (that is, add Extends keywords) COMMONPROXY class, and is used to achieve Mixin
{{
@Inject (Method = "Spawnparticle", at = @AT ("Head"), Cancellable = TRUE)
// This is an injection annotation.It indicates that Mixin will be injected into the head of the Spawnparticle method of the ClientProxy class (Head)
Public void __test (callbackinfo Ci)
// This is the method of injection, named __teest.This method accepts a CallBackinfo object as a parameter to notify the callback after the injection is successfully injected.
{{
Ci.cancel (); // ci.cancel () is called, it will cancel the normal execution of the method}
}
@mixin (value = commonproxy.class, remap = false)// This is the beginning of Mixin annotation.It indicates that Mixin will be applied to the Commonproxy class, and the Remap parameter is set to false, indicating that the codes and the method name will not be reshaped in the confusing code.
Public Abstract CLASS COMMONPROXYMIXIN // This is an abstract class (that is, adding ABSTRACT keywords) to achieve Mixin
{{
@Inject (
method = "spawnParticle(Lslimeknights/tconstruct/library/client/particle/Particles;Lnet/minecraft/world/World;DDDDDD[I)V",
At = @AT ("Head"),
Cancellable = TRUE
Cure
// This is an injection annotation.It indicates that Mixin will be injected into the head (head) of the Spawnparticle method that is injected into the Commonproxy class
Public void __teest (callbackinfo CI) // This is the method of injection, named __teest.This method accepts a callbackInfo object as a parameter to notify the callback after the injection is successfully injected
{{
Ci.cancel (); // ci.cancel () is called, and it will cancel the normal execution of the method.
}
}
Then fill in the category names of these two Mixin classes into the JSON created by the MIXIN section in the previous tutorial
After completing the module
You need to do two things
First, use IDEA to run the module on site to check whether it is available
Press the Ctrl+Shift+A combination key, open the option box for executing related tasks, enter Execute in the search box, select the grade task to enter the Runclient to run the game
Then check the module content by yourself
Second, export module file
Open the terminal below the ID, input ./gradlew.bat build
If you want to clean up the old module file, enter ./gradlew.bat Clean
Then you can find your own module file in the libs under the built folder
Finally, if you want to learn more module development knowledge, you can see these references
Preface: "Pagan and hermit" Harbinger (COVERTDRAGON.TEAM)
(6 news) My world_Jay_fearless's blog-CSDN blog